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 TIME_UNITS_H
8 : #define TIME_UNITS_H
9 :
10 : #include "Intervals.h"
11 : #include "mozilla/CheckedInt.h"
12 : #include "mozilla/FloatingPoint.h"
13 : #include "mozilla/Maybe.h"
14 : #include "mozilla/dom/TimeRanges.h"
15 : #include "mozilla/TimeStamp.h"
16 :
17 : namespace mozilla {
18 : namespace media {
19 : class TimeIntervals;
20 : } // namespace media
21 : } // namespace mozilla
22 : // CopyChooser specalization for nsTArray
23 : template<>
24 : struct nsTArray_CopyChooser<mozilla::media::TimeIntervals>
25 : {
26 : typedef nsTArray_CopyWithConstructors<mozilla::media::TimeIntervals> Type;
27 : };
28 :
29 : namespace mozilla {
30 :
31 : // Number of microseconds per second. 1e6.
32 : static const int64_t USECS_PER_S = 1000000;
33 :
34 : // Number of microseconds per millisecond.
35 : static const int64_t USECS_PER_MS = 1000;
36 :
37 : namespace media {
38 :
39 : // Number of nanoseconds per second. 1e9.
40 : static const int64_t NSECS_PER_S = 1000000000;
41 :
42 : // TimeUnit at present uses a CheckedInt64 as storage.
43 : // INT64_MAX has the special meaning of being +oo.
44 : class TimeUnit final {
45 : public:
46 0 : static TimeUnit FromSeconds(double aValue) {
47 0 : MOZ_ASSERT(!IsNaN(aValue));
48 :
49 0 : if (mozilla::IsInfinite<double>(aValue)) {
50 0 : return FromInfinity();
51 : }
52 : // Due to internal double representation, this
53 : // operation is not commutative, do not attempt to simplify.
54 0 : double val = (aValue + .0000005) * USECS_PER_S;
55 0 : if (val >= double(INT64_MAX)) {
56 0 : return FromMicroseconds(INT64_MAX);
57 0 : } else if (val <= double(INT64_MIN)) {
58 0 : return FromMicroseconds(INT64_MIN);
59 : } else {
60 0 : return FromMicroseconds(int64_t(val));
61 : }
62 : }
63 :
64 0 : static constexpr TimeUnit FromMicroseconds(int64_t aValue) {
65 0 : return TimeUnit(aValue);
66 : }
67 :
68 0 : static constexpr TimeUnit FromNanoseconds(int64_t aValue) {
69 0 : return TimeUnit(aValue / 1000);
70 : }
71 :
72 0 : static constexpr TimeUnit FromInfinity() {
73 0 : return TimeUnit(INT64_MAX);
74 : }
75 :
76 0 : static TimeUnit FromTimeDuration(const TimeDuration& aDuration) {
77 0 : return FromSeconds(aDuration.ToSeconds());
78 : }
79 :
80 0 : static constexpr TimeUnit Zero() {
81 0 : return TimeUnit(0);
82 : }
83 :
84 0 : static TimeUnit Invalid() {
85 0 : TimeUnit ret;
86 0 : ret.mValue = CheckedInt64(INT64_MAX);
87 : // Force an overflow to render the CheckedInt invalid.
88 0 : ret.mValue += 1;
89 0 : return ret;
90 : }
91 :
92 0 : int64_t ToMicroseconds() const {
93 0 : return mValue.value();
94 : }
95 :
96 0 : int64_t ToNanoseconds() const {
97 0 : return mValue.value() * 1000;
98 : }
99 :
100 0 : double ToSeconds() const {
101 0 : if (IsInfinite()) {
102 0 : return PositiveInfinity<double>();
103 : }
104 0 : return double(mValue.value()) / USECS_PER_S;
105 : }
106 :
107 0 : TimeDuration ToTimeDuration() const {
108 0 : return TimeDuration::FromMicroseconds(mValue.value());
109 : }
110 :
111 0 : bool IsInfinite() const {
112 0 : return mValue.value() == INT64_MAX;
113 : }
114 :
115 0 : bool IsPositive() const {
116 0 : return mValue.value() > 0;
117 : }
118 :
119 0 : bool IsNegative() const {
120 0 : return mValue.value() < 0;
121 : }
122 :
123 0 : bool operator == (const TimeUnit& aOther) const {
124 0 : MOZ_ASSERT(IsValid() && aOther.IsValid());
125 0 : return mValue.value() == aOther.mValue.value();
126 : }
127 0 : bool operator != (const TimeUnit& aOther) const {
128 0 : MOZ_ASSERT(IsValid() && aOther.IsValid());
129 0 : return mValue.value() != aOther.mValue.value();
130 : }
131 0 : bool operator >= (const TimeUnit& aOther) const {
132 0 : MOZ_ASSERT(IsValid() && aOther.IsValid());
133 0 : return mValue.value() >= aOther.mValue.value();
134 : }
135 0 : bool operator > (const TimeUnit& aOther) const {
136 0 : return !(*this <= aOther);
137 : }
138 0 : bool operator <= (const TimeUnit& aOther) const {
139 0 : MOZ_ASSERT(IsValid() && aOther.IsValid());
140 0 : return mValue.value() <= aOther.mValue.value();
141 : }
142 0 : bool operator < (const TimeUnit& aOther) const {
143 0 : return !(*this >= aOther);
144 : }
145 0 : TimeUnit operator + (const TimeUnit& aOther) const {
146 0 : if (IsInfinite() || aOther.IsInfinite()) {
147 0 : return FromInfinity();
148 : }
149 0 : return TimeUnit(mValue + aOther.mValue);
150 : }
151 0 : TimeUnit operator - (const TimeUnit& aOther) const {
152 0 : if (IsInfinite() && !aOther.IsInfinite()) {
153 0 : return FromInfinity();
154 : }
155 0 : MOZ_ASSERT(!IsInfinite() && !aOther.IsInfinite());
156 0 : return TimeUnit(mValue - aOther.mValue);
157 : }
158 0 : TimeUnit& operator += (const TimeUnit& aOther) {
159 0 : *this = *this + aOther;
160 0 : return *this;
161 : }
162 : TimeUnit& operator -= (const TimeUnit& aOther) {
163 : *this = *this - aOther;
164 : return *this;
165 : }
166 :
167 : template <typename T>
168 0 : TimeUnit operator*(T aVal) const {
169 : // See bug 853398 for the reason to block double multiplier.
170 : // If required, use MultDouble below and with caution.
171 : static_assert(mozilla::IsIntegral<T>::value, "Must be an integral type");
172 0 : return TimeUnit(mValue * aVal);
173 : }
174 0 : TimeUnit MultDouble(double aVal) const {
175 0 : return TimeUnit::FromSeconds(ToSeconds() * aVal);
176 : }
177 0 : friend TimeUnit operator/ (const TimeUnit& aUnit, int aVal) {
178 0 : return TimeUnit(aUnit.mValue / aVal);
179 : }
180 :
181 0 : bool IsValid() const
182 : {
183 0 : return mValue.isValid();
184 : }
185 :
186 5 : constexpr TimeUnit()
187 5 : : mValue(CheckedInt64(0))
188 5 : {}
189 :
190 : TimeUnit(const TimeUnit&) = default;
191 :
192 : TimeUnit& operator = (const TimeUnit&) = default;
193 :
194 : private:
195 0 : explicit constexpr TimeUnit(CheckedInt64 aMicroseconds)
196 0 : : mValue(aMicroseconds)
197 0 : {}
198 :
199 : // Our internal representation is in microseconds.
200 : CheckedInt64 mValue;
201 : };
202 :
203 : typedef Maybe<TimeUnit> NullableTimeUnit;
204 :
205 : typedef Interval<TimeUnit> TimeInterval;
206 :
207 0 : class TimeIntervals : public IntervalSet<TimeUnit>
208 : {
209 : public:
210 : typedef IntervalSet<TimeUnit> BaseType;
211 :
212 : // We can't use inherited constructors yet. So we have to duplicate all the
213 : // constructors found in IntervalSet base class.
214 : // all this could be later replaced with:
215 : // using IntervalSet<TimeUnit>::IntervalSet;
216 :
217 : // MOZ_IMPLICIT as we want to enable initialization in the form:
218 : // TimeIntervals i = ... like we would do with IntervalSet<T> i = ...
219 0 : MOZ_IMPLICIT TimeIntervals(const BaseType& aOther)
220 0 : : BaseType(aOther)
221 0 : {}
222 0 : MOZ_IMPLICIT TimeIntervals(BaseType&& aOther)
223 0 : : BaseType(Move(aOther))
224 0 : {}
225 : explicit TimeIntervals(const BaseType::ElemType& aOther)
226 : : BaseType(aOther)
227 : {}
228 0 : explicit TimeIntervals(BaseType::ElemType&& aOther)
229 0 : : BaseType(Move(aOther))
230 0 : {}
231 :
232 0 : static TimeIntervals Invalid()
233 : {
234 0 : return TimeIntervals(TimeInterval(TimeUnit::FromMicroseconds(INT64_MIN),
235 0 : TimeUnit::FromMicroseconds(INT64_MIN)));
236 : }
237 0 : bool IsInvalid() const
238 : {
239 0 : return Length() == 1 && Start(0).ToMicroseconds() == INT64_MIN &&
240 0 : End(0).ToMicroseconds() == INT64_MIN;
241 : }
242 :
243 0 : TimeIntervals() = default;
244 :
245 : // Make TimeIntervals interchangeable with dom::TimeRanges.
246 0 : explicit TimeIntervals(dom::TimeRanges* aRanges)
247 0 : {
248 0 : for (uint32_t i = 0; i < aRanges->Length(); i++) {
249 0 : ErrorResult rv;
250 : *this +=
251 0 : TimeInterval(TimeUnit::FromSeconds(aRanges->Start(i, rv)),
252 0 : TimeUnit::FromSeconds(aRanges->End(i, rv)));
253 : }
254 0 : }
255 : TimeIntervals& operator = (dom::TimeRanges* aRanges)
256 : {
257 : *this = TimeIntervals(aRanges);
258 : return *this;
259 : }
260 :
261 : static TimeIntervals FromTimeRanges(dom::TimeRanges* aRanges)
262 : {
263 : return TimeIntervals(aRanges);
264 : }
265 :
266 0 : void ToTimeRanges(dom::TimeRanges* aRanges) const
267 : {
268 0 : for (IndexType i = 0; i < Length(); i++) {
269 0 : aRanges->Add(Start(i).ToSeconds(), End(i).ToSeconds());
270 : }
271 0 : }
272 : };
273 :
274 : } // namespace media
275 : } // namespace mozilla
276 :
277 : #endif // TIME_UNITS_H
|