Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/media/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 20 kB image not shown  

Quelle  Intervals.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef DOM_MEDIA_INTERVALS_H_
#define DOM_MEDIA_INTERVALS_H_

#include <algorithm>
#include <type_traits>

#include "nsTArray.h"
#include "nsString.h"
#include "nsPrintfCString.h"

// Specialization for nsTArray CopyChooser.
namespace mozilla::media {
template <class T>
class IntervalSet;
class TimeUnit;
}  // namespace mozilla::media

template <class E>
struct nsTArray_RelocationStrategy<mozilla::media::IntervalSet<E>> {
  typedef nsTArray_RelocateUsingMoveConstructor<mozilla::media::IntervalSet<E>>
      Type;
};

namespace mozilla::media {

/* Interval defines an interval between two points. Unlike a traditional
   interval [A,B] where A <= x <= B, the upper boundary B is exclusive: A <= x <
   B (e.g [A,B[ or [A,B) depending on where you're living) It provides basic
   interval arithmetic and fuzzy edges. The type T must provides a default
   constructor and +, -, <, <= and == operators.
 */

template <typename T>
class Interval {
 public:
  typedef Interval<T> SelfType;

  Interval() : mStart(T()), mEnd(T()), mFuzz(T()) {}

  template <typename StartArg, typename EndArg>
  Interval(StartArg&& aStart, EndArg&& aEnd)
      : mStart(aStart), mEnd(aEnd), mFuzz() {
    MOZ_DIAGNOSTIC_ASSERT(mStart <= mEnd, "Invalid Interval");
  }

  template <typename StartArg, typename EndArg, typename FuzzArg>
  Interval(StartArg&& aStart, EndArg&& aEnd, FuzzArg&& aFuzz)
      : mStart(aStart), mEnd(aEnd), mFuzz(aFuzz) {
    MOZ_DIAGNOSTIC_ASSERT(mStart <= mEnd, "Invalid Interval");
  }

  Interval(const SelfType& aOther)
      : mStart(aOther.mStart), mEnd(aOther.mEnd), mFuzz(aOther.mFuzz) {}

  Interval(SelfType&& aOther)
      : mStart(std::move(aOther.mStart)),
        mEnd(std::move(aOther.mEnd)),
        mFuzz(std::move(aOther.mFuzz)) {}

  SelfType& operator=(const SelfType& aOther) {
    mStart = aOther.mStart;
    mEnd = aOther.mEnd;
    mFuzz = aOther.mFuzz;
    return *this;
  }

  SelfType& operator=(SelfType&& aOther) {
    MOZ_ASSERT(&aOther != this"self-moves are prohibited");
    this->~Interval();
    new (this) Interval(std::move(aOther));
    return *this;
  }

  // Basic interval arithmetic operator definition.
  SelfType operator+(const SelfType& aOther) const {
    return SelfType(mStart + aOther.mStart, mEnd + aOther.mEnd,
                    mFuzz + aOther.mFuzz);
  }

  SelfType operator+(const T& aVal) const {
    return SelfType(mStart + aVal, mEnd + aVal, mFuzz);
  }

  SelfType operator-(const SelfType& aOther) const {
    return SelfType(mStart - aOther.mEnd, mEnd - aOther.mStart,
                    mFuzz + aOther.mFuzz);
  }

  SelfType operator-(const T& aVal) const {
    return SelfType(mStart - aVal, mEnd - aVal, mFuzz);
  }

  SelfType& operator+=(const SelfType& aOther) {
    mStart += aOther.mStart;
    mEnd += aOther.mEnd;
    mFuzz += aOther.mFuzz;
    return *this;
  }

  SelfType& operator+=(const T& aVal) {
    mStart += aVal;
    mEnd += aVal;
    return *this;
  }

  SelfType& operator-=(const SelfType& aOther) {
    mStart -= aOther.mStart;
    mEnd -= aOther.mEnd;
    mFuzz += aOther.mFuzz;
    return *this;
  }

  SelfType& operator-=(const T& aVal) {
    mStart -= aVal;
    mEnd -= aVal;
    return *this;
  }

  bool operator==(const SelfType& aOther) const {
    return mStart == aOther.mStart && mEnd == aOther.mEnd;
  }

  bool operator!=(const SelfType& aOther) const { return !(*this == aOther); }

  bool Contains(const T& aX) const {
    return mStart - mFuzz <= aX && aX < mEnd + mFuzz;
  }

  bool ContainsStrict(const T& aX) const { return mStart <= aX && aX < mEnd; }

  bool ContainsWithStrictEnd(const T& aX) const {
    return mStart - mFuzz <= aX && aX < mEnd;
  }

  bool Contains(const SelfType& aOther) const {
    return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz) &&
           (aOther.mEnd - aOther.mFuzz <= mEnd + mFuzz);
  }

  bool ContainsStrict(const SelfType& aOther) const {
    return mStart <= aOther.mStart && aOther.mEnd <= mEnd;
  }

  bool ContainsWithStrictEnd(const SelfType& aOther) const {
    return (mStart - mFuzz <= aOther.mStart + aOther.mFuzz) &&
           aOther.mEnd <= mEnd;
  }

  bool Intersects(const SelfType& aOther) const {
    return (mStart - mFuzz < aOther.mEnd + aOther.mFuzz) &&
           (aOther.mStart - aOther.mFuzz < mEnd + mFuzz);
  }

  bool IntersectsStrict(const SelfType& aOther) const {
    return mStart < aOther.mEnd && aOther.mStart < mEnd;
  }

  // Same as Intersects, but including the boundaries.
  bool Touches(const SelfType& aOther) const {
    return (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz) &&
           (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz);
  }

  // Returns true if aOther is strictly to the right of this and contiguous.
  // This operation isn't commutative.
  bool Contiguous(const SelfType& aOther) const {
    return mEnd <= aOther.mStart &&
           aOther.mStart - mEnd <= mFuzz + aOther.mFuzz;
  }

  bool RightOf(const SelfType& aOther) const {
    return aOther.mEnd - aOther.mFuzz <= mStart + mFuzz;
  }

  bool LeftOf(const SelfType& aOther) const {
    return mEnd - mFuzz <= aOther.mStart + aOther.mFuzz;
  }

  SelfType Span(const SelfType& aOther) const {
    if (IsEmpty()) {
      return aOther;
    }
    SelfType result(*this);
    if (aOther.mStart < mStart) {
      result.mStart = aOther.mStart;
    }
    if (mEnd < aOther.mEnd) {
      result.mEnd = aOther.mEnd;
    }
    if (mFuzz < aOther.mFuzz) {
      result.mFuzz = aOther.mFuzz;
    }
    return result;
  }

  SelfType Intersection(const SelfType& aOther) const {
    const T& s = std::max(mStart, aOther.mStart);
    const T& e = std::min(mEnd, aOther.mEnd);
    const T& f = std::max(mFuzz, aOther.mFuzz);
    if (s < e) {
      return SelfType(s, e, f);
    }
    // Return an empty interval.
    return SelfType();
  }

  T Length() const { return mEnd - mStart; }

  bool IsEmpty() const { return mStart == mEnd; }

  void SetFuzz(const T& aFuzz) { mFuzz = aFuzz; }

  // Returns true if the two intervals intersect with this being on the right
  // of aOther
  bool TouchesOnRight(const SelfType& aOther) const {
    return aOther.mStart <= mStart &&
           (mStart - mFuzz <= aOther.mEnd + aOther.mFuzz) &&
           (aOther.mStart - aOther.mFuzz <= mEnd + mFuzz);
  }

  // Returns true if the two intervals intersect with this being on the right
  // of aOther, ignoring fuzz.
  bool TouchesOnRightStrict(const SelfType& aOther) const {
    return aOther.mStart <= mStart && mStart <= aOther.mEnd;
  }

  nsCString ToString() const {
    if constexpr (std::is_same_v<T, TimeUnit>) {
      return nsPrintfCString("[%s, %s](%s)", mStart.ToString().get(),
                             mEnd.ToString().get(), mFuzz.ToString().get());
    } else if constexpr (std::is_same_v<T, double>) {
      return nsPrintfCString("[%lf, %lf](%lf)", mStart, mEnd, mFuzz);
    }
  }

  T mStart;
  T mEnd;
  T mFuzz;
};

// An IntervalSet in a collection of Intervals. The IntervalSet is always
// normalized.
template <typename T>
class IntervalSet {
 public:
  typedef IntervalSet<T> SelfType;
  typedef Interval<T> ElemType;
  typedef AutoTArray<ElemType, 4> ContainerType;
  typedef typename ContainerType::index_type IndexType;

  IntervalSet() = default;
  virtual ~IntervalSet() = default;

  IntervalSet(const SelfType& aOther) : mIntervals(aOther.mIntervals.Clone()) {}

  IntervalSet(SelfType&& aOther) {
    mIntervals.AppendElements(std::move(aOther.mIntervals));
  }

  explicit IntervalSet(const ElemType& aOther) {
    if (!aOther.IsEmpty()) {
      mIntervals.AppendElement(aOther);
    }
  }

  explicit IntervalSet(ElemType&& aOther) {
    if (!aOther.IsEmpty()) {
      mIntervals.AppendElement(std::move(aOther));
    }
  }

  bool operator==(const SelfType& aOther) const {
    return mIntervals == aOther.mIntervals;
  }

  bool operator!=(const SelfType& aOther) const {
    return mIntervals != aOther.mIntervals;
  }

  SelfType& operator=(const SelfType& aOther) {
    mIntervals = aOther.mIntervals.Clone();
    return *this;
  }

  SelfType& operator=(SelfType&& aOther) {
    MOZ_ASSERT(&aOther != this"self-moves are prohibited");
    this->~IntervalSet();
    new (this) IntervalSet(std::move(aOther));
    return *this;
  }

  SelfType& operator=(const ElemType& aInterval) {
    mIntervals.Clear();
    if (!aInterval.IsEmpty()) {
      mIntervals.AppendElement(aInterval);
    }
    return *this;
  }

  SelfType& operator=(ElemType&& aInterval) {
    mIntervals.Clear();
    if (!aInterval.IsEmpty()) {
      mIntervals.AppendElement(std::move(aInterval));
    }
    return *this;
  }

  SelfType& Add(const SelfType& aIntervals) {
    if (aIntervals.mIntervals.Length() == 1) {
      Add(aIntervals.mIntervals[0]);
    } else {
      mIntervals.AppendElements(aIntervals.mIntervals);
      Normalize();
    }
    return *this;
  }

  SelfType& Add(const ElemType& aInterval) {
    if (aInterval.IsEmpty()) {
      return *this;
    }
    if (mIntervals.IsEmpty()) {
      mIntervals.AppendElement(aInterval);
      return *this;
    }
    ElemType& last = mIntervals.LastElement();
    if (aInterval.TouchesOnRight(last)) {
      last = last.Span(aInterval);
      return *this;
    }
    // Most of our actual usage is adding an interval that will be outside the
    // range. We can speed up normalization here.
    if (aInterval.RightOf(last)) {
      mIntervals.AppendElement(aInterval);
      return *this;
    }

    ContainerType normalized;
    ElemType current(aInterval);
    IndexType i = 0;
    for (; i < mIntervals.Length(); i++) {
      ElemType& interval = mIntervals[i];
      if (current.Touches(interval)) {
        current = current.Span(interval);
      } else if (current.LeftOf(interval)) {
        break;
      } else {
        normalized.AppendElement(std::move(interval));
      }
    }
    normalized.AppendElement(std::move(current));
    for (; i < mIntervals.Length(); i++) {
      normalized.AppendElement(std::move(mIntervals[i]));
    }
    mIntervals.Clear();
    mIntervals.AppendElements(std::move(normalized));

    return *this;
  }

  SelfType& operator+=(const SelfType& aIntervals) {
    Add(aIntervals);
    return *this;
  }

  SelfType& operator+=(const ElemType& aInterval) {
    Add(aInterval);
    return *this;
  }

  SelfType operator+(const SelfType& aIntervals) const {
    SelfType intervals(*this);
    intervals.Add(aIntervals);
    return intervals;
  }

  SelfType operator+(const ElemType& aInterval) const {
    SelfType intervals(*this);
    intervals.Add(aInterval);
    return intervals;
  }

  friend SelfType operator+(const ElemType& aInterval,
                            const SelfType& aIntervals) {
    SelfType intervals;
    intervals.Add(aInterval);
    intervals.Add(aIntervals);
    return intervals;
  }

  // Excludes an interval from an IntervalSet.
  SelfType& operator-=(const ElemType& aInterval) {
    if (aInterval.IsEmpty() || mIntervals.IsEmpty()) {
      return *this;
    }
    if (mIntervals.Length() == 1 &&
        mIntervals[0].TouchesOnRightStrict(aInterval)) {
      // Fast path when we're removing from the front of a set with a
      // single interval. This is common for the buffered time ranges
      // we see on Twitch.
      if (aInterval.mEnd >= mIntervals[0].mEnd) {
        mIntervals.RemoveElementAt(0);
      } else {
        mIntervals[0].mStart = aInterval.mEnd;
        mIntervals[0].mFuzz = std::max(mIntervals[0].mFuzz, aInterval.mFuzz);
      }
      return *this;
    }

    // General case performed by inverting aInterval within the bounds of
    // mIntervals and then doing the intersection.
    T firstEnd = std::max(mIntervals[0].mStart, aInterval.mStart);
    T secondStart = std::min(mIntervals.LastElement().mEnd, aInterval.mEnd);
    ElemType startInterval(mIntervals[0].mStart, firstEnd);
    ElemType endInterval(secondStart, mIntervals.LastElement().mEnd);
    SelfType intervals(std::move(startInterval));
    intervals += std::move(endInterval);
    return Intersection(intervals);
  }

  SelfType& operator-=(const SelfType& aIntervals) {
    for (const auto& interval : aIntervals.mIntervals) {
      *this -= interval;
    }
    return *this;
  }

  SelfType operator-(const SelfType& aInterval) const {
    SelfType intervals(*this);
    intervals -= aInterval;
    return intervals;
  }

  SelfType operator-(const ElemType& aInterval) const {
    SelfType intervals(*this);
    intervals -= aInterval;
    return intervals;
  }

  // Mutate this IntervalSet to be the union of this and aOther.
  SelfType& Union(const SelfType& aOther) {
    Add(aOther);
    return *this;
  }

  SelfType& Union(const ElemType& aInterval) {
    Add(aInterval);
    return *this;
  }

  // Mutate this TimeRange to be the intersection of this and aOther.
  SelfType& Intersection(const SelfType& aOther) {
    ContainerType intersection;

    // Ensure the intersection has enough capacity to store the upper bound on
    // the intersection size. This ensures that we don't spend time reallocating
    // the storage as we append, at the expense of extra memory.
    intersection.SetCapacity(std::max(aOther.Length(), mIntervals.Length()));

    const ContainerType& other = aOther.mIntervals;
    IndexType i = 0, j = 0;
    for (; i < mIntervals.Length() && j < other.Length();) {
      if (mIntervals[i].IntersectsStrict(other[j])) {
        intersection.AppendElement(mIntervals[i].Intersection(other[j]));
      }
      if (mIntervals[i].mEnd < other[j].mEnd) {
        i++;
      } else {
        j++;
      }
    }
    mIntervals = std::move(intersection);
    return *this;
  }

  SelfType& Intersection(const ElemType& aInterval) {
    SelfType intervals(aInterval);
    return Intersection(intervals);
  }

  const ElemType& operator[](IndexType aIndex) const {
    return mIntervals[aIndex];
  }

  // Returns the start boundary of the first interval. Or a default constructed
  // T if IntervalSet is empty (and aExists if provided will be set to false).
  T GetStart(bool* aExists = nullptr) const {
    bool exists = !mIntervals.IsEmpty();

    if (aExists) {
      *aExists = exists;
    }

    if (exists) {
      return mIntervals[0].mStart;
    } else {
      return T();
    }
  }

  // Returns the end boundary of the last interval. Or a default constructed T
  // if IntervalSet is empty (and aExists if provided will be set to false).
  T GetEnd(bool* aExists = nullptr) const {
    bool exists = !mIntervals.IsEmpty();
    if (aExists) {
      *aExists = exists;
    }

    if (exists) {
      return mIntervals.LastElement().mEnd;
    } else {
      return T();
    }
  }

  IndexType Length() const { return mIntervals.Length(); }

  bool IsEmpty() const { return mIntervals.IsEmpty(); }

  T Start(IndexType aIndex) const { return mIntervals[aIndex].mStart; }

  T Start(IndexType aIndex, bool& aExists) const {
    aExists = aIndex < mIntervals.Length();

    if (aExists) {
      return mIntervals[aIndex].mStart;
    } else {
      return T();
    }
  }

  T End(IndexType aIndex) const { return mIntervals[aIndex].mEnd; }

  T End(IndexType aIndex, bool& aExists) const {
    aExists = aIndex < mIntervals.Length();

    if (aExists) {
      return mIntervals[aIndex].mEnd;
    } else {
      return T();
    }
  }

  bool Contains(const ElemType& aInterval) const {
    for (const auto& interval : mIntervals) {
      if (interval.Contains(aInterval)) {
        return true;
      }
    }
    return false;
  }

  bool ContainsStrict(const ElemType& aInterval) const {
    for (const auto& interval : mIntervals) {
      if (interval.ContainsStrict(aInterval)) {
        return true;
      }
    }
    return false;
  }

  bool Contains(const T& aX) const {
    for (const auto& interval : mIntervals) {
      if (interval.Contains(aX)) {
        return true;
      }
    }
    return false;
  }

  bool ContainsStrict(const T& aX) const {
    for (const auto& interval : mIntervals) {
      if (interval.ContainsStrict(aX)) {
        return true;
      }
    }
    return false;
  }

  bool ContainsWithStrictEnd(const T& aX) const {
    for (const auto& interval : mIntervals) {
      if (interval.ContainsWithStrictEnd(aX)) {
        return true;
      }
    }
    return false;
  }

  bool ContainsWithStrictEnd(const ElemType& aInterval) const {
    for (const auto& interval : mIntervals) {
      if (interval.ContainsWithStrictEnd(aInterval)) {
        return true;
      }
    }
    return false;
  }

  bool Intersects(const ElemType& aInterval) const {
    for (const auto& interval : mIntervals) {
      if (interval.Intersects(aInterval)) {
        return true;
      }
    }
    return false;
  }

  bool IntersectsStrict(const ElemType& aInterval) const {
    for (const auto& interval : mIntervals) {
      if (interval.IntersectsStrict(aInterval)) {
        return true;
      }
    }
    return false;
  }

  // Returns if there's any intersection between this and aOther.
  bool IntersectsStrict(const SelfType& aOther) const {
    const ContainerType& other = aOther.mIntervals;
    IndexType i = 0, j = 0;
    for (; i < mIntervals.Length() && j < other.Length();) {
      if (mIntervals[i].IntersectsStrict(other[j])) {
        return true;
      }
      if (mIntervals[i].mEnd < other[j].mEnd) {
        i++;
      } else {
        j++;
      }
    }
    return false;
  }

  bool IntersectsWithStrictEnd(const ElemType& aInterval) const {
    for (const auto& interval : mIntervals) {
      if (interval.IntersectsWithStrictEnd(aInterval)) {
        return true;
      }
    }
    return false;
  }

  // Shift all values by aOffset.
  SelfType& Shift(const T& aOffset) {
    for (auto& interval : mIntervals) {
      interval.mStart = interval.mStart + aOffset;
      interval.mEnd = interval.mEnd + aOffset;
    }
    return *this;
  }

  void SetFuzz(const T& aFuzz) {
    for (auto& interval : mIntervals) {
      interval.SetFuzz(aFuzz);
    }
    MergeOverlappingIntervals();
  }

  static const IndexType NoIndex = IndexType(-1);

  IndexType Find(const T& aValue) const {
    for (IndexType i = 0; i < mIntervals.Length(); i++) {
      if (mIntervals[i].Contains(aValue)) {
        return i;
      }
    }
    return NoIndex;
  }

  // Methods for range-based for loops.
  typename ContainerType::iterator begin() { return mIntervals.begin(); }

  typename ContainerType::const_iterator begin() const {
    return mIntervals.begin();
  }

  typename ContainerType::const_iterator cbegin() const {
    return mIntervals.cbegin();
  }

  typename ContainerType::iterator end() { return mIntervals.end(); }

  typename ContainerType::const_iterator end() const {
    return mIntervals.end();
  }

  typename ContainerType::const_iterator cend() const {
    return mIntervals.cend();
  }

  ElemType& LastInterval() {
    MOZ_ASSERT(!mIntervals.IsEmpty());
    return mIntervals.LastElement();
  }

  const ElemType& LastInterval() const {
    MOZ_ASSERT(!mIntervals.IsEmpty());
    return mIntervals.LastElement();
  }

  void Clear() { mIntervals.Clear(); }

 protected:
  ContainerType mIntervals;

 private:
  void Normalize() {
    if (mIntervals.Length() < 2) {
      return;
    }
    mIntervals.Sort(CompareIntervals());
    MergeOverlappingIntervals();
  }

  void MergeOverlappingIntervals() {
    if (mIntervals.Length() < 2) {
      return;
    }

    // This merges the intervals in place.
    IndexType read = 0;
    IndexType write = 0;
    while (read < mIntervals.Length()) {
      ElemType current(mIntervals[read]);
      read++;
      while (read < mIntervals.Length() && current.Touches(mIntervals[read])) {
        current = current.Span(mIntervals[read]);
        read++;
      }
      mIntervals[write] = current;
      write++;
    }
    mIntervals.SetLength(write);
  }

  struct CompareIntervals {
    bool Equals(const ElemType& aT1, const ElemType& aT2) const {
      return aT1.mStart == aT2.mStart && aT1.mEnd == aT2.mEnd;
    }

    bool LessThan(const ElemType& aT1, const ElemType& aT2) const {
      return aT1.mStart < aT2.mStart;
    }
  };
};

// clang doesn't allow for this to be defined inline of IntervalSet.
template <typename T>
IntervalSet<T> Union(const IntervalSet<T>& aIntervals1,
                     const IntervalSet<T>& aIntervals2) {
  IntervalSet<T> intervals(aIntervals1);
  intervals.Union(aIntervals2);
  return intervals;
}

template <typename T>
IntervalSet<T> Intersection(const IntervalSet<T>& aIntervals1,
                            const IntervalSet<T>& aIntervals2) {
  IntervalSet<T> intersection(aIntervals1);
  intersection.Intersection(aIntervals2);
  return intersection;
}

}  // namespace mozilla::media

#endif  // DOM_MEDIA_INTERVALS_H_

Messung V0.5
C=94 H=94 G=93

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.