mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1159579: Add Interval and IntervalSet objects. r=mattwoodrow
Along with a TimeIntervals class that reimplement all of dom::TimeRanges features.
This commit is contained in:
parent
a52d273622
commit
40e5cc7845
525
dom/media/Intervals.h
Normal file
525
dom/media/Intervals.h
Normal file
@ -0,0 +1,525 @@
|
||||
/* -*- 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 INTERVALS_H
|
||||
#define INTERVALS_H
|
||||
|
||||
#include <algorithm>
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace 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(Forward<StartArg>(aStart))
|
||||
, mEnd(Forward<EndArg>(aEnd))
|
||||
, mFuzz()
|
||||
{
|
||||
MOZ_ASSERT(aStart <= aEnd);
|
||||
}
|
||||
|
||||
template<typename StartArg, typename EndArg, typename FuzzArg>
|
||||
Interval(StartArg&& aStart, EndArg&& aEnd, FuzzArg&& aFuzz)
|
||||
: mStart(Forward<StartArg>(aStart))
|
||||
, mEnd(Forward<EndArg>(aEnd))
|
||||
, mFuzz(Forward<FuzzArg>(aFuzz))
|
||||
{
|
||||
MOZ_ASSERT(aStart <= aEnd);
|
||||
}
|
||||
|
||||
Interval(const SelfType& aOther)
|
||||
: mStart(aOther.mStart)
|
||||
, mEnd(aOther.mEnd)
|
||||
, mFuzz(aOther.mFuzz)
|
||||
{}
|
||||
|
||||
Interval(SelfType&& aOther)
|
||||
: mStart(Move(aOther.mStart))
|
||||
, mEnd(Move(aOther.mEnd))
|
||||
, mFuzz(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(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);
|
||||
}
|
||||
|
||||
// Basic interval arithmetic operator definition.
|
||||
SelfType operator- (const SelfType& aOther) const
|
||||
{
|
||||
return SelfType(mStart - aOther.mEnd,
|
||||
mEnd - aOther.mStart,
|
||||
mFuzz + aOther.mFuzz);
|
||||
}
|
||||
|
||||
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 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 Intersects(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;
|
||||
}
|
||||
|
||||
SelfType Union(const SelfType& aOther) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
T mStart;
|
||||
T mEnd;
|
||||
T mFuzz;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class IntervalSet
|
||||
{
|
||||
public:
|
||||
typedef IntervalSet<T> SelfType;
|
||||
typedef Interval<T> ElemType;
|
||||
typedef nsAutoTArray<ElemType,4> ContainerType;
|
||||
typedef typename ContainerType::index_type IndexType;
|
||||
|
||||
IntervalSet()
|
||||
{
|
||||
}
|
||||
~IntervalSet()
|
||||
{
|
||||
}
|
||||
|
||||
IntervalSet(const SelfType& aOther)
|
||||
: mIntervals(aOther.mIntervals)
|
||||
{
|
||||
}
|
||||
|
||||
IntervalSet(SelfType&& aOther)
|
||||
: mIntervals(Move(aOther.mIntervals))
|
||||
{
|
||||
}
|
||||
|
||||
explicit IntervalSet(const ElemType& aOther)
|
||||
{
|
||||
mIntervals.AppendElement(aOther);
|
||||
}
|
||||
|
||||
explicit IntervalSet(ElemType&& aOther)
|
||||
{
|
||||
mIntervals.AppendElement(Move(aOther));
|
||||
}
|
||||
|
||||
SelfType& operator= (const SelfType& aOther)
|
||||
{
|
||||
mIntervals = aOther.mIntervals;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& operator= (SelfType&& aOther)
|
||||
{
|
||||
MOZ_ASSERT(&aOther != this, "self-moves are prohibited");
|
||||
this->~IntervalSet();
|
||||
new(this) IntervalSet(Move(aOther));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& operator= (const ElemType& aInterval)
|
||||
{
|
||||
mIntervals.Clear();
|
||||
mIntervals.AppendElement(aInterval);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& operator= (ElemType&& aInterval)
|
||||
{
|
||||
mIntervals.Clear();
|
||||
mIntervals.AppendElement(Move(aInterval));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// + and += operator will append the provided interval or intervalset.
|
||||
// Note that the result is not normalized. Call Normalize() as required.
|
||||
// Alternatively, use Union()
|
||||
|
||||
SelfType& Add(const SelfType& aIntervals)
|
||||
{
|
||||
mIntervals.AppendElements(aIntervals.mIntervals);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& Add(const ElemType& aInterval)
|
||||
{
|
||||
mIntervals.AppendElement(aInterval);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Mutate this IntervalSet to be the union of this and aOther.
|
||||
// Resulting IntervalSet is normalized.
|
||||
SelfType& Union(const SelfType& aOther)
|
||||
{
|
||||
Add(aOther);
|
||||
Normalize();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& Union(const ElemType& aInterval)
|
||||
{
|
||||
Add(aInterval);
|
||||
Normalize();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Mutate this TimeRange to be the intersection of this and aOther.
|
||||
SelfType& Intersection(const SelfType& aOther)
|
||||
{
|
||||
ContainerType intersection;
|
||||
|
||||
const ContainerType& other = aOther.mIntervals;
|
||||
IndexType i = 0, j = 0;
|
||||
for (; i < mIntervals.Length() && j < other.Length();) {
|
||||
if (mIntervals[i].Intersects(other[j])) {
|
||||
intersection.AppendElement(mIntervals[i].Intersection(other[j]));
|
||||
}
|
||||
if (mIntervals[i].mEnd < other[j].mEnd) {
|
||||
i++;
|
||||
} else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
mIntervals = 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();
|
||||
}
|
||||
|
||||
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 T& aX) {
|
||||
for (const auto& interval : mIntervals) {
|
||||
if (interval.Contains(aX)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContainsStrict(const T& aX) {
|
||||
for (const auto& interval : mIntervals) {
|
||||
if (interval.ContainsStrict(aX)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
if (mIntervals.Length() >= 2) {
|
||||
ContainerType normalized;
|
||||
|
||||
mIntervals.Sort(CompareIntervals());
|
||||
|
||||
// This merges the intervals.
|
||||
ElemType current(mIntervals[0]);
|
||||
for (IndexType i = 1; i < mIntervals.Length(); i++) {
|
||||
if (current.Contains(mIntervals[i])) {
|
||||
continue;
|
||||
}
|
||||
if (current.Intersects(mIntervals[i])) {
|
||||
current = current.Union(mIntervals[i]);
|
||||
} else {
|
||||
normalized.AppendElement(current);
|
||||
current = mIntervals[i];
|
||||
}
|
||||
}
|
||||
|
||||
normalized.AppendElement(current);
|
||||
|
||||
mIntervals = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
// Shift all values by aOffset.
|
||||
void Shift(T aOffset)
|
||||
{
|
||||
for (auto& interval : mIntervals) {
|
||||
interval.mStart += aOffset;
|
||||
interval.mEnd += aOffset;
|
||||
}
|
||||
}
|
||||
|
||||
static const IndexType NoIndex = IndexType(-1);
|
||||
|
||||
IndexType Find(T aValue) const
|
||||
{
|
||||
for (IndexType i = 0; i < mIntervals.Length(); i++) {
|
||||
if (mIntervals[i].Contains(aValue)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return NoIndex;
|
||||
}
|
||||
|
||||
protected:
|
||||
ContainerType mIntervals;
|
||||
|
||||
private:
|
||||
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 - aT1.mFuzz < aT2.mStart + aT2.mFuzz;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 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 media
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // INTERVALS_H
|
@ -7,9 +7,11 @@
|
||||
#ifndef TIME_UNITS_H
|
||||
#define TIME_UNITS_H
|
||||
|
||||
#include "Intervals.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
@ -40,6 +42,9 @@ struct Microseconds {
|
||||
}
|
||||
}
|
||||
|
||||
bool operator == (const Microseconds& aOther) const {
|
||||
return mValue == aOther.mValue;
|
||||
}
|
||||
bool operator > (const Microseconds& aOther) const {
|
||||
return mValue > aOther.mValue;
|
||||
}
|
||||
@ -87,6 +92,10 @@ public:
|
||||
return double(mValue.value()) / USECS_PER_S;
|
||||
}
|
||||
|
||||
bool operator == (const TimeUnit& aOther) const {
|
||||
MOZ_ASSERT(IsValid() && aOther.IsValid());
|
||||
return mValue.value() == aOther.mValue.value();
|
||||
}
|
||||
bool operator >= (const TimeUnit& aOther) const {
|
||||
MOZ_ASSERT(IsValid() && aOther.IsValid());
|
||||
return mValue.value() >= aOther.mValue.value();
|
||||
@ -113,9 +122,18 @@ public:
|
||||
return mValue.isValid();
|
||||
}
|
||||
|
||||
TimeUnit()
|
||||
: mValue(CheckedInt64(0))
|
||||
{}
|
||||
|
||||
explicit TimeUnit(const Microseconds& aMicroseconds)
|
||||
: mValue(aMicroseconds.mValue)
|
||||
{}
|
||||
TimeUnit& operator = (const Microseconds& aMicroseconds)
|
||||
{
|
||||
mValue = aMicroseconds.mValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TimeUnit(const TimeUnit&) = default;
|
||||
|
||||
@ -130,6 +148,64 @@ private:
|
||||
CheckedInt64 mValue;
|
||||
};
|
||||
|
||||
typedef Interval<TimeUnit> TimeInterval;
|
||||
|
||||
class TimeIntervals : public IntervalSet<TimeUnit>
|
||||
{
|
||||
public:
|
||||
typedef IntervalSet<TimeUnit> BaseType;
|
||||
|
||||
// We can't use inherited constructors yet. So we have to duplicate all the
|
||||
// constructors found in IntervalSet base class.
|
||||
// all this could be later replaced with:
|
||||
// using IntervalSet<TimeUnit>::IntervalSet;
|
||||
|
||||
// MOZ_IMPLICIT as we want to enable initialization in the form:
|
||||
// TimeIntervals i = ... like we would do with IntervalSet<T> i = ...
|
||||
MOZ_IMPLICIT TimeIntervals(const BaseType& aOther)
|
||||
: BaseType(aOther)
|
||||
{}
|
||||
MOZ_IMPLICIT TimeIntervals(BaseType&& aOther)
|
||||
: BaseType(Move(aOther))
|
||||
{}
|
||||
explicit TimeIntervals(const BaseType::ElemType& aOther)
|
||||
: BaseType(aOther)
|
||||
{}
|
||||
explicit TimeIntervals(BaseType::ElemType&& aOther)
|
||||
: BaseType(Move(aOther))
|
||||
{}
|
||||
|
||||
TimeIntervals() = default;
|
||||
|
||||
// Make TimeIntervals interchangeable with dom::TimeRanges.
|
||||
explicit TimeIntervals(dom::TimeRanges* aRanges)
|
||||
{
|
||||
for (uint32_t i = 0; i < aRanges->Length(); i++) {
|
||||
ErrorResult rv;
|
||||
*this +=
|
||||
TimeInterval(TimeUnit::FromSeconds(aRanges->Start(i, rv)),
|
||||
TimeUnit::FromSeconds(aRanges->End(i, rv)));
|
||||
}
|
||||
}
|
||||
TimeIntervals& operator = (dom::TimeRanges* aRanges)
|
||||
{
|
||||
*this = TimeIntervals(aRanges);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static TimeIntervals FromTimeRanges(dom::TimeRanges* aRanges)
|
||||
{
|
||||
return TimeIntervals(aRanges);
|
||||
}
|
||||
|
||||
void ToTimeRanges(dom::TimeRanges* aRanges) const
|
||||
{
|
||||
for (IndexType i = 0; i < Length(); i++) {
|
||||
aRanges->Add(Start(i).ToSeconds(), End(i).ToSeconds());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace mozilla
|
||||
|
||||
|
591
dom/media/gtest/TestIntervalSet.cpp
Normal file
591
dom/media/gtest/TestIntervalSet.cpp
Normal file
@ -0,0 +1,591 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "TimeUnits.h"
|
||||
#include "Intervals.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
typedef media::Interval<uint8_t> ByteInterval;
|
||||
typedef media::Interval<int> IntInterval;
|
||||
|
||||
ByteInterval CreateByteInterval(int32_t aStart, int32_t aEnd)
|
||||
{
|
||||
ByteInterval test(aStart, aEnd);
|
||||
return test;
|
||||
}
|
||||
|
||||
media::IntervalSet<uint8_t> CreateByteIntervalSet(int32_t aStart, int32_t aEnd)
|
||||
{
|
||||
media::IntervalSet<uint8_t> test;
|
||||
test += ByteInterval(aStart, aEnd);
|
||||
return test;
|
||||
}
|
||||
|
||||
TEST(IntervalSet, Constructors)
|
||||
{
|
||||
const int32_t start = 1;
|
||||
const int32_t end = 2;
|
||||
const int32_t fuzz = 0;
|
||||
|
||||
// Compiler exercise.
|
||||
ByteInterval test1(start, end);
|
||||
ByteInterval test2(test1);
|
||||
ByteInterval test3(start, end, fuzz);
|
||||
ByteInterval test4(test3);
|
||||
ByteInterval test5 = CreateByteInterval(start, end);
|
||||
|
||||
media::IntervalSet<uint8_t> blah1(test1);
|
||||
media::IntervalSet<uint8_t> blah2 = blah1;
|
||||
media::IntervalSet<uint8_t> blah3 = blah1 + test1;
|
||||
media::IntervalSet<uint8_t> blah4 = test1 + blah1;
|
||||
media::IntervalSet<uint8_t> blah5 = CreateByteIntervalSet(start, end);
|
||||
(void)test1; (void)test2; (void)test3; (void)test4; (void)test5;
|
||||
(void)blah1; (void)blah2; (void)blah3; (void)blah4; (void)blah5;
|
||||
}
|
||||
|
||||
media::TimeInterval CreateTimeInterval(int32_t aStart, int32_t aEnd)
|
||||
{
|
||||
// Copy constructor test
|
||||
media::Microseconds startus(aStart);
|
||||
media::TimeUnit start(startus);
|
||||
media::TimeUnit end;
|
||||
// operator= test
|
||||
end = media::Microseconds(aEnd);
|
||||
media::TimeInterval ti(start, end);
|
||||
return ti;
|
||||
}
|
||||
|
||||
media::TimeIntervals CreateTimeIntervals(int32_t aStart, int32_t aEnd)
|
||||
{
|
||||
media::TimeIntervals test;
|
||||
test += CreateTimeInterval(aStart, aEnd);
|
||||
return test;
|
||||
}
|
||||
|
||||
TEST(IntervalSet, TimeIntervalsConstructors)
|
||||
{
|
||||
const media::Microseconds start(1);
|
||||
const media::Microseconds end(2);
|
||||
const media::Microseconds fuzz;
|
||||
|
||||
// Compiler exercise.
|
||||
media::TimeInterval test1(start, end);
|
||||
media::TimeInterval test2(test1);
|
||||
media::TimeInterval test3(start, end, fuzz);
|
||||
media::TimeInterval test4(test3);
|
||||
media::TimeInterval test5 = CreateTimeInterval(start.mValue, end.mValue);
|
||||
|
||||
media::TimeIntervals blah1(test1);
|
||||
media::TimeIntervals blah2(blah1);
|
||||
media::TimeIntervals blah3 = blah1 + test1;
|
||||
media::TimeIntervals blah4 = test1 + blah1;
|
||||
media::TimeIntervals blah5 = CreateTimeIntervals(start.mValue, end.mValue);
|
||||
(void)test1; (void)test2; (void)test3; (void)test4; (void)test5;
|
||||
(void)blah1; (void)blah2; (void)blah3; (void)blah4; (void)blah5;
|
||||
}
|
||||
|
||||
TEST(IntervalSet, Length)
|
||||
{
|
||||
IntInterval i(15, 25);
|
||||
EXPECT_EQ(10, i.Length());
|
||||
}
|
||||
|
||||
TEST(IntervalSet, Intersection)
|
||||
{
|
||||
IntInterval i0(10, 20);
|
||||
IntInterval i1(15, 25);
|
||||
IntInterval i = i0.Intersection(i1);
|
||||
EXPECT_EQ(15, i.mStart);
|
||||
EXPECT_EQ(20, i.mEnd);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, Equals)
|
||||
{
|
||||
IntInterval i0(10, 20);
|
||||
IntInterval i1(10, 20);
|
||||
EXPECT_EQ(i0, i1);
|
||||
|
||||
IntInterval i2(5, 20);
|
||||
EXPECT_NE(i0, i2);
|
||||
|
||||
IntInterval i3(10, 15);
|
||||
EXPECT_NE(i0, i2);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, IntersectionIntervalSet)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(5, 10);
|
||||
i0 += IntInterval(20, 25);
|
||||
i0 += IntInterval(40, 60);
|
||||
|
||||
media::IntervalSet<int> i1;
|
||||
i1.Add(IntInterval(7, 15));
|
||||
i1.Add(IntInterval(16, 27));
|
||||
i1.Add(IntInterval(45, 50));
|
||||
i1.Add(IntInterval(53, 57));
|
||||
|
||||
media::IntervalSet<int> i = media::Intersection(i0, i1);
|
||||
|
||||
EXPECT_EQ(4u, i.Length());
|
||||
|
||||
EXPECT_EQ(7, i[0].mStart);
|
||||
EXPECT_EQ(10, i[0].mEnd);
|
||||
|
||||
EXPECT_EQ(20, i[1].mStart);
|
||||
EXPECT_EQ(25, i[1].mEnd);
|
||||
|
||||
EXPECT_EQ(45, i[2].mStart);
|
||||
EXPECT_EQ(50, i[2].mEnd);
|
||||
|
||||
EXPECT_EQ(53, i[3].mStart);
|
||||
EXPECT_EQ(57, i[3].mEnd);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void Compare(media::IntervalSet<T> aI1, media::IntervalSet<T> aI2)
|
||||
{
|
||||
media::IntervalSet<T> i1(aI1);
|
||||
media::IntervalSet<T> i2(aI1);
|
||||
EXPECT_EQ(i1.Length(), i2.Length());
|
||||
if (i1.Length() != i2.Length()) {
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < i1.Length(); i++) {
|
||||
EXPECT_EQ(i1[i].mStart, i2[i].mStart);
|
||||
EXPECT_EQ(i1[i].mEnd, i2[i].mEnd);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntervalSet, IntersectionNormalizedIntervalSet)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(5, 10);
|
||||
i0 += IntInterval(8, 25);
|
||||
i0 += IntInterval(24, 60);
|
||||
|
||||
media::IntervalSet<int> i1;
|
||||
i1.Add(IntInterval(7, 15));
|
||||
i1.Add(IntInterval(10, 27));
|
||||
i1.Add(IntInterval(45, 50));
|
||||
i1.Add(IntInterval(53, 57));
|
||||
|
||||
// Compare intersections to ensure an intersection of normalized intervalsets
|
||||
// is equal to the intersection of non-normalized intervalsets.
|
||||
media::IntervalSet<int> intersection = media::Intersection(i0, i1);
|
||||
|
||||
media::IntervalSet<int> i0_normalize(i0);
|
||||
i0_normalize.Normalize();
|
||||
media::IntervalSet<int> i1_normalize(i1);
|
||||
i1_normalize.Normalize();
|
||||
media::IntervalSet<int> intersection_normalize =
|
||||
media::Intersection(i0_normalize, i1_normalize);
|
||||
Compare(intersection, intersection_normalize);
|
||||
}
|
||||
|
||||
static void GeneratePermutations(media::IntervalSet<int> aI1,
|
||||
media::IntervalSet<int> aI2)
|
||||
{
|
||||
media::IntervalSet<int> i_ref = media::Intersection(aI1, aI2);
|
||||
// Test all permutations possible
|
||||
std::vector<uint32_t> comb1;
|
||||
for (uint32_t i = 0; i < aI1.Length(); i++) {
|
||||
comb1.push_back(i);
|
||||
}
|
||||
std::vector<uint32_t> comb2;
|
||||
for (uint32_t i = 0; i < aI2.Length(); i++) {
|
||||
comb2.push_back(i);
|
||||
}
|
||||
|
||||
do {
|
||||
do {
|
||||
// Create intervals according to new indexes.
|
||||
media::IntervalSet<int> i_0;
|
||||
for (uint32_t i = 0; i < comb1.size(); i++) {
|
||||
i_0 += aI1[comb1[i]];
|
||||
}
|
||||
media::IntervalSet<int> i_1;
|
||||
for (uint32_t i = 0; i < comb2.size(); i++) {
|
||||
i_1 += aI2[comb2[i]];
|
||||
}
|
||||
// Check intersections yield the same result.
|
||||
Compare(i_0.Intersection(i_1), i_ref);
|
||||
} while (std::next_permutation(comb2.begin(), comb2.end()));
|
||||
} while (std::next_permutation(comb1.begin(), comb1.end()));
|
||||
}
|
||||
|
||||
TEST(IntervalSet, IntersectionUnorderedIntervalSet)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(5, 10);
|
||||
i0 += IntInterval(20, 25);
|
||||
i0 += IntInterval(40, 60);
|
||||
|
||||
media::IntervalSet<int> i1;
|
||||
i1.Add(IntInterval(7, 15));
|
||||
i1.Add(IntInterval(16, 27));
|
||||
i1.Add(IntInterval(45, 50));
|
||||
i1.Add(IntInterval(53, 57));
|
||||
|
||||
GeneratePermutations(i0, i1);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, IntersectionUnorderedNonNormalizedIntervalSet)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(5, 10);
|
||||
i0 += IntInterval(8, 25);
|
||||
i0 += IntInterval(24, 60);
|
||||
|
||||
media::IntervalSet<int> i1;
|
||||
i1.Add(IntInterval(7, 15));
|
||||
i1.Add(IntInterval(10, 27));
|
||||
i1.Add(IntInterval(45, 50));
|
||||
i1.Add(IntInterval(53, 57));
|
||||
|
||||
GeneratePermutations(i0, i1);
|
||||
}
|
||||
|
||||
static media::IntervalSet<int> Duplicate(const media::IntervalSet<int>& aValue)
|
||||
{
|
||||
media::IntervalSet<int> value(aValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
TEST(IntervalSet, Normalize)
|
||||
{
|
||||
media::IntervalSet<int> i;
|
||||
// Test IntervalSet<T> + Interval<T> operator.
|
||||
i = i + IntInterval(20, 30);
|
||||
// Test Internal<T> + IntervalSet<T> operator.
|
||||
i = IntInterval(2, 7) + i;
|
||||
// Test Interval<T> + IntervalSet<T> operator
|
||||
i = IntInterval(1, 8) + i;
|
||||
media::IntervalSet<int> interval;
|
||||
interval += IntInterval(5, 10);
|
||||
// Test += with move.
|
||||
i += Duplicate(interval);
|
||||
// Test = with move and add with move.
|
||||
i = Duplicate(interval) + i;
|
||||
|
||||
media::IntervalSet<int> o(i);
|
||||
o.Normalize();
|
||||
|
||||
EXPECT_EQ(2u, o.Length());
|
||||
|
||||
EXPECT_EQ(1, o[0].mStart);
|
||||
EXPECT_EQ(10, o[0].mEnd);
|
||||
|
||||
EXPECT_EQ(20, o[1].mStart);
|
||||
EXPECT_EQ(30, o[1].mEnd);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, Union)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(5, 10);
|
||||
i0 += IntInterval(20, 25);
|
||||
i0 += IntInterval(40, 60);
|
||||
|
||||
media::IntervalSet<int> i1;
|
||||
i1.Add(IntInterval(7, 15));
|
||||
i1.Add(IntInterval(16, 27));
|
||||
i1.Add(IntInterval(45, 50));
|
||||
i1.Add(IntInterval(53, 57));
|
||||
|
||||
media::IntervalSet<int> i = media::Union(i0, i1);
|
||||
|
||||
EXPECT_EQ(3u, i.Length());
|
||||
|
||||
EXPECT_EQ(5, i[0].mStart);
|
||||
EXPECT_EQ(15, i[0].mEnd);
|
||||
|
||||
EXPECT_EQ(16, i[1].mStart);
|
||||
EXPECT_EQ(27, i[1].mEnd);
|
||||
|
||||
EXPECT_EQ(40, i[2].mStart);
|
||||
EXPECT_EQ(60, i[2].mEnd);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, UnionNotOrdered)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(20, 25);
|
||||
i0 += IntInterval(40, 60);
|
||||
i0 += IntInterval(5, 10);
|
||||
|
||||
media::IntervalSet<int> i1;
|
||||
i1.Add(IntInterval(16, 27));
|
||||
i1.Add(IntInterval(7, 15));
|
||||
i1.Add(IntInterval(53, 57));
|
||||
i1.Add(IntInterval(45, 50));
|
||||
|
||||
media::IntervalSet<int> i = media::Union(i0, i1);
|
||||
|
||||
EXPECT_EQ(3u, i.Length());
|
||||
|
||||
EXPECT_EQ(5, i[0].mStart);
|
||||
EXPECT_EQ(15, i[0].mEnd);
|
||||
|
||||
EXPECT_EQ(16, i[1].mStart);
|
||||
EXPECT_EQ(27, i[1].mEnd);
|
||||
|
||||
EXPECT_EQ(40, i[2].mStart);
|
||||
EXPECT_EQ(60, i[2].mEnd);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, NormalizeFuzz)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(11, 25, 0);
|
||||
i0 += IntInterval(5, 10, 1);
|
||||
i0 += IntInterval(40, 60, 1);
|
||||
i0.Normalize();
|
||||
|
||||
EXPECT_EQ(2u, i0.Length());
|
||||
|
||||
EXPECT_EQ(5, i0[0].mStart);
|
||||
EXPECT_EQ(25, i0[0].mEnd);
|
||||
|
||||
EXPECT_EQ(40, i0[1].mStart);
|
||||
EXPECT_EQ(60, i0[1].mEnd);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, UnionFuzz)
|
||||
{
|
||||
media::IntervalSet<int> i0;
|
||||
i0 += IntInterval(5, 10, 1);
|
||||
i0 += IntInterval(11, 25, 0);
|
||||
i0 += IntInterval(40, 60, 1);
|
||||
|
||||
media::IntervalSet<int> i1;
|
||||
i1.Add(IntInterval(7, 15, 1));
|
||||
i1.Add(IntInterval(16, 27, 1));
|
||||
i1.Add(IntInterval(45, 50, 1));
|
||||
i1.Add(IntInterval(53, 57, 1));
|
||||
|
||||
media::IntervalSet<int> i = media::Union(i0, i1);
|
||||
|
||||
EXPECT_EQ(2u, i.Length());
|
||||
|
||||
EXPECT_EQ(5, i[0].mStart);
|
||||
EXPECT_EQ(27, i[0].mEnd);
|
||||
|
||||
EXPECT_EQ(40, i[1].mStart);
|
||||
EXPECT_EQ(60, i[1].mEnd);
|
||||
|
||||
i0.Normalize();
|
||||
EXPECT_EQ(2u, i0.Length());
|
||||
EXPECT_EQ(5, i0[0].mStart);
|
||||
EXPECT_EQ(25, i0[0].mEnd);
|
||||
EXPECT_EQ(40, i0[1].mStart);
|
||||
EXPECT_EQ(60, i0[1].mEnd);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, Contiguous)
|
||||
{
|
||||
EXPECT_FALSE(IntInterval(5, 10).Contiguous(IntInterval(11, 25)));
|
||||
EXPECT_TRUE(IntInterval(5, 10).Contiguous(IntInterval(10, 25)));
|
||||
EXPECT_TRUE(IntInterval(5, 10, 1).Contiguous(IntInterval(11, 25)));
|
||||
EXPECT_TRUE(IntInterval(5, 10).Contiguous(IntInterval(11, 25, 1)));
|
||||
}
|
||||
|
||||
TEST(IntervalSet, TimeRangesSeconds)
|
||||
{
|
||||
media::TimeIntervals i0;
|
||||
i0 += media::TimeInterval(media::TimeUnit::FromSeconds(20), media::TimeUnit::FromSeconds(25));
|
||||
i0 += media::TimeInterval(media::TimeUnit::FromSeconds(40), media::TimeUnit::FromSeconds(60));
|
||||
i0 += media::TimeInterval(media::TimeUnit::FromSeconds(5), media::TimeUnit::FromSeconds(10));
|
||||
|
||||
media::TimeIntervals i1;
|
||||
i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(16), media::TimeUnit::FromSeconds(27)));
|
||||
i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(7), media::TimeUnit::FromSeconds(15)));
|
||||
i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(53), media::TimeUnit::FromSeconds(57)));
|
||||
i1.Add(media::TimeInterval(media::TimeUnit::FromSeconds(45), media::TimeUnit::FromSeconds(50)));
|
||||
|
||||
media::TimeIntervals i(i0 + i1);
|
||||
nsRefPtr<dom::TimeRanges> tr = new dom::TimeRanges();
|
||||
i.ToTimeRanges(tr);
|
||||
EXPECT_EQ(tr->Length(), i.Length());
|
||||
for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
|
||||
ErrorResult rv;
|
||||
EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
|
||||
EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
|
||||
}
|
||||
|
||||
i.Normalize();
|
||||
tr->Normalize();
|
||||
EXPECT_EQ(tr->Length(), i.Length());
|
||||
for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
|
||||
ErrorResult rv;
|
||||
EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
|
||||
EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckTimeRanges(dom::TimeRanges* aTr, const media::TimeIntervals& aTi)
|
||||
{
|
||||
EXPECT_EQ(aTr->Length(), aTi.Length());
|
||||
for (dom::TimeRanges::index_type i = 0; i < aTr->Length(); i++) {
|
||||
ErrorResult rv;
|
||||
EXPECT_EQ(aTr->Start(i, rv), aTi[i].mStart.ToSeconds());
|
||||
EXPECT_EQ(aTr->Start(i, rv), aTi.Start(i).ToSeconds());
|
||||
EXPECT_EQ(aTr->End(i, rv), aTi[i].mEnd.ToSeconds());
|
||||
EXPECT_EQ(aTr->End(i, rv), aTi.End(i).ToSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IntervalSet, TimeRangesConversion)
|
||||
{
|
||||
nsRefPtr<dom::TimeRanges> tr = new dom::TimeRanges();
|
||||
tr->Add(20, 25);
|
||||
tr->Add(40, 60);
|
||||
tr->Add(5, 10);
|
||||
tr->Add(16, 27);
|
||||
tr->Add(53, 57);
|
||||
tr->Add(45, 50);
|
||||
|
||||
// explicit copy constructor
|
||||
media::TimeIntervals i1(tr);
|
||||
CheckTimeRanges(tr, i1);
|
||||
|
||||
// static FromTimeRanges
|
||||
media::TimeIntervals i2 = media::TimeIntervals::FromTimeRanges(tr);
|
||||
CheckTimeRanges(tr, i2);
|
||||
|
||||
media::TimeIntervals i3;
|
||||
// operator=(TimeRanges*)
|
||||
i3 = tr;
|
||||
CheckTimeRanges(tr, i3);
|
||||
|
||||
i1.Normalize();
|
||||
tr->Normalize();
|
||||
|
||||
CheckTimeRanges(tr, i1);
|
||||
|
||||
// operator= test
|
||||
i1 = tr.get();
|
||||
CheckTimeRanges(tr, i1);
|
||||
}
|
||||
|
||||
TEST(IntervalSet, TimeRangesMicroseconds)
|
||||
{
|
||||
media::TimeIntervals i0;
|
||||
|
||||
// Test media::Microseconds and TimeUnit interchangeability (compilation only)
|
||||
media::TimeUnit time1{media::Microseconds(5)};
|
||||
media::Microseconds microseconds(5);
|
||||
media::TimeUnit time2 = media::TimeUnit(microseconds);
|
||||
EXPECT_EQ(time1, time2);
|
||||
|
||||
i0 += media::TimeInterval(media::Microseconds(20), media::Microseconds(25));
|
||||
i0 += media::TimeInterval(media::Microseconds(40), media::Microseconds(60));
|
||||
i0 += media::TimeInterval(media::Microseconds(5), media::Microseconds(10));
|
||||
|
||||
media::TimeIntervals i1;
|
||||
i1.Add(media::TimeInterval(media::Microseconds(16), media::Microseconds(27)));
|
||||
i1.Add(media::TimeInterval(media::Microseconds(7), media::Microseconds(15)));
|
||||
i1.Add(media::TimeInterval(media::Microseconds(53), media::Microseconds(57)));
|
||||
i1.Add(media::TimeInterval(media::Microseconds(45), media::Microseconds(50)));
|
||||
|
||||
media::TimeIntervals i(i0 + i1);
|
||||
nsRefPtr<dom::TimeRanges> tr = new dom::TimeRanges();
|
||||
i.ToTimeRanges(tr);
|
||||
EXPECT_EQ(tr->Length(), i.Length());
|
||||
for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
|
||||
ErrorResult rv;
|
||||
EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
|
||||
EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
|
||||
}
|
||||
|
||||
i.Normalize();
|
||||
tr->Normalize();
|
||||
EXPECT_EQ(tr->Length(), i.Length());
|
||||
for (dom::TimeRanges::index_type index = 0; index < tr->Length(); index++) {
|
||||
ErrorResult rv;
|
||||
EXPECT_EQ(tr->Start(index, rv), i[index].mStart.ToSeconds());
|
||||
EXPECT_EQ(tr->Start(index, rv), i.Start(index).ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i[index].mEnd.ToSeconds());
|
||||
EXPECT_EQ(tr->End(index, rv), i.End(index).ToSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class Foo
|
||||
{
|
||||
public:
|
||||
Foo()
|
||||
: mArg1(1)
|
||||
, mArg2(2)
|
||||
, mArg3(3)
|
||||
{}
|
||||
|
||||
Foo(T a1, T a2, T a3)
|
||||
: mArg1(a1)
|
||||
, mArg2(a2)
|
||||
, mArg3(a3)
|
||||
{}
|
||||
|
||||
Foo<T> operator+ (const Foo<T>& aOther) const
|
||||
{
|
||||
Foo<T> blah;
|
||||
blah.mArg1 += aOther.mArg1;
|
||||
blah.mArg2 += aOther.mArg2;
|
||||
blah.mArg3 += aOther.mArg3;
|
||||
return blah;
|
||||
}
|
||||
Foo<T> operator- (const Foo<T>& aOther) const
|
||||
{
|
||||
Foo<T> blah;
|
||||
blah.mArg1 -= aOther.mArg1;
|
||||
blah.mArg2 -= aOther.mArg2;
|
||||
blah.mArg3 -= aOther.mArg3;
|
||||
return blah;
|
||||
}
|
||||
bool operator< (const Foo<T>& aOther) const
|
||||
{
|
||||
return mArg1 < aOther.mArg1;
|
||||
}
|
||||
bool operator== (const Foo<T>& aOther) const
|
||||
{
|
||||
return mArg1 == aOther.mArg1;
|
||||
}
|
||||
bool operator<= (const Foo<T>& aOther) const
|
||||
{
|
||||
return mArg1 <= aOther.mArg1;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t mArg1;
|
||||
int32_t mArg2;
|
||||
int32_t mArg3;
|
||||
};
|
||||
|
||||
TEST(IntervalSet, FooIntervalSet)
|
||||
{
|
||||
media::Interval<Foo<int>> i(Foo<int>(), Foo<int>(4,5,6));
|
||||
media::IntervalSet<Foo<int>> is;
|
||||
is += i;
|
||||
is += i;
|
||||
is.Add(i);
|
||||
is = is + i;
|
||||
is = i + is;
|
||||
EXPECT_EQ(5u, is.Length());
|
||||
is.Normalize();
|
||||
EXPECT_EQ(1u, is.Length());
|
||||
EXPECT_EQ(Foo<int>(), is[0].mStart);
|
||||
EXPECT_EQ(Foo<int>(4,5,6), is[0].mEnd);
|
||||
}
|
@ -9,6 +9,7 @@ UNIFIED_SOURCES += [
|
||||
'TestAudioCompactor.cpp',
|
||||
'TestGMPCrossOrigin.cpp',
|
||||
'TestGMPRemoveAndDelete.cpp',
|
||||
'TestIntervalSet.cpp',
|
||||
'TestMP4Demuxer.cpp',
|
||||
'TestMP4Reader.cpp',
|
||||
'TestTrackEncoder.cpp',
|
||||
|
@ -113,6 +113,7 @@ EXPORTS += [
|
||||
'EncodedBufferCache.h',
|
||||
'FileBlockCache.h',
|
||||
'GraphDriver.h',
|
||||
'Intervals.h',
|
||||
'Latency.h',
|
||||
'MediaCache.h',
|
||||
'MediaData.h',
|
||||
|
Loading…
Reference in New Issue
Block a user