Line data Source code
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 0 : Interval()
45 : : mStart(T())
46 : , mEnd(T())
47 0 : , mFuzz(T())
48 0 : { }
49 :
50 : template<typename StartArg, typename EndArg>
51 0 : Interval(StartArg&& aStart, EndArg&& aEnd)
52 0 : : mStart(Forward<StartArg>(aStart))
53 0 : , mEnd(Forward<EndArg>(aEnd))
54 0 : , mFuzz()
55 : {
56 0 : MOZ_ASSERT(aStart <= aEnd);
57 0 : }
58 :
59 : template<typename StartArg, typename EndArg, typename FuzzArg>
60 0 : Interval(StartArg&& aStart, EndArg&& aEnd, FuzzArg&& aFuzz)
61 0 : : mStart(Forward<StartArg>(aStart))
62 0 : , mEnd(Forward<EndArg>(aEnd))
63 0 : , mFuzz(Forward<FuzzArg>(aFuzz))
64 : {
65 0 : MOZ_ASSERT(aStart <= aEnd);
66 0 : }
67 :
68 0 : Interval(const SelfType& aOther)
69 0 : : mStart(aOther.mStart)
70 0 : , mEnd(aOther.mEnd)
71 0 : , mFuzz(aOther.mFuzz)
72 0 : { }
73 :
74 0 : Interval(SelfType&& aOther)
75 0 : : mStart(Move(aOther.mStart))
76 0 : , mEnd(Move(aOther.mEnd))
77 0 : , mFuzz(Move(aOther.mFuzz))
78 0 : { }
79 :
80 0 : SelfType& operator= (const SelfType& aOther)
81 : {
82 0 : mStart = aOther.mStart;
83 0 : mEnd = aOther.mEnd;
84 0 : mFuzz = aOther.mFuzz;
85 0 : return *this;
86 : }
87 :
88 0 : SelfType& operator= (SelfType&& aOther)
89 : {
90 0 : MOZ_ASSERT(&aOther != this, "self-moves are prohibited");
91 : this->~Interval();
92 0 : new(this) Interval(Move(aOther));
93 0 : 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 0 : SelfType operator+ (const T& aVal) const
105 : {
106 0 : return SelfType(mStart + aVal, mEnd + aVal, mFuzz);
107 : }
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 0 : bool operator== (const SelfType& aOther) const
123 : {
124 0 : return mStart == aOther.mStart && mEnd == aOther.mEnd;
125 : }
126 :
127 : bool operator!= (const SelfType& aOther) const
128 : {
129 : return !(*this == aOther);
130 : }
131 :
132 0 : bool Contains(const T& aX) const
133 : {
134 0 : return mStart - mFuzz <= aX && aX < mEnd + mFuzz;
135 : }
136 :
137 0 : bool ContainsStrict(const T& aX) const
138 : {
139 0 : return mStart <= aX && aX < mEnd;
140 : }
141 :
142 0 : bool ContainsWithStrictEnd(const T& aX) const
143 : {
144 0 : return mStart - mFuzz <= aX && aX < mEnd;
145 : }
146 :
147 0 : bool Contains(const SelfType& aOther) const
148 : {
149 0 : return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz)
150 0 : && (aOther.mEnd - aOther.mFuzz <= mEnd + mFuzz);
151 : }
152 :
153 0 : bool ContainsStrict(const SelfType& aOther) const
154 : {
155 0 : return mStart <= aOther.mStart && aOther.mEnd <= mEnd;
156 : }
157 :
158 0 : bool ContainsWithStrictEnd(const SelfType& aOther) const
159 : {
160 0 : return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz)
161 0 : && aOther.mEnd <= mEnd;
162 : }
163 :
164 0 : bool Intersects(const SelfType& aOther) const
165 : {
166 0 : return (mStart - mFuzz < aOther.mEnd + aOther.mFuzz)
167 0 : && (aOther.mStart - aOther.mFuzz < mEnd + mFuzz);
168 : }
169 :
170 0 : bool IntersectsStrict(const SelfType& aOther) const
171 : {
172 0 : return mStart < aOther.mEnd && aOther.mStart < mEnd;
173 : }
174 :
175 : // Same as Intersects, but including the boundaries.
176 0 : bool Touches(const SelfType& aOther) const
177 : {
178 0 : return (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz)
179 0 : && (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 0 : bool RightOf(const SelfType& aOther) const
190 : {
191 0 : return aOther.mEnd - aOther.mFuzz <= mStart + mFuzz;
192 : }
193 :
194 0 : bool LeftOf(const SelfType& aOther) const
195 : {
196 0 : return mEnd - mFuzz <= aOther.mStart + aOther.mFuzz;
197 : }
198 :
199 0 : SelfType Span(const SelfType& aOther) const
200 : {
201 0 : if (IsEmpty()) {
202 0 : return aOther;
203 : }
204 0 : SelfType result(*this);
205 0 : if (aOther.mStart < mStart) {
206 0 : result.mStart = aOther.mStart;
207 : }
208 0 : if (mEnd < aOther.mEnd) {
209 0 : result.mEnd = aOther.mEnd;
210 : }
211 0 : if (mFuzz < aOther.mFuzz) {
212 0 : result.mFuzz = aOther.mFuzz;
213 : }
214 0 : return result;
215 : }
216 :
217 0 : SelfType Intersection(const SelfType& aOther) const
218 : {
219 0 : const T& s = std::max(mStart, aOther.mStart);
220 0 : const T& e = std::min(mEnd, aOther.mEnd);
221 0 : const T& f = std::max(mFuzz, aOther.mFuzz);
222 0 : if (s < e) {
223 0 : return SelfType(s, e, f);
224 : }
225 : // Return an empty interval.
226 0 : return SelfType();
227 : }
228 :
229 0 : T Length() const
230 : {
231 0 : return mEnd - mStart;
232 : }
233 :
234 0 : bool IsEmpty() const
235 : {
236 0 : return mStart == mEnd;
237 : }
238 :
239 0 : void SetFuzz(const T& aFuzz)
240 : {
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 0 : bool TouchesOnRight(const SelfType& aOther) const
247 : {
248 0 : return aOther.mStart <= mStart
249 0 : && (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz)
250 0 : && (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 0 : IntervalSet()
272 0 : {
273 0 : }
274 0 : virtual ~IntervalSet()
275 : {
276 0 : }
277 :
278 0 : IntervalSet(const SelfType& aOther)
279 0 : : mIntervals(aOther.mIntervals)
280 : {
281 0 : }
282 :
283 0 : IntervalSet(SelfType&& aOther)
284 0 : {
285 0 : mIntervals.AppendElements(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 0 : explicit IntervalSet(ElemType&& aOther)
296 0 : {
297 0 : if (!aOther.IsEmpty()) {
298 0 : mIntervals.AppendElement(Move(aOther));
299 : }
300 0 : }
301 :
302 0 : bool operator== (const SelfType& aOther) const
303 : {
304 0 : return mIntervals == aOther.mIntervals;
305 : }
306 :
307 0 : bool operator!= (const SelfType& aOther) const
308 : {
309 0 : return mIntervals != aOther.mIntervals;
310 : }
311 :
312 0 : SelfType& operator= (const SelfType& aOther)
313 : {
314 0 : mIntervals = aOther.mIntervals;
315 0 : return *this;
316 : }
317 :
318 0 : SelfType& operator= (SelfType&& aOther)
319 : {
320 0 : MOZ_ASSERT(&aOther != this, "self-moves are prohibited");
321 0 : this->~IntervalSet();
322 0 : new(this) IntervalSet(Move(aOther));
323 0 : return *this;
324 : }
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(Move(aInterval));
340 : }
341 : return *this;
342 : }
343 :
344 0 : SelfType& Add(const SelfType& aIntervals)
345 : {
346 0 : mIntervals.AppendElements(aIntervals.mIntervals);
347 0 : Normalize();
348 0 : return *this;
349 : }
350 :
351 0 : SelfType& Add(const ElemType& aInterval)
352 : {
353 0 : if (aInterval.IsEmpty()) {
354 0 : return *this;
355 : }
356 0 : if (mIntervals.IsEmpty()) {
357 0 : mIntervals.AppendElement(aInterval);
358 0 : return *this;
359 : }
360 0 : ElemType& last = mIntervals.LastElement();
361 0 : if (aInterval.TouchesOnRight(last)) {
362 0 : last = last.Span(aInterval);
363 0 : 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 0 : if (aInterval.RightOf(last)) {
368 0 : mIntervals.AppendElement(aInterval);
369 0 : return *this;
370 : }
371 :
372 0 : ContainerType normalized;
373 0 : ElemType current(aInterval);
374 0 : IndexType i = 0;
375 0 : for (; i < mIntervals.Length(); i++) {
376 0 : ElemType& interval = mIntervals[i];
377 0 : if (current.Touches(interval)) {
378 0 : current = current.Span(interval);
379 0 : } else if (current.LeftOf(interval)) {
380 0 : break;
381 : } else {
382 0 : normalized.AppendElement(Move(interval));
383 : }
384 : }
385 0 : normalized.AppendElement(Move(current));
386 0 : for (; i < mIntervals.Length(); i++) {
387 0 : normalized.AppendElement(Move(mIntervals[i]));
388 : }
389 0 : mIntervals.Clear();
390 0 : mIntervals.AppendElements(Move(normalized));
391 :
392 0 : return *this;
393 : }
394 :
395 0 : SelfType& operator+= (const SelfType& aIntervals)
396 : {
397 0 : Add(aIntervals);
398 0 : return *this;
399 : }
400 :
401 0 : SelfType& operator+= (const ElemType& aInterval)
402 : {
403 0 : Add(aInterval);
404 0 : 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 0 : SelfType operator+ (const ElemType& aInterval) const
415 : {
416 0 : SelfType intervals(*this);
417 0 : intervals.Add(aInterval);
418 0 : return intervals;
419 : }
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 0 : SelfType& operator-= (const ElemType& aInterval)
434 : {
435 0 : if (aInterval.IsEmpty() || mIntervals.IsEmpty()) {
436 0 : return *this;
437 : }
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(Move(startInterval));
443 0 : intervals += Move(endInterval);
444 0 : return Intersection(intervals);
445 : }
446 :
447 0 : SelfType& operator-= (const SelfType& aIntervals)
448 : {
449 0 : for (const auto& interval : aIntervals.mIntervals) {
450 0 : *this -= interval;
451 : }
452 0 : return *this;
453 : }
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 0 : SelfType& Intersection(const SelfType& aOther)
484 : {
485 0 : ContainerType intersection;
486 :
487 0 : const ContainerType& other = aOther.mIntervals;
488 0 : IndexType i = 0, j = 0;
489 0 : for (; i < mIntervals.Length() && j < other.Length();) {
490 0 : if (mIntervals[i].IntersectsStrict(other[j])) {
491 0 : intersection.AppendElement(mIntervals[i].Intersection(other[j]));
492 : }
493 0 : if (mIntervals[i].mEnd < other[j].mEnd) {
494 0 : i++;
495 : } else {
496 0 : j++;
497 : }
498 : }
499 0 : mIntervals.Clear();
500 0 : mIntervals.AppendElements(Move(intersection));
501 0 : return *this;
502 : }
503 :
504 : SelfType& Intersection(const ElemType& aInterval)
505 : {
506 : SelfType intervals(aInterval);
507 : return Intersection(intervals);
508 : }
509 :
510 0 : const ElemType& operator[] (IndexType aIndex) const
511 : {
512 0 : return mIntervals[aIndex];
513 : }
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 0 : T GetStart(bool* aExists = nullptr) const
518 : {
519 0 : bool exists = !mIntervals.IsEmpty();
520 :
521 0 : if (aExists) {
522 0 : *aExists = exists;
523 : }
524 :
525 0 : if (exists) {
526 0 : return mIntervals[0].mStart;
527 : } else {
528 0 : return T();
529 : }
530 : }
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 0 : T GetEnd(bool* aExists = nullptr) const
535 : {
536 0 : bool exists = !mIntervals.IsEmpty();
537 0 : if (aExists) {
538 0 : *aExists = exists;
539 : }
540 :
541 0 : if (exists) {
542 0 : return mIntervals.LastElement().mEnd;
543 : } else {
544 0 : return T();
545 : }
546 : }
547 :
548 0 : IndexType Length() const
549 : {
550 0 : return mIntervals.Length();
551 : }
552 :
553 0 : T Start(IndexType aIndex) const
554 : {
555 0 : 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 0 : T End(IndexType aIndex) const
570 : {
571 0 : 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 0 : bool Contains(const ElemType& aInterval) const
586 : {
587 0 : for (const auto& interval : mIntervals) {
588 0 : if (interval.Contains(aInterval)) {
589 0 : return true;
590 : }
591 : }
592 0 : return false;
593 : }
594 :
595 0 : bool ContainsStrict(const ElemType& aInterval) const
596 : {
597 0 : for (const auto& interval : mIntervals) {
598 0 : if (interval.ContainsStrict(aInterval)) {
599 0 : return true;
600 : }
601 : }
602 0 : 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 0 : bool ContainsWithStrictEnd(const T& aX) const
627 : {
628 0 : for (const auto& interval : mIntervals) {
629 0 : if (interval.ContainsWithStrictEnd(aX)) {
630 0 : return true;
631 : }
632 : }
633 0 : return false;
634 : }
635 :
636 : // Shift all values by aOffset.
637 0 : SelfType& Shift(const T& aOffset)
638 : {
639 0 : for (auto& interval : mIntervals) {
640 0 : interval.mStart = interval.mStart + aOffset;
641 0 : interval.mEnd = interval.mEnd + aOffset;
642 : }
643 0 : return *this;
644 : }
645 :
646 0 : void SetFuzz(const T& aFuzz)
647 : {
648 0 : for (auto& interval : mIntervals) {
649 0 : interval.SetFuzz(aFuzz);
650 : }
651 0 : Normalize();
652 0 : }
653 :
654 : static const IndexType NoIndex = IndexType(-1);
655 :
656 0 : IndexType Find(const T& aValue) const
657 : {
658 0 : for (IndexType i = 0; i < mIntervals.Length(); i++) {
659 0 : if (mIntervals[i].Contains(aValue)) {
660 0 : return i;
661 : }
662 : }
663 0 : return NoIndex;
664 : }
665 :
666 : // Methods for range-based for loops.
667 0 : typename ContainerType::iterator begin()
668 : {
669 0 : return mIntervals.begin();
670 : }
671 :
672 0 : typename ContainerType::const_iterator begin() const
673 : {
674 0 : return mIntervals.begin();
675 : }
676 :
677 0 : typename ContainerType::iterator end()
678 : {
679 0 : return mIntervals.end();
680 : }
681 :
682 0 : typename ContainerType::const_iterator end() const
683 : {
684 0 : return mIntervals.end();
685 : }
686 :
687 : ElemType& LastInterval()
688 : {
689 : MOZ_ASSERT(!mIntervals.IsEmpty());
690 : return mIntervals.LastElement();
691 : }
692 :
693 0 : const ElemType& LastInterval() const
694 : {
695 0 : MOZ_ASSERT(!mIntervals.IsEmpty());
696 0 : return mIntervals.LastElement();
697 : }
698 :
699 0 : void Clear()
700 : {
701 0 : mIntervals.Clear();
702 0 : }
703 :
704 : protected:
705 : ContainerType mIntervals;
706 :
707 : private:
708 0 : void Normalize()
709 : {
710 0 : if (mIntervals.Length() >= 2) {
711 0 : ContainerType normalized;
712 :
713 0 : mIntervals.Sort(CompareIntervals());
714 :
715 : // This merges the intervals.
716 0 : ElemType current(mIntervals[0]);
717 0 : for (IndexType i = 1; i < mIntervals.Length(); i++) {
718 0 : ElemType& interval = mIntervals[i];
719 0 : if (current.Touches(interval)) {
720 0 : current = current.Span(interval);
721 : } else {
722 0 : normalized.AppendElement(Move(current));
723 0 : current = Move(interval);
724 : }
725 : }
726 0 : normalized.AppendElement(Move(current));
727 :
728 0 : mIntervals.Clear();
729 0 : mIntervals.AppendElements(Move(normalized));
730 : }
731 0 : }
732 :
733 : struct CompareIntervals
734 : {
735 0 : bool Equals(const ElemType& aT1, const ElemType& aT2) const
736 : {
737 0 : return aT1.mStart == aT2.mStart && aT1.mEnd == aT2.mEnd;
738 : }
739 :
740 0 : bool LessThan(const ElemType& aT1, const ElemType& aT2) const {
741 0 : return aT1.mStart - aT1.mFuzz < aT2.mStart + aT2.mFuzz;
742 : }
743 : };
744 : };
745 :
746 : // clang doesn't allow for this to be defined inline of IntervalSet.
747 : template<typename T>
748 : IntervalSet<T> Union(const IntervalSet<T>& aIntervals1,
749 : const IntervalSet<T>& aIntervals2)
750 : {
751 : IntervalSet<T> intervals(aIntervals1);
752 : intervals.Union(aIntervals2);
753 : return intervals;
754 : }
755 :
756 : template<typename T>
757 0 : IntervalSet<T> Intersection(const IntervalSet<T>& aIntervals1,
758 : const IntervalSet<T>& aIntervals2)
759 : {
760 0 : IntervalSet<T> intersection(aIntervals1);
761 0 : intersection.Intersection(aIntervals2);
762 0 : return intersection;
763 : }
764 :
765 : } // namespace media
766 : } // namespace mozilla
767 :
768 : #endif // INTERVALS_H
|