Ardour  9.2-266-g5d535d4cb7
temporal/temporal/range.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 David Robillard <http://drobilla.net>
3  * Copyright (C) 2000-2017 Paul Davis
4  *
5  * Evoral is free software; you can redistribute it and/or modify it under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2 of the License, or (at your option) any later
8  * version.
9  *
10  * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #ifndef __libtemporal_range_hpp__
20 #define __libtemporal_range_hpp__
21 
22 #include <list>
23 #include <assert.h>
24 #include <iostream>
25 
26 #include "temporal/visibility.h"
27 #include "temporal/timeline.h"
28 #include "temporal/types.h"
29 
30 namespace Temporal {
31 
33 template<typename T>
34 /*LIBTEMPORAL_API*/ OverlapType coverage_inclusive_ends (T sa, T ea, T sb, T eb) {
35  /* OverlapType returned reflects how the second (B)
36  * range overlaps the first (A).
37  *
38  * The diagram shows the OverlapType of each possible relative
39  * placement of A and B.
40  *
41  * Notes:
42  * Internal: the start and end points cannot coincide
43  * External: the start and end points can coincide
44  * Start: end points can coincide
45  * End: start points can coincide
46  *
47  * Internal disallows start and end point equality, and thus implies
48  * that there are two disjoint portions of A which do not overlap B.
49  *
50  * A: |---|
51  * B starts before A
52  * B: |-| None
53  * B: |--| Start
54  * B: |----| Start
55  * B: |------| External
56  * B: |--------| External
57  * B starts equal to A
58  * B: |-| Start
59  * B: |---| External
60  * B: |----| External
61  * B starts inside A
62  * B: |-| Internal
63  * B: |--| End
64  * B: |---| End
65  * B starts at end of A
66  * B: |--| End
67  * B starts after A
68  * B: |-| None
69  * A: |---|
70  */
71 
72  if (sa > ea) {
73  // seems we are sometimes called with negative length ranges
74  return OverlapNone;
75  }
76 
77  if (sb > eb) {
78  // seems we are sometimes called with negative length ranges
79  return OverlapNone;
80  }
81 
82  if (sb < sa) { // B starts before A
83  if (eb < sa) {
84  return OverlapNone;
85  } else if (eb == sa) {
86  return OverlapStart;
87  } else { // eb > sa
88  if (eb < ea) {
89  return OverlapStart;
90  } else if (eb == ea) {
91  return OverlapExternal;
92  } else {
93  return OverlapExternal;
94  }
95  }
96  } else if (sb == sa) { // B starts equal to A
97  if (eb < ea) {
98  return OverlapStart;
99  } else if (eb == ea) {
100  return OverlapExternal;
101  } else { // eb > ea
102  return OverlapExternal;
103  }
104  } else { // sb > sa
105  if (eb < ea) {
106  return OverlapInternal;
107  } else if (eb == ea) {
108  return OverlapEnd;
109  } else { // eb > ea
110  if (sb < ea) { // B starts inside A
111  return OverlapEnd;
112  } else if (sb == ea) { // B starts at end of A
113  return OverlapEnd;
114  } else { // sb > ea, B starts after A
115  return OverlapNone;
116  }
117  }
118  }
119 
120  std::cerr << "unknown overlap type!" << sa << ", " << ea << "; " << sb << ", " << eb << std::endl;
121  assert(!"unknown overlap type!");
122  return OverlapNone;
123 }
124 
126 template<typename T>
127 /*LIBTEMPORAL_API*/ OverlapType coverage_exclusive_ends (T sa, T eaE, T sb, T ebE)
128 {
129  /* convert end positions to inclusive */
130  return coverage_inclusive_ends (sa, eaE.decrement(), sb, ebE.decrement());
131 }
132 
133 template<> LIBTEMPORAL_TEMPLATE_API OverlapType coverage_exclusive_ends<int64_t> (int64_t sa, int64_t eaE, int64_t sb, int64_t ebE);
134 
135 
136 class RangeList;
137 
139  public:
140  /* exclusive end semantics
141  *
142  * |--------------------------------------|
143  * ^ ^
144  * start end
145  * 0 10 => length = 10, last position inside range = 9
146  * 1 11 => length = 10, last position inside range = 10
147  * 0 1 => length = 1, last position inside range = 0
148  * 0 2 => length = 2, last position inside range = 1
149  * 32 48 => length = 16, last position inside range = 47
150  */
151 
152  Range (timepos_t const & s, timepos_t const & e) : _start (s), _end (e) {}
153  Range (samplepos_t const s, samplepos_t const e) : _start (s), _end (e) {}
154  bool empty() const { return _start == _end; }
155 
156  /* length semantics: start + length = end thus end - start aka * start.distance (end)
157  * extent semantics: 1 + (end - start)
158  */
159 
160  timecnt_t length() const { return _start.distance (_end); }
161 
163 
164  void set_start (timepos_t s) { _start = s; }
165  void set_end (timepos_t e) { _end = e; }
166 
167  timepos_t start() const { return _start; }
168  timepos_t end() const { return _end; }
169 
170  timepos_t& start() { return _start; }
171  timepos_t& end() { return _end; }
172 
173  bool operator== (Range const & other) const {
174  return other._start == _start && other._end == _end;
175  }
176 
178  _start = timepos_t((samplepos_t)_start.samples ());
179  _end = timepos_t((samplepos_t)_end.samples ());
180  }
181 
186  timepos_t squish (timepos_t const & t) const;
187 
188  /* end is exclusive */
189  OverlapType coverage (timepos_t const & s, timepos_t const & e) const {
190  return Temporal::coverage_exclusive_ends (_start, _end, s, e);
191  }
192 
193  void dump (std::ostream& ostr) const {
194  ostr << "Range @ " << this << ' ' << _start << " .. " << _end;
195  }
196 
197  private:
200 };
201 
202 typedef Range TimeRange;
203 
204 }
205 
206 namespace std {
207 LIBTEMPORAL_API std::ostream& operator<< (std::ostream & o, Temporal::Range const &);
208 }
209 
210 namespace Temporal {
211 
212 
214 public:
215  RangeList () : _dirty (false) {}
216 
217  typedef std::list<Range> List;
218 
219  List const & get () {
220  coalesce ();
221  return _list;
222  }
223 
224  void add (Range const & range) {
225  _dirty = true;
226  _list.push_back (range);
227  }
228 
229  bool empty () const {
230  return _list.empty ();
231  }
232 
233  void coalesce () {
234  if (!_dirty) {
235  return;
236  }
237 
238  restart:
239  for (typename List::iterator i = _list.begin(); i != _list.end(); ++i) {
240  for (typename List::iterator j = _list.begin(); j != _list.end(); ++j) {
241 
242  if (i == j) {
243  continue;
244  }
245 
246  if (coverage_exclusive_ends (i->start(), i->end(), j->start(), j->end()) != OverlapNone) {
247  i->set_start (std::min (i->start(), j->start()));
248  i->set_end (std::max (i->end(), j->end()));
249  _list.erase (j);
250  goto restart;
251  }
252  }
253  }
254 
255  _dirty = false;
256  }
257 
258  void dump (std::ostream& ostr) const {
259  ostr << "RangeList @ " << this << std::endl;
260  for (auto const & r : _list) {
261  ostr << r << std::endl;
262  }
263  }
264 
265 private:
266 
268  bool _dirty;
269 };
270 
273  RangeMove (timepos_t f, timecnt_t l, timepos_t t) : from (f), length (l), to (t) {}
277 };
278 
279 }
280 
281 namespace std {
282 LIBTEMPORAL_API std::ostream& operator<< (std::ostream & o, Temporal::RangeList const &);
283 }
284 
285 
286 #endif /* __libtemporal_range_hpp__ */
void dump(std::ostream &ostr) const
void add(Range const &range)
RangeList subtract(RangeList &) const
Range(timepos_t const &s, timepos_t const &e)
Range(samplepos_t const s, samplepos_t const e)
timepos_t squish(timepos_t const &t) const
void set_end(timepos_t e)
timepos_t _end
end of the range (exclusive, see above)
timepos_t end() const
timepos_t _start
start of the range
void set_start(timepos_t s)
OverlapType coverage(timepos_t const &s, timepos_t const &e) const
timepos_t start() const
void dump(std::ostream &ostr) const
timecnt_t length() const
int62_t const & distance() const
Definition: timeline.h:340
PBD::PropertyDescriptor< timecnt_t > length
Temporal::timepos_t timepos_t
OverlapType coverage_exclusive_ends(T sa, T eaE, T sb, T ebE)
OverlapType coverage_inclusive_ends(T sa, T ea, T sb, T eb)
LIBTEMPORAL_TEMPLATE_API OverlapType coverage_exclusive_ends< int64_t >(int64_t sa, int64_t eaE, int64_t sb, int64_t ebE)
bool operator==(const ProcessorSelection &a, const ProcessorSelection &b)
timecnt_t length
length of the range
RangeMove(timepos_t f, timecnt_t l, timepos_t t)
timepos_t to
new start of the range
timepos_t from
start of the range
#define LIBTEMPORAL_TEMPLATE_API
#define LIBTEMPORAL_API