tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Intervals.h (21032B)


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