no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / xpcom / ds / StickyTimeDuration.h
blobce4e8c1e69c616b8c5746e0e55c1556d97253058
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/. */
7 #ifndef mozilla_StickyTimeDuration_h
8 #define mozilla_StickyTimeDuration_h
10 #include <cmath>
11 #include "mozilla/TimeStamp.h"
12 #include "mozilla/FloatingPoint.h"
14 namespace mozilla {
16 /**
17 * A ValueCalculator class that performs additional checks before performing
18 * arithmetic operations such that if either operand is Forever (or the
19 * negative equivalent) the result remains Forever (or the negative equivalent
20 * as appropriate).
22 * Currently this only checks if either argument to each operation is
23 * Forever/-Forever. However, it is possible that, for example,
24 * aA + aB > INT64_MAX (or < INT64_MIN).
26 * We currently don't check for that case since we don't expect that to
27 * happen often except under test conditions in which case the wrapping
28 * behavior is probably acceptable.
30 class StickyTimeDurationValueCalculator {
31 public:
32 static int64_t Add(int64_t aA, int64_t aB) {
33 MOZ_ASSERT((aA != INT64_MAX || aB != INT64_MIN) &&
34 (aA != INT64_MIN || aB != INT64_MAX),
35 "'Infinity + -Infinity' and '-Infinity + Infinity'"
36 " are undefined");
38 // Forever + x = Forever
39 // x + Forever = Forever
40 if (aA == INT64_MAX || aB == INT64_MAX) {
41 return INT64_MAX;
43 // -Forever + x = -Forever
44 // x + -Forever = -Forever
45 if (aA == INT64_MIN || aB == INT64_MIN) {
46 return INT64_MIN;
49 return aA + aB;
52 // Note that we can't just define Add and have BaseTimeDuration call Add with
53 // negative arguments since INT64_MAX != -INT64_MIN so the saturating logic
54 // won't work.
55 static int64_t Subtract(int64_t aA, int64_t aB) {
56 MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) || aA != aB,
57 "'Infinity - Infinity' and '-Infinity - -Infinity'"
58 " are undefined");
60 // Forever - x = Forever
61 // x - -Forever = Forever
62 if (aA == INT64_MAX || aB == INT64_MIN) {
63 return INT64_MAX;
65 // -Forever - x = -Forever
66 // x - Forever = -Forever
67 if (aA == INT64_MIN || aB == INT64_MAX) {
68 return INT64_MIN;
71 return aA - aB;
74 template <typename T>
75 static int64_t Multiply(int64_t aA, T aB) {
76 // Specializations for double, float, and int64_t are provided following.
77 return Multiply(aA, static_cast<int64_t>(aB));
80 static int64_t Divide(int64_t aA, int64_t aB) {
81 MOZ_ASSERT(aB != 0, "Division by zero");
82 MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
83 (aB != INT64_MAX && aB != INT64_MIN),
84 "Dividing +/-Infinity by +/-Infinity is undefined");
86 // Forever / +x = Forever
87 // Forever / -x = -Forever
88 // -Forever / +x = -Forever
89 // -Forever / -x = Forever
90 if (aA == INT64_MAX || aA == INT64_MIN) {
91 return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
93 // x / Forever = 0
94 // x / -Forever = 0
95 if (aB == INT64_MAX || aB == INT64_MIN) {
96 return 0;
99 return aA / aB;
102 static double DivideDouble(int64_t aA, int64_t aB) {
103 MOZ_ASSERT(aB != 0, "Division by zero");
104 MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
105 (aB != INT64_MAX && aB != INT64_MIN),
106 "Dividing +/-Infinity by +/-Infinity is undefined");
108 // Forever / +x = Forever
109 // Forever / -x = -Forever
110 // -Forever / +x = -Forever
111 // -Forever / -x = Forever
112 if (aA == INT64_MAX || aA == INT64_MIN) {
113 return (aA >= 0) ^ (aB >= 0) ? NegativeInfinity<double>()
114 : PositiveInfinity<double>();
116 // x / Forever = 0
117 // x / -Forever = 0
118 if (aB == INT64_MAX || aB == INT64_MIN) {
119 return 0.0;
122 return static_cast<double>(aA) / aB;
125 static int64_t Modulo(int64_t aA, int64_t aB) {
126 MOZ_ASSERT(aA != INT64_MAX && aA != INT64_MIN,
127 "Infinity modulo x is undefined");
129 return aA % aB;
133 template <>
134 inline int64_t StickyTimeDurationValueCalculator::Multiply<int64_t>(
135 int64_t aA, int64_t aB) {
136 MOZ_ASSERT((aA != 0 || (aB != INT64_MIN && aB != INT64_MAX)) &&
137 ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0),
138 "Multiplication of infinity by zero");
140 // Forever * +x = Forever
141 // Forever * -x = -Forever
142 // -Forever * +x = -Forever
143 // -Forever * -x = Forever
145 // i.e. If one or more of the arguments is +/-Forever, then
146 // return -Forever if the signs differ, or +Forever otherwise.
147 if (aA == INT64_MAX || aA == INT64_MIN || aB == INT64_MAX ||
148 aB == INT64_MIN) {
149 return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
152 return aA * aB;
155 template <>
156 inline int64_t StickyTimeDurationValueCalculator::Multiply<double>(int64_t aA,
157 double aB) {
158 MOZ_ASSERT((aA != 0 || (!std::isinf(aB))) &&
159 ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0.0),
160 "Multiplication of infinity by zero");
162 // As with Multiply<int64_t>, if one or more of the arguments is
163 // +/-Forever or +/-Infinity, then return -Forever if the signs differ,
164 // or +Forever otherwise.
165 if (aA == INT64_MAX || aA == INT64_MIN || std::isinf(aB)) {
166 return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX;
169 return aA * aB;
172 template <>
173 inline int64_t StickyTimeDurationValueCalculator::Multiply<float>(int64_t aA,
174 float aB) {
175 MOZ_ASSERT(std::isinf(aB) == std::isinf(static_cast<double>(aB)),
176 "Casting to float loses infinite-ness");
178 return Multiply(aA, static_cast<double>(aB));
182 * Specialization of BaseTimeDuration that uses
183 * StickyTimeDurationValueCalculator for arithmetic on the mValue member.
185 * Use this class when you need a time duration that is expected to hold values
186 * of Forever (or the negative equivalent) *and* when you expect that
187 * time duration to be used in arithmetic operations (and not just value
188 * comparisons).
190 typedef BaseTimeDuration<StickyTimeDurationValueCalculator> StickyTimeDuration;
192 // Template specializations to allow arithmetic between StickyTimeDuration
193 // and TimeDuration objects by falling back to the safe behavior.
194 inline StickyTimeDuration operator+(const TimeDuration& aA,
195 const StickyTimeDuration& aB) {
196 return StickyTimeDuration(aA) + aB;
198 inline StickyTimeDuration operator+(const StickyTimeDuration& aA,
199 const TimeDuration& aB) {
200 return aA + StickyTimeDuration(aB);
203 inline StickyTimeDuration operator-(const TimeDuration& aA,
204 const StickyTimeDuration& aB) {
205 return StickyTimeDuration(aA) - aB;
207 inline StickyTimeDuration operator-(const StickyTimeDuration& aA,
208 const TimeDuration& aB) {
209 return aA - StickyTimeDuration(aB);
212 inline StickyTimeDuration& operator+=(StickyTimeDuration& aA,
213 const TimeDuration& aB) {
214 return aA += StickyTimeDuration(aB);
216 inline StickyTimeDuration& operator-=(StickyTimeDuration& aA,
217 const TimeDuration& aB) {
218 return aA -= StickyTimeDuration(aB);
221 inline double operator/(const TimeDuration& aA, const StickyTimeDuration& aB) {
222 return StickyTimeDuration(aA) / aB;
224 inline double operator/(const StickyTimeDuration& aA, const TimeDuration& aB) {
225 return aA / StickyTimeDuration(aB);
228 inline StickyTimeDuration operator%(const TimeDuration& aA,
229 const StickyTimeDuration& aB) {
230 return StickyTimeDuration(aA) % aB;
232 inline StickyTimeDuration operator%(const StickyTimeDuration& aA,
233 const TimeDuration& aB) {
234 return aA % StickyTimeDuration(aB);
237 } // namespace mozilla
239 #endif /* mozilla_StickyTimeDuration_h */