Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / xpcom / ds / StickyTimeDuration.h
blob4d888dfbcd234ab641fff30ad997e51d86668d8b
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 "mozilla/TimeStamp.h"
11 #include "mozilla/FloatingPoint.h"
13 namespace mozilla {
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).
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).
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.
29 class StickyTimeDurationValueCalculator {
30 public:
31 static int64_t Add(int64_t aA, int64_t aB) {
32 MOZ_ASSERT((aA != INT64_MAX || aB != INT64_MIN) &&
33 (aA != INT64_MIN || aB != INT64_MAX),
34 "'Infinity + -Infinity' and '-Infinity + Infinity'"
35 " are undefined");
37 // Forever + x = Forever
38 // x + Forever = Forever
39 if (aA == INT64_MAX || aB == INT64_MAX) {
40 return INT64_MAX;
42 // -Forever + x = -Forever
43 // x + -Forever = -Forever
44 if (aA == INT64_MIN || aB == INT64_MIN) {
45 return INT64_MIN;
48 return aA + aB;
51 // Note that we can't just define Add and have BaseTimeDuration call Add with
52 // negative arguments since INT64_MAX != -INT64_MIN so the saturating logic
53 // won't work.
54 static int64_t Subtract(int64_t aA, int64_t aB) {
55 MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) || aA != aB,
56 "'Infinity - Infinity' and '-Infinity - -Infinity'"
57 " are undefined");
59 // Forever - x = Forever
60 // x - -Forever = Forever
61 if (aA == INT64_MAX || aB == INT64_MIN) {
62 return INT64_MAX;
64 // -Forever - x = -Forever
65 // x - Forever = -Forever
66 if (aA == INT64_MIN || aB == INT64_MAX) {
67 return INT64_MIN;
70 return aA - aB;
73 template <typename T>
74 static int64_t Multiply(int64_t aA, T aB) {
75 // Specializations for double, float, and int64_t are provided following.
76 return Multiply(aA, static_cast<int64_t>(aB));
79 static int64_t Divide(int64_t aA, int64_t aB) {
80 MOZ_ASSERT(aB != 0, "Division by zero");
81 MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
82 (aB != INT64_MAX && aB != INT64_MIN),
83 "Dividing +/-Infinity by +/-Infinity is undefined");
85 // Forever / +x = Forever
86 // Forever / -x = -Forever
87 // -Forever / +x = -Forever
88 // -Forever / -x = Forever
89 if (aA == INT64_MAX || aA == INT64_MIN) {
90 return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
92 // x / Forever = 0
93 // x / -Forever = 0
94 if (aB == INT64_MAX || aB == INT64_MIN) {
95 return 0;
98 return aA / aB;
101 static double DivideDouble(int64_t aA, int64_t aB) {
102 MOZ_ASSERT(aB != 0, "Division by zero");
103 MOZ_ASSERT((aA != INT64_MAX && aA != INT64_MIN) ||
104 (aB != INT64_MAX && aB != INT64_MIN),
105 "Dividing +/-Infinity by +/-Infinity is undefined");
107 // Forever / +x = Forever
108 // Forever / -x = -Forever
109 // -Forever / +x = -Forever
110 // -Forever / -x = Forever
111 if (aA == INT64_MAX || aA == INT64_MIN) {
112 return (aA >= 0) ^ (aB >= 0) ? NegativeInfinity<double>()
113 : PositiveInfinity<double>();
115 // x / Forever = 0
116 // x / -Forever = 0
117 if (aB == INT64_MAX || aB == INT64_MIN) {
118 return 0.0;
121 return static_cast<double>(aA) / aB;
124 static int64_t Modulo(int64_t aA, int64_t aB) {
125 MOZ_ASSERT(aA != INT64_MAX && aA != INT64_MIN,
126 "Infinity modulo x is undefined");
128 return aA % aB;
132 template <>
133 inline int64_t StickyTimeDurationValueCalculator::Multiply<int64_t>(
134 int64_t aA, int64_t aB) {
135 MOZ_ASSERT((aA != 0 || (aB != INT64_MIN && aB != INT64_MAX)) &&
136 ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0),
137 "Multiplication of infinity by zero");
139 // Forever * +x = Forever
140 // Forever * -x = -Forever
141 // -Forever * +x = -Forever
142 // -Forever * -x = Forever
144 // i.e. If one or more of the arguments is +/-Forever, then
145 // return -Forever if the signs differ, or +Forever otherwise.
146 if (aA == INT64_MAX || aA == INT64_MIN || aB == INT64_MAX ||
147 aB == INT64_MIN) {
148 return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
151 return aA * aB;
154 template <>
155 inline int64_t StickyTimeDurationValueCalculator::Multiply<double>(int64_t aA,
156 double aB) {
157 MOZ_ASSERT((aA != 0 || (!IsInfinite(aB))) &&
158 ((aA != INT64_MIN && aA != INT64_MAX) || aB != 0.0),
159 "Multiplication of infinity by zero");
161 // As with Multiply<int64_t>, if one or more of the arguments is
162 // +/-Forever or +/-Infinity, then return -Forever if the signs differ,
163 // or +Forever otherwise.
164 if (aA == INT64_MAX || aA == INT64_MIN || IsInfinite(aB)) {
165 return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX;
168 return aA * aB;
171 template <>
172 inline int64_t StickyTimeDurationValueCalculator::Multiply<float>(int64_t aA,
173 float aB) {
174 MOZ_ASSERT(IsInfinite(aB) == IsInfinite(static_cast<double>(aB)),
175 "Casting to float loses infinite-ness");
177 return Multiply(aA, static_cast<double>(aB));
181 * Specialization of BaseTimeDuration that uses
182 * StickyTimeDurationValueCalculator for arithmetic on the mValue member.
184 * Use this class when you need a time duration that is expected to hold values
185 * of Forever (or the negative equivalent) *and* when you expect that
186 * time duration to be used in arithmetic operations (and not just value
187 * comparisons).
189 typedef BaseTimeDuration<StickyTimeDurationValueCalculator> StickyTimeDuration;
191 // Template specializations to allow arithmetic between StickyTimeDuration
192 // and TimeDuration objects by falling back to the safe behavior.
193 inline StickyTimeDuration operator+(const TimeDuration& aA,
194 const StickyTimeDuration& aB) {
195 return StickyTimeDuration(aA) + aB;
197 inline StickyTimeDuration operator+(const StickyTimeDuration& aA,
198 const TimeDuration& aB) {
199 return aA + StickyTimeDuration(aB);
202 inline StickyTimeDuration operator-(const TimeDuration& aA,
203 const StickyTimeDuration& aB) {
204 return StickyTimeDuration(aA) - aB;
206 inline StickyTimeDuration operator-(const StickyTimeDuration& aA,
207 const TimeDuration& aB) {
208 return aA - StickyTimeDuration(aB);
211 inline StickyTimeDuration& operator+=(StickyTimeDuration& aA,
212 const TimeDuration& aB) {
213 return aA += StickyTimeDuration(aB);
215 inline StickyTimeDuration& operator-=(StickyTimeDuration& aA,
216 const TimeDuration& aB) {
217 return aA -= StickyTimeDuration(aB);
220 inline double operator/(const TimeDuration& aA, const StickyTimeDuration& aB) {
221 return StickyTimeDuration(aA) / aB;
223 inline double operator/(const StickyTimeDuration& aA, const TimeDuration& aB) {
224 return aA / StickyTimeDuration(aB);
227 inline StickyTimeDuration operator%(const TimeDuration& aA,
228 const StickyTimeDuration& aB) {
229 return StickyTimeDuration(aA) % aB;
231 inline StickyTimeDuration operator%(const StickyTimeDuration& aA,
232 const TimeDuration& aB) {
233 return aA % StickyTimeDuration(aB);
236 } // namespace mozilla
238 #endif /* mozilla_StickyTimeDuration_h */