[WTF] Add a multiplication operator (and a few others) to MediaTime
[WebKit-https.git] / Source / WTF / wtf / MediaTime.cpp
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "MediaTime.h"
31
32 #include <algorithm>
33 #include <wtf/CheckedArithmetic.h>
34 #include <wtf/MathExtras.h>
35
36 using namespace std;
37
38 namespace WTF {
39
40 static int32_t greatestCommonDivisor(int32_t a, int32_t b)
41 {
42     // Euclid's Algorithm
43     int32_t temp = 0;
44     while (b) {
45         temp = b;
46         b = a % b;
47         a = temp;
48     }
49     return a;
50 }
51
52 static int32_t leastCommonMultiple(int32_t a, int32_t b, int32_t &result)
53 {
54     return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
55 }
56
57 static int32_t signum(int64_t val)
58 {
59     return (0 < val) - (val < 0);
60 }
61
62 const int32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
63
64 MediaTime::MediaTime()
65     : m_timeValue(0)
66     , m_timeScale(DefaultTimeScale)
67     , m_timeFlags(Valid)
68 {
69 }
70
71 MediaTime::MediaTime(int64_t value, int32_t scale, uint32_t flags)
72     : m_timeValue(value)
73     , m_timeScale(scale)
74     , m_timeFlags(flags)
75 {
76 }
77
78 MediaTime::~MediaTime()
79 {
80 }
81
82 MediaTime::MediaTime(const MediaTime& rhs)
83 {
84     *this = rhs;
85 }
86
87 MediaTime MediaTime::createWithFloat(float floatTime, int32_t timeScale)
88 {
89     if (floatTime != floatTime)
90         return invalidTime();
91     if (std::isinf(floatTime))
92         return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
93     if (floatTime > numeric_limits<int64_t>::max())
94         return positiveInfiniteTime();
95     if (floatTime < numeric_limits<int64_t>::min())
96         return negativeInfiniteTime();
97
98     while (floatTime * timeScale > numeric_limits<int64_t>::max())
99         timeScale /= 2;
100     return MediaTime(static_cast<int64_t>(floatTime * timeScale), timeScale, Valid);
101 }
102
103 MediaTime MediaTime::createWithDouble(double doubleTime, int32_t timeScale)
104 {
105     if (doubleTime != doubleTime)
106         return invalidTime();
107     if (std::isinf(doubleTime))
108         return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
109     if (doubleTime > numeric_limits<int64_t>::max())
110         return positiveInfiniteTime();
111     if (doubleTime < numeric_limits<int64_t>::min())
112         return negativeInfiniteTime();
113
114     while (doubleTime * timeScale > numeric_limits<int64_t>::max())
115         timeScale /= 2;
116     return MediaTime(static_cast<int64_t>(doubleTime * timeScale), timeScale, Valid);
117 }
118
119 float MediaTime::toFloat() const
120 {
121     if (isInvalid() || isIndefinite())
122         return std::numeric_limits<float>::quiet_NaN();
123     if (isPositiveInfinite())
124         return std::numeric_limits<float>::infinity();
125     if (isNegativeInfinite())
126         return -std::numeric_limits<float>::infinity();
127     return static_cast<float>(m_timeValue) / m_timeScale;
128 }
129
130 double MediaTime::toDouble() const
131 {
132     if (isInvalid() || isIndefinite())
133         return std::numeric_limits<double>::quiet_NaN();
134     if (isPositiveInfinite())
135         return std::numeric_limits<double>::infinity();
136     if (isNegativeInfinite())
137         return -std::numeric_limits<double>::infinity();
138     return static_cast<double>(m_timeValue) / m_timeScale;
139 }
140
141 MediaTime& MediaTime::operator=(const MediaTime& rhs)
142 {
143     m_timeValue = rhs.m_timeValue;
144     m_timeScale = rhs.m_timeScale;
145     m_timeFlags = rhs.m_timeFlags;
146     return *this;
147 }
148
149 MediaTime MediaTime::operator+(const MediaTime& rhs) const
150 {
151     if (rhs.isInvalid() || isInvalid())
152         return invalidTime();
153
154     if (rhs.isIndefinite() || isIndefinite())
155         return indefiniteTime();
156
157     if (isPositiveInfinite()) {
158         if (rhs.isNegativeInfinite())
159             return invalidTime();
160         return positiveInfiniteTime();
161     }
162
163     if (isNegativeInfinite()) {
164         if (rhs.isPositiveInfinite())
165             return invalidTime();
166         return negativeInfiniteTime();
167     }
168
169     int32_t commonTimeScale;
170     if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
171         commonTimeScale = MaximumTimeScale;
172     MediaTime a = *this;
173     MediaTime b = rhs;
174     a.setTimeScale(commonTimeScale);
175     b.setTimeScale(commonTimeScale);
176     while (!safeAdd(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
177         if (commonTimeScale == 1)
178             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
179         commonTimeScale /= 2;
180         a.setTimeScale(commonTimeScale);
181         b.setTimeScale(commonTimeScale);
182     }
183     return a;
184 }
185
186 MediaTime MediaTime::operator-(const MediaTime& rhs) const
187 {
188     if (rhs.isInvalid() || isInvalid())
189         return invalidTime();
190
191     if (rhs.isIndefinite() || isIndefinite())
192         return indefiniteTime();
193
194     if (isPositiveInfinite()) {
195         if (rhs.isPositiveInfinite())
196             return invalidTime();
197         return positiveInfiniteTime();
198     }
199
200     if (isNegativeInfinite()) {
201         if (rhs.isNegativeInfinite())
202             return invalidTime();
203         return negativeInfiniteTime();
204     }
205
206     int32_t commonTimeScale;
207     if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
208         commonTimeScale = MaximumTimeScale;
209     MediaTime a = *this;
210     MediaTime b = rhs;
211     a.setTimeScale(commonTimeScale);
212     b.setTimeScale(commonTimeScale);
213     while (!safeSub(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
214         if (commonTimeScale == 1)
215             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
216         commonTimeScale /= 2;
217         a.setTimeScale(commonTimeScale);
218         b.setTimeScale(commonTimeScale);
219     }
220     return a;
221 }
222
223 MediaTime MediaTime::operator*(int32_t rhs) const
224 {
225     if (isInvalid())
226         return invalidTime();
227
228     if (isIndefinite())
229         return indefiniteTime();
230
231     if (!rhs)
232         return zeroTime();
233
234     if (isPositiveInfinite()) {
235         if (rhs > 0)
236             return positiveInfiniteTime();
237         return negativeInfiniteTime();
238     }
239
240     if (isNegativeInfinite()) {
241         if (rhs > 0)
242             return negativeInfiniteTime();
243         return positiveInfiniteTime();
244     }
245
246     MediaTime a = *this;
247
248     while (!safeMultiply(a.m_timeValue, rhs, a.m_timeValue)) {
249         if (a.m_timeScale == 1)
250             return signum(a.m_timeValue) == signum(rhs) ? positiveInfiniteTime() : negativeInfiniteTime();
251         a.setTimeScale(a.m_timeScale / 2);
252     }
253
254     return a;
255 }
256
257 bool MediaTime::operator<(const MediaTime& rhs) const
258 {
259     return compare(rhs) == LessThan;
260 }
261
262 bool MediaTime::operator>(const MediaTime& rhs) const
263 {
264     return compare(rhs) == GreaterThan;
265 }
266
267 bool MediaTime::operator!=(const MediaTime& rhs) const
268 {
269     return compare(rhs) != EqualTo;
270 }
271
272 bool MediaTime::operator==(const MediaTime& rhs) const
273 {
274     return compare(rhs) == EqualTo;
275 }
276
277 bool MediaTime::operator>=(const MediaTime& rhs) const
278 {
279     return compare(rhs) >= EqualTo;
280 }
281
282 bool MediaTime::operator<=(const MediaTime& rhs) const
283 {
284     return compare(rhs) <= EqualTo;
285 }
286
287 MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
288 {
289     if ((isPositiveInfinite() && rhs.isPositiveInfinite())
290         || (isNegativeInfinite() && rhs.isNegativeInfinite())
291         || (isInvalid() && rhs.isInvalid())
292         || (isIndefinite() && rhs.isIndefinite()))
293         return EqualTo;
294
295     if (isInvalid())
296         return GreaterThan;
297
298     if (rhs.isInvalid())
299         return LessThan;
300
301     if (rhs.isNegativeInfinite() || isPositiveInfinite())
302         return GreaterThan;
303
304     if (rhs.isPositiveInfinite() || isNegativeInfinite())
305         return LessThan;
306
307     if (isIndefinite())
308         return GreaterThan;
309
310     if (rhs.isIndefinite())
311         return LessThan;
312
313     int64_t rhsWhole = rhs.m_timeValue / rhs.m_timeScale;
314     int64_t lhsWhole = m_timeValue / m_timeScale;
315     if (lhsWhole > rhsWhole)
316         return GreaterThan;
317     if (lhsWhole < rhsWhole)
318         return LessThan;
319
320     int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
321     int64_t lhsRemain = m_timeValue % m_timeScale;
322     int64_t lhsFactor = lhsRemain * rhs.m_timeScale;
323     int64_t rhsFactor = rhsRemain * m_timeScale;
324
325     if (lhsFactor == rhsFactor)
326         return EqualTo;
327     return lhsFactor > rhsFactor ? GreaterThan : LessThan;
328 }
329
330 const MediaTime& MediaTime::zeroTime()
331 {
332     static const MediaTime* time = new MediaTime(0, 1, Valid);
333     return *time;
334 }
335
336 const MediaTime& MediaTime::invalidTime()
337 {
338     static const MediaTime* time = new MediaTime(-1, 1, 0);
339     return *time;
340 }
341
342 const MediaTime& MediaTime::positiveInfiniteTime()
343 {
344     static const MediaTime* time = new MediaTime(0, 1, PositiveInfinite | Valid);
345     return *time;
346 }
347
348 const MediaTime& MediaTime::negativeInfiniteTime()
349 {
350     static const MediaTime* time = new MediaTime(-1, 1, NegativeInfinite | Valid);
351     return *time;
352 }
353
354 const MediaTime& MediaTime::indefiniteTime()
355 {
356     static const MediaTime* time = new MediaTime(0, 1, Indefinite | Valid);
357     return *time;
358 }
359
360 void MediaTime::setTimeScale(int32_t timeScale)
361 {
362     if (timeScale == m_timeScale)
363         return;
364     timeScale = std::min(MaximumTimeScale, timeScale);
365     int64_t wholePart = m_timeValue / m_timeScale;
366
367     // If setting the time scale will cause an overflow, divide the
368     // timescale by two until the number will fit, and round the
369     // result.
370     int64_t newWholePart;
371     while (!safeMultiply(wholePart, timeScale, newWholePart))
372         timeScale /= 2;
373
374     int64_t remainder = m_timeValue % m_timeScale;
375     m_timeValue = newWholePart + (remainder * timeScale) / m_timeScale;
376     m_timeScale = timeScale;
377 }
378
379 MediaTime abs(const MediaTime& rhs)
380 {
381     if (rhs.isInvalid())
382         return MediaTime::invalidTime();
383     if (rhs.isNegativeInfinite() || rhs.isPositiveInfinite())
384         return MediaTime::positiveInfiniteTime();
385     MediaTime val = rhs;
386     val.m_timeValue *= signum(rhs.m_timeScale) * signum(rhs.m_timeValue);
387     return val;
388 }
389
390 }
391