Coverage Report

Created: 2018-09-25 14:53

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