/work/obj-fuzz/dist/include/Intervals.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef INTERVALS_H |
8 | | #define INTERVALS_H |
9 | | |
10 | | #include <algorithm> |
11 | | #include "mozilla/TypeTraits.h" |
12 | | #include "nsTArray.h" |
13 | | |
14 | | // Specialization for nsTArray CopyChooser. |
15 | | namespace mozilla { |
16 | | namespace media { |
17 | | template<class T> |
18 | | class IntervalSet; |
19 | | } // namespace media |
20 | | } // namespace mozilla |
21 | | |
22 | | template<class E> |
23 | | struct nsTArray_CopyChooser<mozilla::media::IntervalSet<E>> |
24 | | { |
25 | | typedef nsTArray_CopyWithConstructors<mozilla::media::IntervalSet<E>> Type; |
26 | | }; |
27 | | |
28 | | namespace mozilla { |
29 | | namespace media { |
30 | | |
31 | | /* Interval defines an interval between two points. Unlike a traditional |
32 | | interval [A,B] where A <= x <= B, the upper boundary B is exclusive: A <= x < B |
33 | | (e.g [A,B[ or [A,B) depending on where you're living) |
34 | | It provides basic interval arithmetic and fuzzy edges. |
35 | | The type T must provides a default constructor and +, -, <, <= and == |
36 | | operators. |
37 | | */ |
38 | | template<typename T> |
39 | | class Interval |
40 | | { |
41 | | public: |
42 | | typedef Interval<T> SelfType; |
43 | | |
44 | | Interval() |
45 | | : mStart(T()) |
46 | | , mEnd(T()) |
47 | | , mFuzz(T()) |
48 | 0 | { } |
49 | | |
50 | | template<typename StartArg, typename EndArg> |
51 | | Interval(StartArg&& aStart, EndArg&& aEnd) |
52 | | : mStart(std::forward<StartArg>(aStart)) |
53 | | , mEnd(std::forward<EndArg>(aEnd)) |
54 | | , mFuzz() |
55 | 0 | { |
56 | 0 | MOZ_ASSERT(aStart <= aEnd); |
57 | 0 | } Unexecuted instantiation: mozilla::media::Interval<long>::Interval<long&, long>(long&, long&&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<long, long>(long&&, long&&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<unsigned long&, unsigned long&>(unsigned long&, unsigned long&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<unsigned long, unsigned long>(unsigned long&&, unsigned long&&) Unexecuted instantiation: mozilla::media::Interval<mozilla::media::TimeUnit>::Interval<mozilla::media::TimeUnit, mozilla::media::TimeUnit&>(mozilla::media::TimeUnit&&, mozilla::media::TimeUnit&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<int, int>(int&&, int&&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<unsigned long&, unsigned long>(unsigned long&, unsigned long&&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<long&, unsigned long>(long&, unsigned long&&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<unsigned long&, long&>(unsigned long&, long&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<int, long const&>(int&&, long const&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<unsigned long&, long const&>(unsigned long&, long const&) |
58 | | |
59 | | template<typename StartArg, typename EndArg, typename FuzzArg> |
60 | | Interval(StartArg&& aStart, EndArg&& aEnd, FuzzArg&& aFuzz) |
61 | | : mStart(std::forward<StartArg>(aStart)) |
62 | | , mEnd(std::forward<EndArg>(aEnd)) |
63 | | , mFuzz(std::forward<FuzzArg>(aFuzz)) |
64 | 0 | { |
65 | 0 | MOZ_ASSERT(aStart <= aEnd); |
66 | 0 | } Unexecuted instantiation: mozilla::media::Interval<long>::Interval<long, long, long const&>(long&&, long&&, long const&) Unexecuted instantiation: mozilla::media::Interval<mozilla::media::TimeUnit>::Interval<mozilla::media::TimeUnit&, mozilla::media::TimeUnit&, mozilla::media::TimeUnit&>(mozilla::media::TimeUnit&, mozilla::media::TimeUnit&, mozilla::media::TimeUnit&) Unexecuted instantiation: mozilla::media::Interval<mozilla::media::TimeUnit>::Interval<mozilla::media::TimeUnit&, mozilla::media::TimeUnit, mozilla::media::TimeUnit const&>(mozilla::media::TimeUnit&, mozilla::media::TimeUnit&&, mozilla::media::TimeUnit const&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<long&, long&, int>(long&, long&, int&&) Unexecuted instantiation: mozilla::media::Interval<long>::Interval<long const&, long const&, int>(long const&, long const&, int&&) |
67 | | |
68 | | Interval(const SelfType& aOther) |
69 | | : mStart(aOther.mStart) |
70 | | , mEnd(aOther.mEnd) |
71 | | , mFuzz(aOther.mFuzz) |
72 | | { } |
73 | | |
74 | | Interval(SelfType&& aOther) |
75 | | : mStart(std::move(aOther.mStart)) |
76 | | , mEnd(std::move(aOther.mEnd)) |
77 | | , mFuzz(std::move(aOther.mFuzz)) |
78 | | { } |
79 | | |
80 | | SelfType& operator= (const SelfType& aOther) |
81 | 0 | { |
82 | 0 | mStart = aOther.mStart; |
83 | 0 | mEnd = aOther.mEnd; |
84 | 0 | mFuzz = aOther.mFuzz; |
85 | 0 | return *this; |
86 | 0 | } Unexecuted instantiation: mozilla::media::Interval<long>::operator=(mozilla::media::Interval<long> const&) Unexecuted instantiation: mozilla::media::Interval<mozilla::media::TimeUnit>::operator=(mozilla::media::Interval<mozilla::media::TimeUnit> const&) |
87 | | |
88 | | SelfType& operator= (SelfType&& aOther) |
89 | | { |
90 | | MOZ_ASSERT(&aOther != this, "self-moves are prohibited"); |
91 | | this->~Interval(); |
92 | | new(this) Interval(std::move(aOther)); |
93 | | return *this; |
94 | | } |
95 | | |
96 | | // Basic interval arithmetic operator definition. |
97 | | SelfType operator+ (const SelfType& aOther) const |
98 | | { |
99 | | return SelfType(mStart + aOther.mStart, |
100 | | mEnd + aOther.mEnd, |
101 | | mFuzz + aOther.mFuzz); |
102 | | } |
103 | | |
104 | | SelfType operator+ (const T& aVal) const |
105 | 0 | { |
106 | 0 | return SelfType(mStart + aVal, mEnd + aVal, mFuzz); |
107 | 0 | } |
108 | | |
109 | | // Basic interval arithmetic operator definition. |
110 | | SelfType operator- (const SelfType& aOther) const |
111 | | { |
112 | | return SelfType(mStart - aOther.mEnd, |
113 | | mEnd - aOther.mStart, |
114 | | mFuzz + aOther.mFuzz); |
115 | | } |
116 | | |
117 | | SelfType operator- (const T& aVal) const |
118 | | { |
119 | | return SelfType(mStart - aVal, mEnd - aVal, mFuzz); |
120 | | } |
121 | | |
122 | | bool operator== (const SelfType& aOther) const |
123 | 0 | { |
124 | 0 | return mStart == aOther.mStart && mEnd == aOther.mEnd; |
125 | 0 | } |
126 | | |
127 | | bool operator!= (const SelfType& aOther) const |
128 | | { |
129 | | return !(*this == aOther); |
130 | | } |
131 | | |
132 | | bool Contains(const T& aX) const |
133 | | { |
134 | | return mStart - mFuzz <= aX && aX < mEnd + mFuzz; |
135 | | } |
136 | | |
137 | | bool ContainsStrict(const T& aX) const |
138 | 0 | { |
139 | 0 | return mStart <= aX && aX < mEnd; |
140 | 0 | } |
141 | | |
142 | | bool ContainsWithStrictEnd(const T& aX) const |
143 | 0 | { |
144 | 0 | return mStart - mFuzz <= aX && aX < mEnd; |
145 | 0 | } |
146 | | |
147 | | bool Contains(const SelfType& aOther) const |
148 | 0 | { |
149 | 0 | return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz) && |
150 | 0 | (aOther.mEnd - aOther.mFuzz <= mEnd + mFuzz); |
151 | 0 | } |
152 | | |
153 | | bool ContainsStrict(const SelfType& aOther) const |
154 | 0 | { |
155 | 0 | return mStart <= aOther.mStart && aOther.mEnd <= mEnd; |
156 | 0 | } |
157 | | |
158 | | bool ContainsWithStrictEnd(const SelfType& aOther) const |
159 | 0 | { |
160 | 0 | return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz) && |
161 | 0 | aOther.mEnd <= mEnd; |
162 | 0 | } |
163 | | |
164 | | bool Intersects(const SelfType& aOther) const |
165 | 0 | { |
166 | 0 | return (mStart - mFuzz < aOther.mEnd + aOther.mFuzz) && |
167 | 0 | (aOther.mStart - aOther.mFuzz < mEnd + mFuzz); |
168 | 0 | } |
169 | | |
170 | | bool IntersectsStrict(const SelfType& aOther) const |
171 | | { |
172 | | return mStart < aOther.mEnd && aOther.mStart < mEnd; |
173 | | } |
174 | | |
175 | | // Same as Intersects, but including the boundaries. |
176 | | bool Touches(const SelfType& aOther) const |
177 | | { |
178 | | return (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz) && |
179 | | (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz); |
180 | | } |
181 | | |
182 | | // Returns true if aOther is strictly to the right of this and contiguous. |
183 | | // This operation isn't commutative. |
184 | | bool Contiguous(const SelfType& aOther) const |
185 | | { |
186 | | return mEnd <= aOther.mStart && aOther.mStart - mEnd <= mFuzz + aOther.mFuzz; |
187 | | } |
188 | | |
189 | | bool RightOf(const SelfType& aOther) const |
190 | | { |
191 | | return aOther.mEnd - aOther.mFuzz <= mStart + mFuzz; |
192 | | } |
193 | | |
194 | | bool LeftOf(const SelfType& aOther) const |
195 | | { |
196 | | return mEnd - mFuzz <= aOther.mStart + aOther.mFuzz; |
197 | | } |
198 | | |
199 | | SelfType Span(const SelfType& aOther) const |
200 | | { |
201 | | if (IsEmpty()) { |
202 | | return aOther; |
203 | | } |
204 | | SelfType result(*this); |
205 | | if (aOther.mStart < mStart) { |
206 | | result.mStart = aOther.mStart; |
207 | | } |
208 | | if (mEnd < aOther.mEnd) { |
209 | | result.mEnd = aOther.mEnd; |
210 | | } |
211 | | if (mFuzz < aOther.mFuzz) { |
212 | | result.mFuzz = aOther.mFuzz; |
213 | | } |
214 | | return result; |
215 | | } |
216 | | |
217 | | SelfType Intersection(const SelfType& aOther) const |
218 | | { |
219 | | const T& s = std::max(mStart, aOther.mStart); |
220 | | const T& e = std::min(mEnd, aOther.mEnd); |
221 | | const T& f = std::max(mFuzz, aOther.mFuzz); |
222 | | if (s < e) { |
223 | | return SelfType(s, e, f); |
224 | | } |
225 | | // Return an empty interval. |
226 | | return SelfType(); |
227 | | } |
228 | | |
229 | | T Length() const |
230 | 0 | { |
231 | 0 | return mEnd - mStart; |
232 | 0 | } |
233 | | |
234 | | bool IsEmpty() const |
235 | | { |
236 | | return mStart == mEnd; |
237 | | } |
238 | | |
239 | | void SetFuzz(const T& aFuzz) |
240 | 0 | { |
241 | 0 | mFuzz = aFuzz; |
242 | 0 | } |
243 | | |
244 | | // Returns true if the two intervals intersect with this being on the right |
245 | | // of aOther |
246 | | bool TouchesOnRight(const SelfType& aOther) const |
247 | | { |
248 | | return aOther.mStart <= mStart && |
249 | | (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz) && |
250 | | (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz); |
251 | | } |
252 | | |
253 | | T mStart; |
254 | | T mEnd; |
255 | | T mFuzz; |
256 | | |
257 | | private: |
258 | | }; |
259 | | |
260 | | // An IntervalSet in a collection of Intervals. The IntervalSet is always |
261 | | // normalized. |
262 | | template<typename T> |
263 | | class IntervalSet |
264 | | { |
265 | | public: |
266 | | typedef IntervalSet<T> SelfType; |
267 | | typedef Interval<T> ElemType; |
268 | | typedef AutoTArray<ElemType,4> ContainerType; |
269 | | typedef typename ContainerType::index_type IndexType; |
270 | | |
271 | | IntervalSet() |
272 | 0 | { |
273 | 0 | } |
274 | | virtual ~IntervalSet() |
275 | 0 | { |
276 | 0 | } |
277 | | |
278 | | IntervalSet(const SelfType& aOther) |
279 | | : mIntervals(aOther.mIntervals) |
280 | | { |
281 | | } |
282 | | |
283 | | IntervalSet(SelfType&& aOther) |
284 | 0 | { |
285 | 0 | mIntervals.AppendElements(std::move(aOther.mIntervals)); |
286 | 0 | } |
287 | | |
288 | | explicit IntervalSet(const ElemType& aOther) |
289 | | { |
290 | | if (!aOther.IsEmpty()) { |
291 | | mIntervals.AppendElement(aOther); |
292 | | } |
293 | | } |
294 | | |
295 | | explicit IntervalSet(ElemType&& aOther) |
296 | 0 | { |
297 | 0 | if (!aOther.IsEmpty()) { |
298 | 0 | mIntervals.AppendElement(std::move(aOther)); |
299 | 0 | } |
300 | 0 | } |
301 | | |
302 | | bool operator== (const SelfType& aOther) const |
303 | 0 | { |
304 | 0 | return mIntervals == aOther.mIntervals; |
305 | 0 | } |
306 | | |
307 | | bool operator!= (const SelfType& aOther) const |
308 | | { |
309 | | return mIntervals != aOther.mIntervals; |
310 | | } |
311 | | |
312 | | SelfType& operator= (const SelfType& aOther) |
313 | 0 | { |
314 | 0 | mIntervals = aOther.mIntervals; |
315 | 0 | return *this; |
316 | 0 | } |
317 | | |
318 | | SelfType& operator= (SelfType&& aOther) |
319 | 0 | { |
320 | 0 | MOZ_ASSERT(&aOther != this, "self-moves are prohibited"); |
321 | 0 | this->~IntervalSet(); |
322 | 0 | new(this) IntervalSet(std::move(aOther)); |
323 | 0 | return *this; |
324 | 0 | } |
325 | | |
326 | | SelfType& operator= (const ElemType& aInterval) |
327 | | { |
328 | | mIntervals.Clear(); |
329 | | if (!aInterval.IsEmpty()) { |
330 | | mIntervals.AppendElement(aInterval); |
331 | | } |
332 | | return *this; |
333 | | } |
334 | | |
335 | | SelfType& operator= (ElemType&& aInterval) |
336 | | { |
337 | | mIntervals.Clear(); |
338 | | if (!aInterval.IsEmpty()) { |
339 | | mIntervals.AppendElement(std::move(aInterval)); |
340 | | } |
341 | | return *this; |
342 | | } |
343 | | |
344 | | SelfType& Add(const SelfType& aIntervals) |
345 | 0 | { |
346 | 0 | mIntervals.AppendElements(aIntervals.mIntervals); |
347 | 0 | Normalize(); |
348 | 0 | return *this; |
349 | 0 | } |
350 | | |
351 | | SelfType& Add(const ElemType& aInterval) |
352 | | { |
353 | | if (aInterval.IsEmpty()) { |
354 | | return *this; |
355 | | } |
356 | | if (mIntervals.IsEmpty()) { |
357 | | mIntervals.AppendElement(aInterval); |
358 | | return *this; |
359 | | } |
360 | | ElemType& last = mIntervals.LastElement(); |
361 | | if (aInterval.TouchesOnRight(last)) { |
362 | | last = last.Span(aInterval); |
363 | | return *this; |
364 | | } |
365 | | // Most of our actual usage is adding an interval that will be outside the |
366 | | // range. We can speed up normalization here. |
367 | | if (aInterval.RightOf(last)) { |
368 | | mIntervals.AppendElement(aInterval); |
369 | | return *this; |
370 | | } |
371 | | |
372 | | ContainerType normalized; |
373 | | ElemType current(aInterval); |
374 | | IndexType i = 0; |
375 | | for (; i < mIntervals.Length(); i++) { |
376 | | ElemType& interval = mIntervals[i]; |
377 | | if (current.Touches(interval)) { |
378 | | current = current.Span(interval); |
379 | | } else if (current.LeftOf(interval)) { |
380 | | break; |
381 | | } else { |
382 | | normalized.AppendElement(std::move(interval)); |
383 | | } |
384 | | } |
385 | | normalized.AppendElement(std::move(current)); |
386 | | for (; i < mIntervals.Length(); i++) { |
387 | | normalized.AppendElement(std::move(mIntervals[i])); |
388 | | } |
389 | | mIntervals.Clear(); |
390 | | mIntervals.AppendElements(std::move(normalized)); |
391 | | |
392 | | return *this; |
393 | | } |
394 | | |
395 | | SelfType& operator+= (const SelfType& aIntervals) |
396 | 0 | { |
397 | 0 | Add(aIntervals); |
398 | 0 | return *this; |
399 | 0 | } |
400 | | |
401 | | SelfType& operator+= (const ElemType& aInterval) |
402 | | { |
403 | | Add(aInterval); |
404 | | return *this; |
405 | | } |
406 | | |
407 | | SelfType operator+ (const SelfType& aIntervals) const |
408 | | { |
409 | | SelfType intervals(*this); |
410 | | intervals.Add(aIntervals); |
411 | | return intervals; |
412 | | } |
413 | | |
414 | | SelfType operator+ (const ElemType& aInterval) const |
415 | 0 | { |
416 | 0 | SelfType intervals(*this); |
417 | 0 | intervals.Add(aInterval); |
418 | 0 | return intervals; |
419 | 0 | } |
420 | | |
421 | | friend SelfType operator+ (const ElemType& aInterval, |
422 | | const SelfType& aIntervals) |
423 | | { |
424 | | SelfType intervals; |
425 | | intervals.Add(aInterval); |
426 | | intervals.Add(aIntervals); |
427 | | return intervals; |
428 | | } |
429 | | |
430 | | // Excludes an interval from an IntervalSet. |
431 | | // This is done by inverting aInterval within the bounds of mIntervals |
432 | | // and then doing the intersection. |
433 | | SelfType& operator-= (const ElemType& aInterval) |
434 | 0 | { |
435 | 0 | if (aInterval.IsEmpty() || mIntervals.IsEmpty()) { |
436 | 0 | return *this; |
437 | 0 | } |
438 | 0 | T firstEnd = std::max(mIntervals[0].mStart, aInterval.mStart); |
439 | 0 | T secondStart = std::min(mIntervals.LastElement().mEnd, aInterval.mEnd); |
440 | 0 | ElemType startInterval(mIntervals[0].mStart, firstEnd); |
441 | 0 | ElemType endInterval(secondStart, mIntervals.LastElement().mEnd); |
442 | 0 | SelfType intervals(std::move(startInterval)); |
443 | 0 | intervals += std::move(endInterval); |
444 | 0 | return Intersection(intervals); |
445 | 0 | } |
446 | | |
447 | | SelfType& operator-= (const SelfType& aIntervals) |
448 | 0 | { |
449 | 0 | for (const auto& interval : aIntervals.mIntervals) { |
450 | 0 | *this -= interval; |
451 | 0 | } |
452 | 0 | return *this; |
453 | 0 | } |
454 | | |
455 | | SelfType operator- (const SelfType& aInterval) const |
456 | | { |
457 | | SelfType intervals(*this); |
458 | | intervals -= aInterval; |
459 | | return intervals; |
460 | | } |
461 | | |
462 | | SelfType operator- (const ElemType& aInterval) const |
463 | | { |
464 | | SelfType intervals(*this); |
465 | | intervals -= aInterval; |
466 | | return intervals; |
467 | | } |
468 | | |
469 | | // Mutate this IntervalSet to be the union of this and aOther. |
470 | | SelfType& Union(const SelfType& aOther) |
471 | | { |
472 | | Add(aOther); |
473 | | return *this; |
474 | | } |
475 | | |
476 | | SelfType& Union(const ElemType& aInterval) |
477 | | { |
478 | | Add(aInterval); |
479 | | return *this; |
480 | | } |
481 | | |
482 | | // Mutate this TimeRange to be the intersection of this and aOther. |
483 | | SelfType& Intersection(const SelfType& aOther) |
484 | | { |
485 | | ContainerType intersection; |
486 | | |
487 | | const ContainerType& other = aOther.mIntervals; |
488 | | IndexType i = 0, j = 0; |
489 | | for (; i < mIntervals.Length() && j < other.Length();) { |
490 | | if (mIntervals[i].IntersectsStrict(other[j])) { |
491 | | intersection.AppendElement(mIntervals[i].Intersection(other[j])); |
492 | | } |
493 | | if (mIntervals[i].mEnd < other[j].mEnd) { |
494 | | i++; |
495 | | } else { |
496 | | j++; |
497 | | } |
498 | | } |
499 | | mIntervals.Clear(); |
500 | | mIntervals.AppendElements(std::move(intersection)); |
501 | | return *this; |
502 | | } |
503 | | |
504 | | SelfType& Intersection(const ElemType& aInterval) |
505 | | { |
506 | | SelfType intervals(aInterval); |
507 | | return Intersection(intervals); |
508 | | } |
509 | | |
510 | | const ElemType& operator[] (IndexType aIndex) const |
511 | 0 | { |
512 | 0 | return mIntervals[aIndex]; |
513 | 0 | } Unexecuted instantiation: mozilla::media::IntervalSet<mozilla::media::TimeUnit>::operator[](unsigned long) const Unexecuted instantiation: mozilla::media::IntervalSet<long>::operator[](unsigned long) const |
514 | | |
515 | | // Returns the start boundary of the first interval. Or a default constructed |
516 | | // T if IntervalSet is empty (and aExists if provided will be set to false). |
517 | | T GetStart(bool* aExists = nullptr) const |
518 | 0 | { |
519 | 0 | bool exists = !mIntervals.IsEmpty(); |
520 | 0 |
|
521 | 0 | if (aExists) { |
522 | 0 | *aExists = exists; |
523 | 0 | } |
524 | 0 |
|
525 | 0 | if (exists) { |
526 | 0 | return mIntervals[0].mStart; |
527 | 0 | } else { |
528 | 0 | return T(); |
529 | 0 | } |
530 | 0 | } |
531 | | |
532 | | // Returns the end boundary of the last interval. Or a default constructed T |
533 | | // if IntervalSet is empty (and aExists if provided will be set to false). |
534 | | T GetEnd(bool* aExists = nullptr) const |
535 | 0 | { |
536 | 0 | bool exists = !mIntervals.IsEmpty(); |
537 | 0 | if (aExists) { |
538 | 0 | *aExists = exists; |
539 | 0 | } |
540 | 0 |
|
541 | 0 | if (exists) { |
542 | 0 | return mIntervals.LastElement().mEnd; |
543 | 0 | } else { |
544 | 0 | return T(); |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | IndexType Length() const |
549 | 0 | { |
550 | 0 | return mIntervals.Length(); |
551 | 0 | } |
552 | | |
553 | | T Start(IndexType aIndex) const |
554 | | { |
555 | | return mIntervals[aIndex].mStart; |
556 | | } |
557 | | |
558 | | T Start(IndexType aIndex, bool& aExists) const |
559 | | { |
560 | | aExists = aIndex < mIntervals.Length(); |
561 | | |
562 | | if (aExists) { |
563 | | return mIntervals[aIndex].mStart; |
564 | | } else { |
565 | | return T(); |
566 | | } |
567 | | } |
568 | | |
569 | | T End(IndexType aIndex) const |
570 | | { |
571 | | return mIntervals[aIndex].mEnd; |
572 | | } |
573 | | |
574 | | T End(IndexType aIndex, bool& aExists) const |
575 | | { |
576 | | aExists = aIndex < mIntervals.Length(); |
577 | | |
578 | | if (aExists) { |
579 | | return mIntervals[aIndex].mEnd; |
580 | | } else { |
581 | | return T(); |
582 | | } |
583 | | } |
584 | | |
585 | | bool Contains(const ElemType& aInterval) const |
586 | | { |
587 | | for (const auto& interval : mIntervals) { |
588 | | if (interval.Contains(aInterval)) { |
589 | | return true; |
590 | | } |
591 | | } |
592 | | return false; |
593 | | } |
594 | | |
595 | | bool ContainsStrict(const ElemType& aInterval) const |
596 | | { |
597 | | for (const auto& interval : mIntervals) { |
598 | | if (interval.ContainsStrict(aInterval)) { |
599 | | return true; |
600 | | } |
601 | | } |
602 | | return false; |
603 | | } |
604 | | |
605 | | bool Contains(const T& aX) const |
606 | | { |
607 | | for (const auto& interval : mIntervals) |
608 | | { |
609 | | if (interval.Contains(aX)) { |
610 | | return true; |
611 | | } |
612 | | } |
613 | | return false; |
614 | | } |
615 | | |
616 | | bool ContainsStrict(const T& aX) const |
617 | | { |
618 | | for (const auto& interval : mIntervals) { |
619 | | if (interval.ContainsStrict(aX)) { |
620 | | return true; |
621 | | } |
622 | | } |
623 | | return false; |
624 | | } |
625 | | |
626 | | bool ContainsWithStrictEnd(const T& aX) const |
627 | 0 | { |
628 | 0 | for (const auto& interval : mIntervals) { |
629 | 0 | if (interval.ContainsWithStrictEnd(aX)) { |
630 | 0 | return true; |
631 | 0 | } |
632 | 0 | } |
633 | 0 | return false; |
634 | 0 | } |
635 | | |
636 | | bool ContainsWithStrictEnd(const ElemType& aInterval) const |
637 | 0 | { |
638 | 0 | for (const auto& interval : mIntervals) { |
639 | 0 | if (interval.ContainsWithStrictEnd(aInterval)) { |
640 | 0 | return true; |
641 | 0 | } |
642 | 0 | } |
643 | 0 | return false; |
644 | 0 | } |
645 | | |
646 | | // Shift all values by aOffset. |
647 | | SelfType& Shift(const T& aOffset) |
648 | | { |
649 | | for (auto& interval : mIntervals) { |
650 | | interval.mStart = interval.mStart + aOffset; |
651 | | interval.mEnd = interval.mEnd + aOffset; |
652 | | } |
653 | | return *this; |
654 | | } |
655 | | |
656 | | void SetFuzz(const T& aFuzz) |
657 | 0 | { |
658 | 0 | for (auto& interval : mIntervals) { |
659 | 0 | interval.SetFuzz(aFuzz); |
660 | 0 | } |
661 | 0 | Normalize(); |
662 | 0 | } |
663 | | |
664 | | static const IndexType NoIndex = IndexType(-1); |
665 | | |
666 | | IndexType Find(const T& aValue) const |
667 | 0 | { |
668 | 0 | for (IndexType i = 0; i < mIntervals.Length(); i++) { |
669 | 0 | if (mIntervals[i].Contains(aValue)) { |
670 | 0 | return i; |
671 | 0 | } |
672 | 0 | } |
673 | 0 | return NoIndex; |
674 | 0 | } |
675 | | |
676 | | // Methods for range-based for loops. |
677 | | typename ContainerType::iterator begin() |
678 | 0 | { |
679 | 0 | return mIntervals.begin(); |
680 | 0 | } |
681 | | |
682 | | typename ContainerType::const_iterator begin() const |
683 | 0 | { |
684 | 0 | return mIntervals.begin(); |
685 | 0 | } |
686 | | |
687 | | typename ContainerType::iterator end() |
688 | 0 | { |
689 | 0 | return mIntervals.end(); |
690 | 0 | } |
691 | | |
692 | | typename ContainerType::const_iterator end() const |
693 | 0 | { |
694 | 0 | return mIntervals.end(); |
695 | 0 | } |
696 | | |
697 | | ElemType& LastInterval() |
698 | | { |
699 | | MOZ_ASSERT(!mIntervals.IsEmpty()); |
700 | | return mIntervals.LastElement(); |
701 | | } |
702 | | |
703 | | const ElemType& LastInterval() const |
704 | 0 | { |
705 | 0 | MOZ_ASSERT(!mIntervals.IsEmpty()); |
706 | 0 | return mIntervals.LastElement(); |
707 | 0 | } |
708 | | |
709 | | void Clear() |
710 | 0 | { |
711 | 0 | mIntervals.Clear(); |
712 | 0 | } |
713 | | |
714 | | protected: |
715 | | ContainerType mIntervals; |
716 | | |
717 | | private: |
718 | | void Normalize() |
719 | 0 | { |
720 | 0 | if (mIntervals.Length() >= 2) { |
721 | 0 | ContainerType normalized; |
722 | 0 |
|
723 | 0 | mIntervals.Sort(CompareIntervals()); |
724 | 0 |
|
725 | 0 | // This merges the intervals. |
726 | 0 | ElemType current(mIntervals[0]); |
727 | 0 | for (IndexType i = 1; i < mIntervals.Length(); i++) { |
728 | 0 | ElemType& interval = mIntervals[i]; |
729 | 0 | if (current.Touches(interval)) { |
730 | 0 | current = current.Span(interval); |
731 | 0 | } else { |
732 | 0 | normalized.AppendElement(std::move(current)); |
733 | 0 | current = std::move(interval); |
734 | 0 | } |
735 | 0 | } |
736 | 0 | normalized.AppendElement(std::move(current)); |
737 | 0 |
|
738 | 0 | mIntervals.Clear(); |
739 | 0 | mIntervals.AppendElements(std::move(normalized)); |
740 | 0 | } |
741 | 0 | } |
742 | | |
743 | | struct CompareIntervals |
744 | | { |
745 | | bool Equals(const ElemType& aT1, const ElemType& aT2) const |
746 | 0 | { |
747 | 0 | return aT1.mStart == aT2.mStart && aT1.mEnd == aT2.mEnd; |
748 | 0 | } |
749 | | |
750 | 0 | bool LessThan(const ElemType& aT1, const ElemType& aT2) const { |
751 | 0 | return aT1.mStart - aT1.mFuzz < aT2.mStart + aT2.mFuzz; |
752 | 0 | } |
753 | | }; |
754 | | }; |
755 | | |
756 | | // clang doesn't allow for this to be defined inline of IntervalSet. |
757 | | template<typename T> |
758 | | IntervalSet<T> Union(const IntervalSet<T>& aIntervals1, |
759 | | const IntervalSet<T>& aIntervals2) |
760 | | { |
761 | | IntervalSet<T> intervals(aIntervals1); |
762 | | intervals.Union(aIntervals2); |
763 | | return intervals; |
764 | | } |
765 | | |
766 | | template<typename T> |
767 | | IntervalSet<T> Intersection(const IntervalSet<T>& aIntervals1, |
768 | | const IntervalSet<T>& aIntervals2) |
769 | | { |
770 | | IntervalSet<T> intersection(aIntervals1); |
771 | | intersection.Intersection(aIntervals2); |
772 | | return intersection; |
773 | | } |
774 | | |
775 | | } // namespace media |
776 | | } // namespace mozilla |
777 | | |
778 | | #endif // INTERVALS_H |