Ardour  9.0-pre0-582-g084a23a80d
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  bool operator== (Range const & other) const {
171  return other._start == _start && other._end == _end;
172  }
173 
175  _start = timepos_t((samplepos_t)_start.samples ());
176  _end = timepos_t((samplepos_t)_end.samples ());
177  }
178 
183  timepos_t squish (timepos_t const & t) const;
184 
185  /* end is exclusive */
186  OverlapType coverage (timepos_t const & s, timepos_t const & e) const {
187  return Temporal::coverage_exclusive_ends (_start, _end, s, e);
188  }
189 
190  void dump (std::ostream& ostr) const {
191  ostr << "Range @ " << this << ' ' << _start << " .. " << _end;
192  }
193 
194  private:
197 };
198 
199 typedef Range TimeRange;
200 
201 }
202 
203 namespace std {
204 LIBTEMPORAL_API std::ostream& operator<< (std::ostream & o, Temporal::Range const &);
205 }
206 
207 namespace Temporal {
208 
209 
211 public:
212  RangeList () : _dirty (false) {}
213 
214  typedef std::list<Range> List;
215 
216  List const & get () {
217  coalesce ();
218  return _list;
219  }
220 
221  void add (Range const & range) {
222  _dirty = true;
223  _list.push_back (range);
224  }
225 
226  bool empty () const {
227  return _list.empty ();
228  }
229 
230  void coalesce () {
231  if (!_dirty) {
232  return;
233  }
234 
235  restart:
236  for (typename List::iterator i = _list.begin(); i != _list.end(); ++i) {
237  for (typename List::iterator j = _list.begin(); j != _list.end(); ++j) {
238 
239  if (i == j) {
240  continue;
241  }
242 
243  if (coverage_exclusive_ends (i->start(), i->end(), j->start(), j->end()) != OverlapNone) {
244  i->set_start (std::min (i->start(), j->start()));
245  i->set_end (std::max (i->end(), j->end()));
246  _list.erase (j);
247  goto restart;
248  }
249  }
250  }
251 
252  _dirty = false;
253  }
254 
255  void dump (std::ostream& ostr) const {
256  ostr << "RangeList @ " << this << std::endl;
257  for (auto const & r : _list) {
258  ostr << r << std::endl;
259  }
260  }
261 
262 private:
263 
265  bool _dirty;
266 };
267 
270  RangeMove (timepos_t f, timecnt_t l, timepos_t t) : from (f), length (l), to (t) {}
274 };
275 
276 }
277 
278 namespace std {
279 LIBTEMPORAL_API std::ostream& operator<< (std::ostream & o, Temporal::RangeList const &);
280 }
281 
282 
283 #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