Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/StickyTimeDuration.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 mozilla_StickyTimeDuration_h
8
#define mozilla_StickyTimeDuration_h
9
10
#include "mozilla/TimeStamp.h"
11
#include "mozilla/FloatingPoint.h"
12
13
namespace mozilla {
14
15
/**
16
 * A ValueCalculator class that performs additional checks before performing
17
 * arithmetic operations such that if either operand is Forever (or the
18
 * negative equivalent) the result remains Forever (or the negative equivalent
19
 * as appropriate).
20
 *
21
 * Currently this only checks if either argument to each operation is
22
 * Forever/-Forever. However, it is possible that, for example,
23
 * aA + aB > INT64_MAX (or < INT64_MIN).
24
 *
25
 * We currently don't check for that case since we don't expect that to
26
 * happen often except under test conditions in which case the wrapping
27
 * behavior is probably acceptable.
28
 */
29
class StickyTimeDurationValueCalculator
30
{
31
public:
32
  static int64_t
33
  Add(int64_t aA, int64_t aB)
34
0
  {
35
0
    MOZ_ASSERT((aA != INT64_MAX || aB != INT64_MIN) &&
36
0
               (aA != INT64_MIN || aB != INT64_MAX),
37
0
               "'Infinity + -Infinity' and '-Infinity + Infinity'"
38
0
               " are undefined");
39
0
40
0
    // Forever + x = Forever
41
0
    // x + Forever = Forever
42
0
    if (aA == INT64_MAX || aB == INT64_MAX) {
43
0
      return INT64_MAX;
44
0
    }
45
0
    // -Forever + x = -Forever
46
0
    // x + -Forever = -Forever
47
0
    if (aA == INT64_MIN || aB == INT64_MIN) {
48
0
      return INT64_MIN;
49
0
    }
50
0
51
0
    return aA + aB;
52
0
  }
53
54
  // Note that we can't just define Add and have BaseTimeDuration call Add with
55
  // negative arguments since INT64_MAX != -INT64_MIN so the saturating logic
56
  // won't work.
57
  static int64_t
58
  Subtract(int64_t aA, int64_t aB)
59
0
  {
60
0
    MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) || aA != aB,
61
0
               "'Infinity - Infinity' and '-Infinity - -Infinity'"
62
0
               " are undefined");
63
0
64
0
    // Forever - x  = Forever
65
0
    // x - -Forever = Forever
66
0
    if (aA == INT64_MAX || aB == INT64_MIN) {
67
0
      return INT64_MAX;
68
0
    }
69
0
    // -Forever - x = -Forever
70
0
    // x - Forever  = -Forever
71
0
    if (aA == INT64_MIN || aB == INT64_MAX) {
72
0
      return INT64_MIN;
73
0
    }
74
0
75
0
    return aA - aB;
76
0
  }
77
78
  template <typename T>
79
  static int64_t
80
  Multiply(int64_t aA, T aB) {
81
    // Specializations for double, float, and int64_t are provided following.
82
    return Multiply(aA, static_cast<int64_t>(aB));
83
  }
84
85
  static int64_t
86
0
  Divide(int64_t aA, int64_t aB) {
87
0
    MOZ_ASSERT(aB != 0, "Division by zero");
88
0
    MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
89
0
               (aB != INT64_MAX && aB != INT64_MIN),
90
0
               "Dividing +/-Infinity by +/-Infinity is undefined");
91
0
92
0
    // Forever / +x = Forever
93
0
    // Forever / -x = -Forever
94
0
    // -Forever / +x = -Forever
95
0
    // -Forever / -x = Forever
96
0
    if (aA == INT64_MAX || aA == INT64_MIN) {
97
0
      return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
98
0
    }
99
0
    // x /  Forever = 0
100
0
    // x / -Forever = 0
101
0
    if (aB == INT64_MAX || aB == INT64_MIN) {
102
0
      return 0;
103
0
    }
104
0
105
0
    return aA / aB;
106
0
  }
107
108
  static double
109
  DivideDouble(int64_t aA, int64_t aB)
110
0
  {
111
0
    MOZ_ASSERT(aB != 0, "Division by zero");
112
0
    MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
113
0
               (aB != INT64_MAX && aB != INT64_MIN),
114
0
               "Dividing +/-Infinity by +/-Infinity is undefined");
115
0
116
0
    // Forever / +x = Forever
117
0
    // Forever / -x = -Forever
118
0
    // -Forever / +x = -Forever
119
0
    // -Forever / -x = Forever
120
0
    if (aA == INT64_MAX || aA == INT64_MIN) {
121
0
      return (aA >= 0) ^ (aB >= 0)
122
0
             ? NegativeInfinity<double>()
123
0
             : PositiveInfinity<double>();
124
0
    }
125
0
    // x /  Forever = 0
126
0
    // x / -Forever = 0
127
0
    if (aB == INT64_MAX || aB == INT64_MIN) {
128
0
      return 0.0;
129
0
    }
130
0
131
0
    return static_cast<double>(aA) / aB;
132
0
  }
133
134
  static int64_t
135
  Modulo(int64_t aA, int64_t aB)
136
0
  {
137
0
    MOZ_ASSERT(aA != INT64_MAX && aA != INT64_MIN,
138
0
               "Infinity modulo x is undefined");
139
0
140
0
    return aA % aB;
141
0
  }
142
};
143
144
template <>
145
inline int64_t
146
StickyTimeDurationValueCalculator::Multiply<int64_t>(int64_t aA,
147
                                                          int64_t aB)
148
0
{
149
0
  MOZ_ASSERT((aA != 0 || (aB != INT64_MIN && aB != INT64_MAX)) &&
150
0
             ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0),
151
0
             "Multiplication of infinity by zero");
152
0
153
0
  // Forever  * +x = Forever
154
0
  // Forever  * -x = -Forever
155
0
  // -Forever * +x = -Forever
156
0
  // -Forever * -x = Forever
157
0
  //
158
0
  // i.e. If one or more of the arguments is +/-Forever, then
159
0
  // return -Forever if the signs differ, or +Forever otherwise.
160
0
  if (aA == INT64_MAX || aA == INT64_MIN ||
161
0
      aB == INT64_MAX || aB == INT64_MIN) {
162
0
    return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
163
0
  }
164
0
165
0
  return aA * aB;
166
0
}
167
168
template <>
169
inline int64_t
170
StickyTimeDurationValueCalculator::Multiply<double>(int64_t aA, double aB)
171
0
{
172
0
  MOZ_ASSERT((aA != 0 || (!IsInfinite(aB))) &&
173
0
             ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0.0),
174
0
             "Multiplication of infinity by zero");
175
0
176
0
  // As with Multiply<int64_t>, if one or more of the arguments is
177
0
  // +/-Forever or +/-Infinity, then return -Forever if the signs differ,
178
0
  // or +Forever otherwise.
179
0
  if (aA == INT64_MAX || aA == INT64_MIN || IsInfinite(aB)) {
180
0
    return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX;
181
0
  }
182
0
183
0
  return aA * aB;
184
0
}
185
186
template <>
187
inline int64_t
188
StickyTimeDurationValueCalculator::Multiply<float>(int64_t aA, float aB)
189
0
{
190
0
  MOZ_ASSERT(IsInfinite(aB) == IsInfinite(static_cast<double>(aB)),
191
0
             "Casting to float loses infinite-ness");
192
0
193
0
  return Multiply(aA, static_cast<double>(aB));
194
0
}
195
196
/**
197
 * Specialization of BaseTimeDuration that uses
198
 * StickyTimeDurationValueCalculator for arithmetic on the mValue member.
199
 *
200
 * Use this class when you need a time duration that is expected to hold values
201
 * of Forever (or the negative equivalent) *and* when you expect that
202
 * time duration to be used in arithmetic operations (and not just value
203
 * comparisons).
204
 */
205
typedef BaseTimeDuration<StickyTimeDurationValueCalculator>
206
  StickyTimeDuration;
207
208
// Template specializations to allow arithmetic between StickyTimeDuration
209
// and TimeDuration objects by falling back to the safe behavior.
210
inline StickyTimeDuration
211
operator+(const TimeDuration& aA, const StickyTimeDuration& aB)
212
0
{
213
0
  return StickyTimeDuration(aA) + aB;
214
0
}
215
inline StickyTimeDuration
216
operator+(const StickyTimeDuration& aA, const TimeDuration& aB)
217
0
{
218
0
  return aA + StickyTimeDuration(aB);
219
0
}
220
221
inline StickyTimeDuration
222
operator-(const TimeDuration& aA, const StickyTimeDuration& aB)
223
0
{
224
0
  return StickyTimeDuration(aA) - aB;
225
0
}
226
inline StickyTimeDuration
227
operator-(const StickyTimeDuration& aA, const TimeDuration& aB)
228
0
{
229
0
  return aA - StickyTimeDuration(aB);
230
0
}
231
232
inline StickyTimeDuration&
233
operator+=(StickyTimeDuration &aA, const TimeDuration& aB)
234
0
{
235
0
  return aA += StickyTimeDuration(aB);
236
0
}
237
inline StickyTimeDuration&
238
operator-=(StickyTimeDuration &aA, const TimeDuration& aB)
239
0
{
240
0
  return aA -= StickyTimeDuration(aB);
241
0
}
242
243
inline double
244
operator/(const TimeDuration& aA, const StickyTimeDuration& aB)
245
0
{
246
0
  return StickyTimeDuration(aA) / aB;
247
0
}
248
inline double
249
operator/(const StickyTimeDuration& aA, const TimeDuration& aB)
250
0
{
251
0
  return aA / StickyTimeDuration(aB);
252
0
}
253
254
inline StickyTimeDuration
255
operator%(const TimeDuration& aA, const StickyTimeDuration& aB)
256
0
{
257
0
  return StickyTimeDuration(aA) % aB;
258
0
}
259
inline StickyTimeDuration
260
operator%(const StickyTimeDuration& aA, const TimeDuration& aB)
261
0
{
262
0
  return aA % StickyTimeDuration(aB);
263
0
}
264
265
} // namespace mozilla
266
267
#endif /* mozilla_StickyTimeDuration_h */