Mercurial > hg > sv-dependency-builds
comparison osx/include/kj/units.h @ 62:0994c39f1e94
Cap'n Proto v0.6 + build for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 22 May 2017 10:01:37 +0100 |
parents | 3ab5a40c4e3b |
children |
comparison
equal
deleted
inserted
replaced
61:d101c4099725 | 62:0994c39f1e94 |
---|---|
29 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS | 29 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS |
30 #pragma GCC system_header | 30 #pragma GCC system_header |
31 #endif | 31 #endif |
32 | 32 |
33 #include "common.h" | 33 #include "common.h" |
34 #include <inttypes.h> | |
34 | 35 |
35 namespace kj { | 36 namespace kj { |
36 | 37 |
37 // ======================================================================================= | 38 // ======================================================================================= |
38 // IDs | 39 // IDs |
64 inline constexpr bool operator> (const Id& other) const { return value > other.value; } | 65 inline constexpr bool operator> (const Id& other) const { return value > other.value; } |
65 }; | 66 }; |
66 | 67 |
67 // ======================================================================================= | 68 // ======================================================================================= |
68 // Quantity and UnitRatio -- implement unit analysis via the type system | 69 // Quantity and UnitRatio -- implement unit analysis via the type system |
70 | |
71 struct Unsafe_ {}; | |
72 constexpr Unsafe_ unsafe = Unsafe_(); | |
73 // Use as a parameter to constructors that are unsafe to indicate that you really do mean it. | |
74 | |
75 template <uint64_t maxN, typename T> | |
76 class Bounded; | |
77 template <uint value> | |
78 class BoundedConst; | |
69 | 79 |
70 template <typename T> constexpr bool isIntegral() { return false; } | 80 template <typename T> constexpr bool isIntegral() { return false; } |
71 template <> constexpr bool isIntegral<char>() { return true; } | 81 template <> constexpr bool isIntegral<char>() { return true; } |
72 template <> constexpr bool isIntegral<signed char>() { return true; } | 82 template <> constexpr bool isIntegral<signed char>() { return true; } |
73 template <> constexpr bool isIntegral<short>() { return true; } | 83 template <> constexpr bool isIntegral<short>() { return true; } |
78 template <> constexpr bool isIntegral<unsigned short>() { return true; } | 88 template <> constexpr bool isIntegral<unsigned short>() { return true; } |
79 template <> constexpr bool isIntegral<unsigned int>() { return true; } | 89 template <> constexpr bool isIntegral<unsigned int>() { return true; } |
80 template <> constexpr bool isIntegral<unsigned long>() { return true; } | 90 template <> constexpr bool isIntegral<unsigned long>() { return true; } |
81 template <> constexpr bool isIntegral<unsigned long long>() { return true; } | 91 template <> constexpr bool isIntegral<unsigned long long>() { return true; } |
82 | 92 |
93 template <typename T> | |
94 struct IsIntegralOrBounded_ { static constexpr bool value = isIntegral<T>(); }; | |
95 template <uint64_t m, typename T> | |
96 struct IsIntegralOrBounded_<Bounded<m, T>> { static constexpr bool value = true; }; | |
97 template <uint v> | |
98 struct IsIntegralOrBounded_<BoundedConst<v>> { static constexpr bool value = true; }; | |
99 | |
100 template <typename T> | |
101 inline constexpr bool isIntegralOrBounded() { return IsIntegralOrBounded_<T>::value; } | |
102 | |
83 template <typename Number, typename Unit1, typename Unit2> | 103 template <typename Number, typename Unit1, typename Unit2> |
84 class UnitRatio { | 104 class UnitRatio { |
85 // A multiplier used to convert Quantities of one unit to Quantities of another unit. See | 105 // A multiplier used to convert Quantities of one unit to Quantities of another unit. See |
86 // Quantity, below. | 106 // Quantity, below. |
87 // | 107 // |
88 // Construct this type by dividing one Quantity by another of a different unit. Use this type | 108 // Construct this type by dividing one Quantity by another of a different unit. Use this type |
89 // by multiplying it by a Quantity, or dividing a Quantity by it. | 109 // by multiplying it by a Quantity, or dividing a Quantity by it. |
90 | 110 |
91 static_assert(isIntegral<Number>(), "Underlying type for UnitRatio must be integer."); | 111 static_assert(isIntegralOrBounded<Number>(), |
112 "Underlying type for UnitRatio must be integer."); | |
92 | 113 |
93 public: | 114 public: |
94 inline UnitRatio() {} | 115 inline UnitRatio() {} |
95 | 116 |
96 constexpr explicit UnitRatio(Number unit1PerUnit2): unit1PerUnit2(unit1PerUnit2) {} | 117 constexpr UnitRatio(Number unit1PerUnit2, decltype(unsafe)): unit1PerUnit2(unit1PerUnit2) {} |
97 // This constructor was intended to be private, but GCC complains about it being private in a | 118 // This constructor was intended to be private, but GCC complains about it being private in a |
98 // bunch of places that don't appear to even call it, so I made it public. Oh well. | 119 // bunch of places that don't appear to even call it, so I made it public. Oh well. |
99 | 120 |
100 template <typename OtherNumber> | 121 template <typename OtherNumber> |
101 inline constexpr UnitRatio(const UnitRatio<OtherNumber, Unit1, Unit2>& other) | 122 inline constexpr UnitRatio(const UnitRatio<OtherNumber, Unit1, Unit2>& other) |
102 : unit1PerUnit2(other.unit1PerUnit2) {} | 123 : unit1PerUnit2(other.unit1PerUnit2) {} |
103 | 124 |
104 template <typename OtherNumber> | 125 template <typename OtherNumber> |
105 inline constexpr UnitRatio<decltype(Number(1)+OtherNumber(1)), Unit1, Unit2> | 126 inline constexpr UnitRatio<decltype(Number()+OtherNumber()), Unit1, Unit2> |
106 operator+(UnitRatio<OtherNumber, Unit1, Unit2> other) const { | 127 operator+(UnitRatio<OtherNumber, Unit1, Unit2> other) const { |
107 return UnitRatio<decltype(Number(1)+OtherNumber(1)), Unit1, Unit2>( | 128 return UnitRatio<decltype(Number()+OtherNumber()), Unit1, Unit2>( |
108 unit1PerUnit2 + other.unit1PerUnit2); | 129 unit1PerUnit2 + other.unit1PerUnit2, unsafe); |
109 } | 130 } |
110 template <typename OtherNumber> | 131 template <typename OtherNumber> |
111 inline constexpr UnitRatio<decltype(Number(1)-OtherNumber(1)), Unit1, Unit2> | 132 inline constexpr UnitRatio<decltype(Number()-OtherNumber()), Unit1, Unit2> |
112 operator-(UnitRatio<OtherNumber, Unit1, Unit2> other) const { | 133 operator-(UnitRatio<OtherNumber, Unit1, Unit2> other) const { |
113 return UnitRatio<decltype(Number(1)-OtherNumber(1)), Unit1, Unit2>( | 134 return UnitRatio<decltype(Number()-OtherNumber()), Unit1, Unit2>( |
114 unit1PerUnit2 - other.unit1PerUnit2); | 135 unit1PerUnit2 - other.unit1PerUnit2, unsafe); |
115 } | 136 } |
116 | 137 |
117 template <typename OtherNumber, typename Unit3> | 138 template <typename OtherNumber, typename Unit3> |
118 inline constexpr UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit3, Unit2> | 139 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2> |
119 operator*(UnitRatio<OtherNumber, Unit3, Unit1> other) const { | 140 operator*(UnitRatio<OtherNumber, Unit3, Unit1> other) const { |
120 // U1 / U2 * U3 / U1 = U3 / U2 | 141 // U1 / U2 * U3 / U1 = U3 / U2 |
121 return UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit3, Unit2>( | 142 return UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2>( |
122 unit1PerUnit2 * other.unit1PerUnit2); | 143 unit1PerUnit2 * other.unit1PerUnit2, unsafe); |
123 } | 144 } |
124 template <typename OtherNumber, typename Unit3> | 145 template <typename OtherNumber, typename Unit3> |
125 inline constexpr UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit1, Unit3> | 146 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3> |
126 operator*(UnitRatio<OtherNumber, Unit2, Unit3> other) const { | 147 operator*(UnitRatio<OtherNumber, Unit2, Unit3> other) const { |
127 // U1 / U2 * U2 / U3 = U1 / U3 | 148 // U1 / U2 * U2 / U3 = U1 / U3 |
128 return UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit1, Unit3>( | 149 return UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3>( |
129 unit1PerUnit2 * other.unit1PerUnit2); | 150 unit1PerUnit2 * other.unit1PerUnit2, unsafe); |
130 } | 151 } |
131 | 152 |
132 template <typename OtherNumber, typename Unit3> | 153 template <typename OtherNumber, typename Unit3> |
133 inline constexpr UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit3, Unit2> | 154 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2> |
134 operator/(UnitRatio<OtherNumber, Unit1, Unit3> other) const { | 155 operator/(UnitRatio<OtherNumber, Unit1, Unit3> other) const { |
135 // (U1 / U2) / (U1 / U3) = U3 / U2 | 156 // (U1 / U2) / (U1 / U3) = U3 / U2 |
136 return UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit3, Unit2>( | 157 return UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2>( |
137 unit1PerUnit2 / other.unit1PerUnit2); | 158 unit1PerUnit2 / other.unit1PerUnit2, unsafe); |
138 } | 159 } |
139 template <typename OtherNumber, typename Unit3> | 160 template <typename OtherNumber, typename Unit3> |
140 inline constexpr UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit1, Unit3> | 161 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3> |
141 operator/(UnitRatio<OtherNumber, Unit3, Unit2> other) const { | 162 operator/(UnitRatio<OtherNumber, Unit3, Unit2> other) const { |
142 // (U1 / U2) / (U3 / U2) = U1 / U3 | 163 // (U1 / U2) / (U3 / U2) = U1 / U3 |
143 return UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit1, Unit3>( | 164 return UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3>( |
144 unit1PerUnit2 / other.unit1PerUnit2); | 165 unit1PerUnit2 / other.unit1PerUnit2, unsafe); |
145 } | 166 } |
146 | 167 |
147 template <typename OtherNumber> | 168 template <typename OtherNumber> |
148 inline decltype(Number(1) / OtherNumber(1)) | 169 inline decltype(Number() / OtherNumber()) |
149 operator/(UnitRatio<OtherNumber, Unit1, Unit2> other) const { | 170 operator/(UnitRatio<OtherNumber, Unit1, Unit2> other) const { |
150 return unit1PerUnit2 / other.unit1PerUnit2; | 171 return unit1PerUnit2 / other.unit1PerUnit2; |
151 } | 172 } |
152 | 173 |
153 inline bool operator==(UnitRatio other) const { return unit1PerUnit2 == other.unit1PerUnit2; } | 174 inline bool operator==(UnitRatio other) const { return unit1PerUnit2 == other.unit1PerUnit2; } |
159 template <typename OtherNumber, typename OtherUnit> | 180 template <typename OtherNumber, typename OtherUnit> |
160 friend class Quantity; | 181 friend class Quantity; |
161 template <typename OtherNumber, typename OtherUnit1, typename OtherUnit2> | 182 template <typename OtherNumber, typename OtherUnit1, typename OtherUnit2> |
162 friend class UnitRatio; | 183 friend class UnitRatio; |
163 | 184 |
164 template <typename N1, typename N2, typename U1, typename U2> | 185 template <typename N1, typename N2, typename U1, typename U2, typename> |
165 friend inline constexpr UnitRatio<decltype(N1(1) * N2(1)), U1, U2> | 186 friend inline constexpr UnitRatio<decltype(N1() * N2()), U1, U2> |
166 operator*(N1, UnitRatio<N2, U1, U2>); | 187 operator*(N1, UnitRatio<N2, U1, U2>); |
167 }; | 188 }; |
168 | 189 |
169 template <typename N1, typename N2, typename U1, typename U2> | 190 template <typename N1, typename N2, typename U1, typename U2, |
170 inline constexpr UnitRatio<decltype(N1(1) * N2(1)), U1, U2> | 191 typename = EnableIf<isIntegralOrBounded<N1>() && isIntegralOrBounded<N2>()>> |
192 inline constexpr UnitRatio<decltype(N1() * N2()), U1, U2> | |
171 operator*(N1 n, UnitRatio<N2, U1, U2> r) { | 193 operator*(N1 n, UnitRatio<N2, U1, U2> r) { |
172 return UnitRatio<decltype(N1(1) * N2(1)), U1, U2>(n * r.unit1PerUnit2); | 194 return UnitRatio<decltype(N1() * N2()), U1, U2>(n * r.unit1PerUnit2, unsafe); |
173 } | 195 } |
174 | 196 |
175 template <typename Number, typename Unit> | 197 template <typename Number, typename Unit> |
176 class Quantity { | 198 class Quantity { |
177 // A type-safe numeric quantity, specified in terms of some unit. Two Quantities cannot be used | 199 // A type-safe numeric quantity, specified in terms of some unit. Two Quantities cannot be used |
214 // | 236 // |
215 // void waitThreeMinutes() { | 237 // void waitThreeMinutes() { |
216 // waitFor(3 * MINUTES); | 238 // waitFor(3 * MINUTES); |
217 // } | 239 // } |
218 | 240 |
219 static_assert(isIntegral<Number>(), "Underlying type for Quantity must be integer."); | 241 static_assert(isIntegralOrBounded<Number>(), |
242 "Underlying type for Quantity must be integer."); | |
220 | 243 |
221 public: | 244 public: |
222 inline constexpr Quantity() {} | 245 inline constexpr Quantity() = default; |
223 | 246 |
224 inline constexpr Quantity(MaxValue_): value(maxValue) {} | 247 inline constexpr Quantity(MaxValue_): value(maxValue) {} |
225 inline constexpr Quantity(MinValue_): value(minValue) {} | 248 inline constexpr Quantity(MinValue_): value(minValue) {} |
226 // Allow initialization from maxValue and minValue. | 249 // Allow initialization from maxValue and minValue. |
227 // TODO(msvc): decltype(maxValue) and decltype(minValue) deduce unknown-type for these function | 250 // TODO(msvc): decltype(maxValue) and decltype(minValue) deduce unknown-type for these function |
228 // parameters, causing the compiler to complain of a duplicate constructor definition, so we | 251 // parameters, causing the compiler to complain of a duplicate constructor definition, so we |
229 // specify MaxValue_ and MinValue_ types explicitly. | 252 // specify MaxValue_ and MinValue_ types explicitly. |
230 | 253 |
231 inline explicit constexpr Quantity(Number value): value(value) {} | 254 inline constexpr Quantity(Number value, decltype(unsafe)): value(value) {} |
232 // This constructor was intended to be private, but GCC complains about it being private in a | 255 // This constructor was intended to be private, but GCC complains about it being private in a |
233 // bunch of places that don't appear to even call it, so I made it public. Oh well. | 256 // bunch of places that don't appear to even call it, so I made it public. Oh well. |
234 | 257 |
235 template <typename OtherNumber> | 258 template <typename OtherNumber> |
236 inline constexpr Quantity(const Quantity<OtherNumber, Unit>& other) | 259 inline constexpr Quantity(const Quantity<OtherNumber, Unit>& other) |
237 : value(other.value) {} | 260 : value(other.value) {} |
238 | 261 |
239 template <typename OtherNumber> | 262 template <typename OtherNumber> |
240 inline constexpr Quantity<decltype(Number(1) + OtherNumber(1)), Unit> | 263 inline Quantity& operator=(const Quantity<OtherNumber, Unit>& other) { |
264 value = other.value; | |
265 return *this; | |
266 } | |
267 | |
268 template <typename OtherNumber> | |
269 inline constexpr Quantity<decltype(Number() + OtherNumber()), Unit> | |
241 operator+(const Quantity<OtherNumber, Unit>& other) const { | 270 operator+(const Quantity<OtherNumber, Unit>& other) const { |
242 return Quantity<decltype(Number(1) + OtherNumber(1)), Unit>(value + other.value); | 271 return Quantity<decltype(Number() + OtherNumber()), Unit>(value + other.value, unsafe); |
243 } | 272 } |
244 template <typename OtherNumber> | 273 template <typename OtherNumber> |
245 inline constexpr Quantity<decltype(Number(1) - OtherNumber(1)), Unit> | 274 inline constexpr Quantity<decltype(Number() - OtherNumber()), Unit> |
246 operator-(const Quantity<OtherNumber, Unit>& other) const { | 275 operator-(const Quantity<OtherNumber, Unit>& other) const { |
247 return Quantity<decltype(Number(1) - OtherNumber(1)), Unit>(value - other.value); | 276 return Quantity<decltype(Number() - OtherNumber()), Unit>(value - other.value, unsafe); |
248 } | 277 } |
249 template <typename OtherNumber> | 278 template <typename OtherNumber, typename = EnableIf<isIntegralOrBounded<OtherNumber>()>> |
250 inline constexpr Quantity<decltype(Number(1) * OtherNumber(1)), Unit> | 279 inline constexpr Quantity<decltype(Number() * OtherNumber()), Unit> |
251 operator*(OtherNumber other) const { | 280 operator*(OtherNumber other) const { |
252 static_assert(isIntegral<OtherNumber>(), "Multiplied Quantity by non-integer."); | 281 return Quantity<decltype(Number() * other), Unit>(value * other, unsafe); |
253 return Quantity<decltype(Number(1) * other), Unit>(value * other); | 282 } |
254 } | 283 template <typename OtherNumber, typename = EnableIf<isIntegralOrBounded<OtherNumber>()>> |
255 template <typename OtherNumber> | 284 inline constexpr Quantity<decltype(Number() / OtherNumber()), Unit> |
256 inline constexpr Quantity<decltype(Number(1) / OtherNumber(1)), Unit> | |
257 operator/(OtherNumber other) const { | 285 operator/(OtherNumber other) const { |
258 static_assert(isIntegral<OtherNumber>(), "Divided Quantity by non-integer."); | 286 return Quantity<decltype(Number() / other), Unit>(value / other, unsafe); |
259 return Quantity<decltype(Number(1) / other), Unit>(value / other); | 287 } |
260 } | 288 template <typename OtherNumber> |
261 template <typename OtherNumber> | 289 inline constexpr decltype(Number() / OtherNumber()) |
262 inline constexpr decltype(Number(1) / OtherNumber(1)) | |
263 operator/(const Quantity<OtherNumber, Unit>& other) const { | 290 operator/(const Quantity<OtherNumber, Unit>& other) const { |
264 return value / other.value; | 291 return value / other.value; |
265 } | 292 } |
266 template <typename OtherNumber> | 293 template <typename OtherNumber> |
267 inline constexpr decltype(Number(1) % OtherNumber(1)) | 294 inline constexpr Quantity<decltype(Number() % OtherNumber()), Unit> |
268 operator%(const Quantity<OtherNumber, Unit>& other) const { | 295 operator%(const Quantity<OtherNumber, Unit>& other) const { |
269 return value % other.value; | 296 return Quantity<decltype(Number() % OtherNumber()), Unit>(value % other.value, unsafe); |
270 } | 297 } |
271 | 298 |
272 template <typename OtherNumber, typename OtherUnit> | 299 template <typename OtherNumber, typename OtherUnit> |
273 inline constexpr Quantity<decltype(Number(1) * OtherNumber(1)), OtherUnit> | 300 inline constexpr Quantity<decltype(Number() * OtherNumber()), OtherUnit> |
274 operator*(const UnitRatio<OtherNumber, OtherUnit, Unit>& ratio) const { | 301 operator*(UnitRatio<OtherNumber, OtherUnit, Unit> ratio) const { |
275 return Quantity<decltype(Number(1) * OtherNumber(1)), OtherUnit>( | 302 return Quantity<decltype(Number() * OtherNumber()), OtherUnit>( |
276 value * ratio.unit1PerUnit2); | 303 value * ratio.unit1PerUnit2, unsafe); |
277 } | 304 } |
278 template <typename OtherNumber, typename OtherUnit> | 305 template <typename OtherNumber, typename OtherUnit> |
279 inline constexpr Quantity<decltype(Number(1) / OtherNumber(1)), OtherUnit> | 306 inline constexpr Quantity<decltype(Number() / OtherNumber()), OtherUnit> |
280 operator/(const UnitRatio<OtherNumber, Unit, OtherUnit>& ratio) const { | 307 operator/(UnitRatio<OtherNumber, Unit, OtherUnit> ratio) const { |
281 return Quantity<decltype(Number(1) / OtherNumber(1)), OtherUnit>( | 308 return Quantity<decltype(Number() / OtherNumber()), OtherUnit>( |
282 value / ratio.unit1PerUnit2); | 309 value / ratio.unit1PerUnit2, unsafe); |
283 } | 310 } |
284 template <typename OtherNumber, typename OtherUnit> | 311 template <typename OtherNumber, typename OtherUnit> |
285 inline constexpr Quantity<decltype(Number(1) % OtherNumber(1)), Unit> | 312 inline constexpr Quantity<decltype(Number() % OtherNumber()), Unit> |
286 operator%(const UnitRatio<OtherNumber, Unit, OtherUnit>& ratio) const { | 313 operator%(UnitRatio<OtherNumber, Unit, OtherUnit> ratio) const { |
287 return Quantity<decltype(Number(1) % OtherNumber(1)), Unit>( | 314 return Quantity<decltype(Number() % OtherNumber()), Unit>( |
288 value % ratio.unit1PerUnit2); | 315 value % ratio.unit1PerUnit2, unsafe); |
289 } | 316 } |
290 template <typename OtherNumber, typename OtherUnit> | 317 template <typename OtherNumber, typename OtherUnit> |
291 inline constexpr UnitRatio<decltype(Number(1) / OtherNumber(1)), Unit, OtherUnit> | 318 inline constexpr UnitRatio<decltype(Number() / OtherNumber()), Unit, OtherUnit> |
292 operator/(const Quantity<OtherNumber, OtherUnit>& other) const { | 319 operator/(Quantity<OtherNumber, OtherUnit> other) const { |
293 return UnitRatio<decltype(Number(1) / OtherNumber(1)), Unit, OtherUnit>(value / other.value); | 320 return UnitRatio<decltype(Number() / OtherNumber()), Unit, OtherUnit>( |
321 value / other.value, unsafe); | |
294 } | 322 } |
295 | 323 |
296 template <typename OtherNumber> | 324 template <typename OtherNumber> |
297 inline constexpr bool operator==(const Quantity<OtherNumber, Unit>& other) const { | 325 inline constexpr bool operator==(const Quantity<OtherNumber, Unit>& other) const { |
298 return value == other.value; | 326 return value == other.value; |
345 template <typename OtherNumber, typename OtherUnit> | 373 template <typename OtherNumber, typename OtherUnit> |
346 friend class Quantity; | 374 friend class Quantity; |
347 | 375 |
348 template <typename Number1, typename Number2, typename Unit2> | 376 template <typename Number1, typename Number2, typename Unit2> |
349 friend inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit2> b) | 377 friend inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit2> b) |
350 -> Quantity<decltype(Number1(1) * Number2(1)), Unit2>; | 378 -> Quantity<decltype(Number1() * Number2()), Unit2>; |
351 | 379 }; |
352 template <typename T> | 380 |
353 friend inline constexpr T unit(); | 381 template <typename T> struct Unit_ { |
382 static inline constexpr T get() { return T(1); } | |
383 }; | |
384 template <typename T, typename U> | |
385 struct Unit_<Quantity<T, U>> { | |
386 static inline constexpr Quantity<decltype(Unit_<T>::get()), U> get() { | |
387 return Quantity<decltype(Unit_<T>::get()), U>(Unit_<T>::get(), unsafe); | |
388 } | |
354 }; | 389 }; |
355 | 390 |
356 template <typename T> | 391 template <typename T> |
357 inline constexpr T unit() { return T(1); } | 392 inline constexpr auto unit() -> decltype(Unit_<T>::get()) { return Unit_<T>::get(); } |
358 // unit<Quantity<T, U>>() returns a Quantity of value 1. It also, intentionally, works on basic | 393 // unit<Quantity<T, U>>() returns a Quantity of value 1. It also, intentionally, works on basic |
359 // numeric types. | 394 // numeric types. |
360 | 395 |
361 template <typename Number1, typename Number2, typename Unit> | 396 template <typename Number1, typename Number2, typename Unit> |
362 inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit> b) | 397 inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit> b) |
363 -> Quantity<decltype(Number1(1) * Number2(1)), Unit> { | 398 -> Quantity<decltype(Number1() * Number2()), Unit> { |
364 return Quantity<decltype(Number1(1) * Number2(1)), Unit>(a * b.value); | 399 return Quantity<decltype(Number1() * Number2()), Unit>(a * b.value, unsafe); |
365 } | 400 } |
366 | 401 |
367 template <typename Number1, typename Number2, typename Unit, typename Unit2> | 402 template <typename Number1, typename Number2, typename Unit, typename Unit2> |
368 inline constexpr auto operator*(UnitRatio<Number1, Unit2, Unit> ratio, | 403 inline constexpr auto operator*(UnitRatio<Number1, Unit2, Unit> ratio, |
369 Quantity<Number2, Unit> measure) | 404 Quantity<Number2, Unit> measure) |
426 template <typename T> | 461 template <typename T> |
427 inline constexpr T origin() { return T(0 * unit<UnitOf<T>>()); } | 462 inline constexpr T origin() { return T(0 * unit<UnitOf<T>>()); } |
428 // origin<Absolute<T, U>>() returns an Absolute of value 0. It also, intentionally, works on basic | 463 // origin<Absolute<T, U>>() returns an Absolute of value 0. It also, intentionally, works on basic |
429 // numeric types. | 464 // numeric types. |
430 | 465 |
466 // ======================================================================================= | |
467 // Overflow avoidance | |
468 | |
469 template <uint64_t n, uint accum = 0> | |
470 struct BitCount_ { | |
471 static constexpr uint value = BitCount_<(n >> 1), accum + 1>::value; | |
472 }; | |
473 template <uint accum> | |
474 struct BitCount_<0, accum> { | |
475 static constexpr uint value = accum; | |
476 }; | |
477 | |
478 template <uint64_t n> | |
479 inline constexpr uint bitCount() { return BitCount_<n>::value; } | |
480 // Number of bits required to represent the number `n`. | |
481 | |
482 template <uint bitCountBitCount> struct AtLeastUInt_ { | |
483 static_assert(bitCountBitCount < 7, "don't know how to represent integers over 64 bits"); | |
484 }; | |
485 template <> struct AtLeastUInt_<0> { typedef uint8_t Type; }; | |
486 template <> struct AtLeastUInt_<1> { typedef uint8_t Type; }; | |
487 template <> struct AtLeastUInt_<2> { typedef uint8_t Type; }; | |
488 template <> struct AtLeastUInt_<3> { typedef uint8_t Type; }; | |
489 template <> struct AtLeastUInt_<4> { typedef uint16_t Type; }; | |
490 template <> struct AtLeastUInt_<5> { typedef uint32_t Type; }; | |
491 template <> struct AtLeastUInt_<6> { typedef uint64_t Type; }; | |
492 | |
493 template <uint bits> | |
494 using AtLeastUInt = typename AtLeastUInt_<bitCount<max(bits, 1) - 1>()>::Type; | |
495 // AtLeastUInt<n> is an unsigned integer of at least n bits. E.g. AtLeastUInt<12> is uint16_t. | |
496 | |
497 // ------------------------------------------------------------------- | |
498 | |
499 template <uint value> | |
500 class BoundedConst { | |
501 // A constant integer value on which we can do bit size analysis. | |
502 | |
503 public: | |
504 BoundedConst() = default; | |
505 | |
506 inline constexpr uint unwrap() const { return value; } | |
507 | |
508 #define OP(op, check) \ | |
509 template <uint other> \ | |
510 inline constexpr BoundedConst<(value op other)> \ | |
511 operator op(BoundedConst<other>) const { \ | |
512 static_assert(check, "overflow in BoundedConst arithmetic"); \ | |
513 return BoundedConst<(value op other)>(); \ | |
514 } | |
515 #define COMPARE_OP(op) \ | |
516 template <uint other> \ | |
517 inline constexpr bool operator op(BoundedConst<other>) const { \ | |
518 return value op other; \ | |
519 } | |
520 | |
521 OP(+, value + other >= value) | |
522 OP(-, value - other <= value) | |
523 OP(*, value * other / other == value) | |
524 OP(/, true) // div by zero already errors out; no other division ever overflows | |
525 OP(%, true) // mod by zero already errors out; no other modulus ever overflows | |
526 OP(<<, value << other >= value) | |
527 OP(>>, true) // right shift can't overflow | |
528 OP(&, true) // bitwise ops can't overflow | |
529 OP(|, true) // bitwise ops can't overflow | |
530 | |
531 COMPARE_OP(==) | |
532 COMPARE_OP(!=) | |
533 COMPARE_OP(< ) | |
534 COMPARE_OP(> ) | |
535 COMPARE_OP(<=) | |
536 COMPARE_OP(>=) | |
537 #undef OP | |
538 #undef COMPARE_OP | |
539 }; | |
540 | |
541 template <uint64_t m, typename T> | |
542 struct Unit_<Bounded<m, T>> { | |
543 static inline constexpr BoundedConst<1> get() { return BoundedConst<1>(); } | |
544 }; | |
545 | |
546 template <uint value> | |
547 struct Unit_<BoundedConst<value>> { | |
548 static inline constexpr BoundedConst<1> get() { return BoundedConst<1>(); } | |
549 }; | |
550 | |
551 template <uint value> | |
552 inline constexpr BoundedConst<value> bounded() { | |
553 return BoundedConst<value>(); | |
554 } | |
555 | |
556 template <uint64_t a, uint64_t b> | |
557 static constexpr uint64_t boundedAdd() { | |
558 static_assert(a + b >= a, "possible overflow detected"); | |
559 return a + b; | |
560 } | |
561 template <uint64_t a, uint64_t b> | |
562 static constexpr uint64_t boundedSub() { | |
563 static_assert(a - b <= a, "possible underflow detected"); | |
564 return a - b; | |
565 } | |
566 template <uint64_t a, uint64_t b> | |
567 static constexpr uint64_t boundedMul() { | |
568 static_assert(a * b / b == a, "possible overflow detected"); | |
569 return a * b; | |
570 } | |
571 template <uint64_t a, uint64_t b> | |
572 static constexpr uint64_t boundedLShift() { | |
573 static_assert(a << b >= a, "possible overflow detected"); | |
574 return a << b; | |
575 } | |
576 | |
577 template <uint a, uint b> | |
578 inline constexpr BoundedConst<kj::min(a, b)> min(BoundedConst<a>, BoundedConst<b>) { | |
579 return bounded<kj::min(a, b)>(); | |
580 } | |
581 template <uint a, uint b> | |
582 inline constexpr BoundedConst<kj::max(a, b)> max(BoundedConst<a>, BoundedConst<b>) { | |
583 return bounded<kj::max(a, b)>(); | |
584 } | |
585 // We need to override min() and max() between constants because the ternary operator in the | |
586 // default implementation would complain. | |
587 | |
588 // ------------------------------------------------------------------- | |
589 | |
590 template <uint64_t maxN, typename T> | |
591 class Bounded { | |
592 public: | |
593 static_assert(maxN <= T(kj::maxValue), "possible overflow detected"); | |
594 | |
595 Bounded() = default; | |
596 | |
597 Bounded(const Bounded& other) = default; | |
598 template <typename OtherInt, typename = EnableIf<isIntegral<OtherInt>()>> | |
599 inline constexpr Bounded(OtherInt value): value(value) { | |
600 static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); | |
601 } | |
602 template <uint64_t otherMax, typename OtherT> | |
603 inline constexpr Bounded(const Bounded<otherMax, OtherT>& other) | |
604 : value(other.value) { | |
605 static_assert(otherMax <= maxN, "possible overflow detected"); | |
606 } | |
607 template <uint otherValue> | |
608 inline constexpr Bounded(BoundedConst<otherValue>) | |
609 : value(otherValue) { | |
610 static_assert(otherValue <= maxN, "overflow detected"); | |
611 } | |
612 | |
613 Bounded& operator=(const Bounded& other) = default; | |
614 template <typename OtherInt, typename = EnableIf<isIntegral<OtherInt>()>> | |
615 Bounded& operator=(OtherInt other) { | |
616 static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); | |
617 value = other; | |
618 return *this; | |
619 } | |
620 template <uint64_t otherMax, typename OtherT> | |
621 inline Bounded& operator=(const Bounded<otherMax, OtherT>& other) { | |
622 static_assert(otherMax <= maxN, "possible overflow detected"); | |
623 value = other.value; | |
624 return *this; | |
625 } | |
626 template <uint otherValue> | |
627 inline Bounded& operator=(BoundedConst<otherValue>) { | |
628 static_assert(otherValue <= maxN, "overflow detected"); | |
629 value = otherValue; | |
630 return *this; | |
631 } | |
632 | |
633 inline constexpr T unwrap() const { return value; } | |
634 | |
635 #define OP(op, newMax) \ | |
636 template <uint64_t otherMax, typename otherT> \ | |
637 inline constexpr Bounded<newMax, decltype(T() op otherT())> \ | |
638 operator op(const Bounded<otherMax, otherT>& other) const { \ | |
639 return Bounded<newMax, decltype(T() op otherT())>(value op other.value, unsafe); \ | |
640 } | |
641 #define COMPARE_OP(op) \ | |
642 template <uint64_t otherMax, typename OtherT> \ | |
643 inline constexpr bool operator op(const Bounded<otherMax, OtherT>& other) const { \ | |
644 return value op other.value; \ | |
645 } | |
646 | |
647 OP(+, (boundedAdd<maxN, otherMax>())) | |
648 OP(*, (boundedMul<maxN, otherMax>())) | |
649 OP(/, maxN) | |
650 OP(%, otherMax - 1) | |
651 | |
652 // operator- is intentionally omitted because we mostly use this with unsigned types, and | |
653 // subtraction requires proof that subtrahend is not greater than the minuend. | |
654 | |
655 COMPARE_OP(==) | |
656 COMPARE_OP(!=) | |
657 COMPARE_OP(< ) | |
658 COMPARE_OP(> ) | |
659 COMPARE_OP(<=) | |
660 COMPARE_OP(>=) | |
661 | |
662 #undef OP | |
663 #undef COMPARE_OP | |
664 | |
665 template <uint64_t newMax, typename ErrorFunc> | |
666 inline Bounded<newMax, T> assertMax(ErrorFunc&& func) const { | |
667 // Assert that the number is no more than `newMax`. Otherwise, call `func`. | |
668 static_assert(newMax < maxN, "this bounded size assertion is redundant"); | |
669 if (KJ_UNLIKELY(value > newMax)) func(); | |
670 return Bounded<newMax, T>(value, unsafe); | |
671 } | |
672 | |
673 template <uint64_t otherMax, typename OtherT, typename ErrorFunc> | |
674 inline Bounded<maxN, decltype(T() - OtherT())> subtractChecked( | |
675 const Bounded<otherMax, OtherT>& other, ErrorFunc&& func) const { | |
676 // Subtract a number, calling func() if the result would underflow. | |
677 if (KJ_UNLIKELY(value < other.value)) func(); | |
678 return Bounded<maxN, decltype(T() - OtherT())>(value - other.value, unsafe); | |
679 } | |
680 | |
681 template <uint otherValue, typename ErrorFunc> | |
682 inline Bounded<maxN - otherValue, T> subtractChecked( | |
683 BoundedConst<otherValue>, ErrorFunc&& func) const { | |
684 // Subtract a number, calling func() if the result would underflow. | |
685 static_assert(otherValue <= maxN, "underflow detected"); | |
686 if (KJ_UNLIKELY(value < otherValue)) func(); | |
687 return Bounded<maxN - otherValue, T>(value - otherValue, unsafe); | |
688 } | |
689 | |
690 template <uint64_t otherMax, typename OtherT> | |
691 inline Maybe<Bounded<maxN, decltype(T() - OtherT())>> trySubtract( | |
692 const Bounded<otherMax, OtherT>& other) const { | |
693 // Subtract a number, calling func() if the result would underflow. | |
694 if (value < other.value) { | |
695 return nullptr; | |
696 } else { | |
697 return Bounded<maxN, decltype(T() - OtherT())>(value - other.value, unsafe); | |
698 } | |
699 } | |
700 | |
701 template <uint otherValue> | |
702 inline Maybe<Bounded<maxN - otherValue, T>> trySubtract(BoundedConst<otherValue>) const { | |
703 // Subtract a number, calling func() if the result would underflow. | |
704 if (value < otherValue) { | |
705 return nullptr; | |
706 } else { | |
707 return Bounded<maxN - otherValue, T>(value - otherValue, unsafe); | |
708 } | |
709 } | |
710 | |
711 inline constexpr Bounded(T value, decltype(unsafe)): value(value) {} | |
712 template <uint64_t otherMax, typename OtherT> | |
713 inline constexpr Bounded(Bounded<otherMax, OtherT> value, decltype(unsafe)) | |
714 : value(value.value) {} | |
715 // Mainly for internal use. | |
716 // | |
717 // Only use these as a last resort, with ample commentary on why you think it's safe. | |
718 | |
719 private: | |
720 T value; | |
721 | |
722 template <uint64_t, typename> | |
723 friend class Bounded; | |
724 }; | |
725 | |
726 template <typename Number> | |
727 inline constexpr Bounded<Number(kj::maxValue), Number> bounded(Number value) { | |
728 return Bounded<Number(kj::maxValue), Number>(value, unsafe); | |
729 } | |
730 | |
731 inline constexpr Bounded<1, uint8_t> bounded(bool value) { | |
732 return Bounded<1, uint8_t>(value, unsafe); | |
733 } | |
734 | |
735 template <uint bits, typename Number> | |
736 inline constexpr Bounded<maxValueForBits<bits>(), Number> assumeBits(Number value) { | |
737 return Bounded<maxValueForBits<bits>(), Number>(value, unsafe); | |
738 } | |
739 | |
740 template <uint bits, uint64_t maxN, typename T> | |
741 inline constexpr Bounded<maxValueForBits<bits>(), T> assumeBits(Bounded<maxN, T> value) { | |
742 return Bounded<maxValueForBits<bits>(), T>(value, unsafe); | |
743 } | |
744 | |
745 template <uint bits, typename Number, typename Unit> | |
746 inline constexpr auto assumeBits(Quantity<Number, Unit> value) | |
747 -> Quantity<decltype(assumeBits<bits>(value / unit<Quantity<Number, Unit>>())), Unit> { | |
748 return Quantity<decltype(assumeBits<bits>(value / unit<Quantity<Number, Unit>>())), Unit>( | |
749 assumeBits<bits>(value / unit<Quantity<Number, Unit>>()), unsafe); | |
750 } | |
751 | |
752 template <uint64_t maxN, typename Number> | |
753 inline constexpr Bounded<maxN, Number> assumeMax(Number value) { | |
754 return Bounded<maxN, Number>(value, unsafe); | |
755 } | |
756 | |
757 template <uint64_t newMaxN, uint64_t maxN, typename T> | |
758 inline constexpr Bounded<newMaxN, T> assumeMax(Bounded<maxN, T> value) { | |
759 return Bounded<newMaxN, T>(value, unsafe); | |
760 } | |
761 | |
762 template <uint64_t maxN, typename Number, typename Unit> | |
763 inline constexpr auto assumeMax(Quantity<Number, Unit> value) | |
764 -> Quantity<decltype(assumeMax<maxN>(value / unit<Quantity<Number, Unit>>())), Unit> { | |
765 return Quantity<decltype(assumeMax<maxN>(value / unit<Quantity<Number, Unit>>())), Unit>( | |
766 assumeMax<maxN>(value / unit<Quantity<Number, Unit>>()), unsafe); | |
767 } | |
768 | |
769 template <uint maxN, typename Number> | |
770 inline constexpr Bounded<maxN, Number> assumeMax(BoundedConst<maxN>, Number value) { | |
771 return assumeMax<maxN>(value); | |
772 } | |
773 | |
774 template <uint newMaxN, uint64_t maxN, typename T> | |
775 inline constexpr Bounded<newMaxN, T> assumeMax(BoundedConst<maxN>, Bounded<maxN, T> value) { | |
776 return assumeMax<maxN>(value); | |
777 } | |
778 | |
779 template <uint maxN, typename Number, typename Unit> | |
780 inline constexpr auto assumeMax(Quantity<BoundedConst<maxN>, Unit>, Quantity<Number, Unit> value) | |
781 -> decltype(assumeMax<maxN>(value)) { | |
782 return assumeMax<maxN>(value); | |
783 } | |
784 | |
785 template <uint64_t newMax, uint64_t maxN, typename T, typename ErrorFunc> | |
786 inline Bounded<newMax, T> assertMax(Bounded<maxN, T> value, ErrorFunc&& errorFunc) { | |
787 // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() | |
788 // if not. | |
789 static_assert(newMax < maxN, "this bounded size assertion is redundant"); | |
790 return value.template assertMax<newMax>(kj::fwd<ErrorFunc>(errorFunc)); | |
791 } | |
792 | |
793 template <uint64_t newMax, uint64_t maxN, typename T, typename Unit, typename ErrorFunc> | |
794 inline Quantity<Bounded<newMax, T>, Unit> assertMax( | |
795 Quantity<Bounded<maxN, T>, Unit> value, ErrorFunc&& errorFunc) { | |
796 // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() | |
797 // if not. | |
798 static_assert(newMax < maxN, "this bounded size assertion is redundant"); | |
799 return (value / unit<decltype(value)>()).template assertMax<newMax>( | |
800 kj::fwd<ErrorFunc>(errorFunc)) * unit<decltype(value)>(); | |
801 } | |
802 | |
803 template <uint newMax, uint64_t maxN, typename T, typename ErrorFunc> | |
804 inline Bounded<newMax, T> assertMax( | |
805 BoundedConst<newMax>, Bounded<maxN, T> value, ErrorFunc&& errorFunc) { | |
806 return assertMax<newMax>(value, kj::mv(errorFunc)); | |
807 } | |
808 | |
809 template <uint newMax, uint64_t maxN, typename T, typename Unit, typename ErrorFunc> | |
810 inline Quantity<Bounded<newMax, T>, Unit> assertMax( | |
811 Quantity<BoundedConst<newMax>, Unit>, | |
812 Quantity<Bounded<maxN, T>, Unit> value, ErrorFunc&& errorFunc) { | |
813 return assertMax<newMax>(value, kj::mv(errorFunc)); | |
814 } | |
815 | |
816 template <uint64_t newBits, uint64_t maxN, typename T, typename ErrorFunc = ThrowOverflow> | |
817 inline Bounded<maxValueForBits<newBits>(), T> assertMaxBits( | |
818 Bounded<maxN, T> value, ErrorFunc&& errorFunc = ErrorFunc()) { | |
819 // Assert that the bounded value requires no more than the given number of bits, calling | |
820 // errorFunc() if not. | |
821 return assertMax<maxValueForBits<newBits>()>(value, kj::fwd<ErrorFunc>(errorFunc)); | |
822 } | |
823 | |
824 template <uint64_t newBits, uint64_t maxN, typename T, typename Unit, | |
825 typename ErrorFunc = ThrowOverflow> | |
826 inline Quantity<Bounded<maxValueForBits<newBits>(), T>, Unit> assertMaxBits( | |
827 Quantity<Bounded<maxN, T>, Unit> value, ErrorFunc&& errorFunc = ErrorFunc()) { | |
828 // Assert that the bounded value requires no more than the given number of bits, calling | |
829 // errorFunc() if not. | |
830 return assertMax<maxValueForBits<newBits>()>(value, kj::fwd<ErrorFunc>(errorFunc)); | |
831 } | |
832 | |
833 template <typename newT, uint64_t maxN, typename T> | |
834 inline constexpr Bounded<maxN, newT> upgradeBound(Bounded<maxN, T> value) { | |
835 return value; | |
836 } | |
837 | |
838 template <typename newT, uint64_t maxN, typename T, typename Unit> | |
839 inline constexpr Quantity<Bounded<maxN, newT>, Unit> upgradeBound( | |
840 Quantity<Bounded<maxN, T>, Unit> value) { | |
841 return value; | |
842 } | |
843 | |
844 template <uint64_t maxN, typename T, typename Other, typename ErrorFunc> | |
845 inline auto subtractChecked(Bounded<maxN, T> value, Other other, ErrorFunc&& errorFunc) | |
846 -> decltype(value.subtractChecked(other, kj::fwd<ErrorFunc>(errorFunc))) { | |
847 return value.subtractChecked(other, kj::fwd<ErrorFunc>(errorFunc)); | |
848 } | |
849 | |
850 template <typename T, typename U, typename Unit, typename ErrorFunc> | |
851 inline auto subtractChecked(Quantity<T, Unit> value, Quantity<U, Unit> other, ErrorFunc&& errorFunc) | |
852 -> Quantity<decltype(subtractChecked(T(), U(), kj::fwd<ErrorFunc>(errorFunc))), Unit> { | |
853 return subtractChecked(value / unit<Quantity<T, Unit>>(), | |
854 other / unit<Quantity<U, Unit>>(), | |
855 kj::fwd<ErrorFunc>(errorFunc)) | |
856 * unit<Quantity<T, Unit>>(); | |
857 } | |
858 | |
859 template <uint64_t maxN, typename T, typename Other> | |
860 inline auto trySubtract(Bounded<maxN, T> value, Other other) | |
861 -> decltype(value.trySubtract(other)) { | |
862 return value.trySubtract(other); | |
863 } | |
864 | |
865 template <typename T, typename U, typename Unit> | |
866 inline auto trySubtract(Quantity<T, Unit> value, Quantity<U, Unit> other) | |
867 -> Maybe<Quantity<decltype(subtractChecked(T(), U(), int())), Unit>> { | |
868 return trySubtract(value / unit<Quantity<T, Unit>>(), | |
869 other / unit<Quantity<U, Unit>>()) | |
870 .map([](decltype(subtractChecked(T(), U(), int())) x) { | |
871 return x * unit<Quantity<T, Unit>>(); | |
872 }); | |
873 } | |
874 | |
875 template <uint64_t aN, uint64_t bN, typename A, typename B> | |
876 inline constexpr Bounded<kj::min(aN, bN), WiderType<A, B>> | |
877 min(Bounded<aN, A> a, Bounded<bN, B> b) { | |
878 return Bounded<kj::min(aN, bN), WiderType<A, B>>(kj::min(a.unwrap(), b.unwrap()), unsafe); | |
879 } | |
880 template <uint64_t aN, uint64_t bN, typename A, typename B> | |
881 inline constexpr Bounded<kj::max(aN, bN), WiderType<A, B>> | |
882 max(Bounded<aN, A> a, Bounded<bN, B> b) { | |
883 return Bounded<kj::max(aN, bN), WiderType<A, B>>(kj::max(a.unwrap(), b.unwrap()), unsafe); | |
884 } | |
885 // We need to override min() and max() because: | |
886 // 1) WiderType<> might not choose the correct bounds. | |
887 // 2) One of the two sides of the ternary operator in the default implementation would fail to | |
888 // typecheck even though it is OK in practice. | |
889 | |
890 // ------------------------------------------------------------------- | |
891 // Operators between Bounded and BoundedConst | |
892 | |
893 #define OP(op, newMax) \ | |
894 template <uint64_t maxN, uint cvalue, typename T> \ | |
895 inline constexpr Bounded<(newMax), decltype(T() op uint())> operator op( \ | |
896 Bounded<maxN, T> value, BoundedConst<cvalue>) { \ | |
897 return Bounded<(newMax), decltype(T() op uint())>(value.unwrap() op cvalue, unsafe); \ | |
898 } | |
899 | |
900 #define REVERSE_OP(op, newMax) \ | |
901 template <uint64_t maxN, uint cvalue, typename T> \ | |
902 inline constexpr Bounded<(newMax), decltype(uint() op T())> operator op( \ | |
903 BoundedConst<cvalue>, Bounded<maxN, T> value) { \ | |
904 return Bounded<(newMax), decltype(uint() op T())>(cvalue op value.unwrap(), unsafe); \ | |
905 } | |
906 | |
907 #define COMPARE_OP(op) \ | |
908 template <uint64_t maxN, uint cvalue, typename T> \ | |
909 inline constexpr bool operator op(Bounded<maxN, T> value, BoundedConst<cvalue>) { \ | |
910 return value.unwrap() op cvalue; \ | |
911 } \ | |
912 template <uint64_t maxN, uint cvalue, typename T> \ | |
913 inline constexpr bool operator op(BoundedConst<cvalue>, Bounded<maxN, T> value) { \ | |
914 return cvalue op value.unwrap(); \ | |
915 } | |
916 | |
917 OP(+, (boundedAdd<maxN, cvalue>())) | |
918 REVERSE_OP(+, (boundedAdd<maxN, cvalue>())) | |
919 | |
920 OP(*, (boundedMul<maxN, cvalue>())) | |
921 REVERSE_OP(*, (boundedAdd<maxN, cvalue>())) | |
922 | |
923 OP(/, maxN / cvalue) | |
924 REVERSE_OP(/, cvalue) // denominator could be 1 | |
925 | |
926 OP(%, cvalue - 1) | |
927 REVERSE_OP(%, maxN - 1) | |
928 | |
929 OP(<<, (boundedLShift<maxN, cvalue>())) | |
930 REVERSE_OP(<<, (boundedLShift<cvalue, maxN>())) | |
931 | |
932 OP(>>, maxN >> cvalue) | |
933 REVERSE_OP(>>, cvalue >> maxN) | |
934 | |
935 OP(&, maxValueForBits<bitCount<maxN>()>() & cvalue) | |
936 REVERSE_OP(&, maxValueForBits<bitCount<maxN>()>() & cvalue) | |
937 | |
938 OP(|, maxN | cvalue) | |
939 REVERSE_OP(|, maxN | cvalue) | |
940 | |
941 COMPARE_OP(==) | |
942 COMPARE_OP(!=) | |
943 COMPARE_OP(< ) | |
944 COMPARE_OP(> ) | |
945 COMPARE_OP(<=) | |
946 COMPARE_OP(>=) | |
947 | |
948 #undef OP | |
949 #undef REVERSE_OP | |
950 #undef COMPARE_OP | |
951 | |
952 template <uint64_t maxN, uint cvalue, typename T> | |
953 inline constexpr Bounded<cvalue, decltype(uint() - T())> | |
954 operator-(BoundedConst<cvalue>, Bounded<maxN, T> value) { | |
955 // We allow subtraction of a variable from a constant only if the constant is greater than or | |
956 // equal to the maximum possible value of the variable. Since the variable could be zero, the | |
957 // result can be as large as the constant. | |
958 // | |
959 // We do not allow subtraction of a constant from a variable because there's never a guarantee it | |
960 // won't underflow (unless the constant is zero, which is silly). | |
961 static_assert(cvalue >= maxN, "possible underflow detected"); | |
962 return Bounded<cvalue, decltype(uint() - T())>(cvalue - value.unwrap(), unsafe); | |
963 } | |
964 | |
965 template <uint64_t aN, uint b, typename A> | |
966 inline constexpr Bounded<kj::min(aN, b), A> min(Bounded<aN, A> a, BoundedConst<b>) { | |
967 return Bounded<kj::min(aN, b), A>(kj::min(b, a.unwrap()), unsafe); | |
968 } | |
969 template <uint64_t aN, uint b, typename A> | |
970 inline constexpr Bounded<kj::min(aN, b), A> min(BoundedConst<b>, Bounded<aN, A> a) { | |
971 return Bounded<kj::min(aN, b), A>(kj::min(a.unwrap(), b), unsafe); | |
972 } | |
973 template <uint64_t aN, uint b, typename A> | |
974 inline constexpr Bounded<kj::max(aN, b), A> max(Bounded<aN, A> a, BoundedConst<b>) { | |
975 return Bounded<kj::max(aN, b), A>(kj::max(b, a.unwrap()), unsafe); | |
976 } | |
977 template <uint64_t aN, uint b, typename A> | |
978 inline constexpr Bounded<kj::max(aN, b), A> max(BoundedConst<b>, Bounded<aN, A> a) { | |
979 return Bounded<kj::max(aN, b), A>(kj::max(a.unwrap(), b), unsafe); | |
980 } | |
981 // We need to override min() between a Bounded and a constant since: | |
982 // 1) WiderType<> might choose BoundedConst over a 1-byte Bounded, which is wrong. | |
983 // 2) To clamp the bounds of the output type. | |
984 // 3) Same ternary operator typechecking issues. | |
985 | |
986 // ------------------------------------------------------------------- | |
987 | |
988 template <uint64_t maxN, typename T> | |
989 class SafeUnwrapper { | |
990 public: | |
991 inline explicit constexpr SafeUnwrapper(Bounded<maxN, T> value): value(value.unwrap()) {} | |
992 | |
993 template <typename U, typename = EnableIf<isIntegral<U>()>> | |
994 inline constexpr operator U() const { | |
995 static_assert(maxN <= U(maxValue), "possible truncation detected"); | |
996 return value; | |
997 } | |
998 | |
999 inline constexpr operator bool() const { | |
1000 static_assert(maxN <= 1, "possible truncation detected"); | |
1001 return value; | |
1002 } | |
1003 | |
1004 private: | |
1005 T value; | |
1006 }; | |
1007 | |
1008 template <uint64_t maxN, typename T> | |
1009 inline constexpr SafeUnwrapper<maxN, T> unbound(Bounded<maxN, T> bounded) { | |
1010 // Unwraps the bounded value, returning a value that can be implicitly cast to any integer type. | |
1011 // If this implicit cast could truncate, a compile-time error will be raised. | |
1012 return SafeUnwrapper<maxN, T>(bounded); | |
1013 } | |
1014 | |
1015 template <uint64_t value> | |
1016 class SafeConstUnwrapper { | |
1017 public: | |
1018 template <typename T, typename = EnableIf<isIntegral<T>()>> | |
1019 inline constexpr operator T() const { | |
1020 static_assert(value <= T(maxValue), "this operation will truncate"); | |
1021 return value; | |
1022 } | |
1023 | |
1024 inline constexpr operator bool() const { | |
1025 static_assert(value <= 1, "this operation will truncate"); | |
1026 return value; | |
1027 } | |
1028 }; | |
1029 | |
1030 template <uint value> | |
1031 inline constexpr SafeConstUnwrapper<value> unbound(BoundedConst<value>) { | |
1032 return SafeConstUnwrapper<value>(); | |
1033 } | |
1034 | |
1035 template <typename T, typename U> | |
1036 inline constexpr T unboundAs(U value) { | |
1037 return unbound(value); | |
1038 } | |
1039 | |
1040 template <uint64_t requestedMax, uint64_t maxN, typename T> | |
1041 inline constexpr T unboundMax(Bounded<maxN, T> value) { | |
1042 // Explicitly ungaurd expecting a value that is at most `maxN`. | |
1043 static_assert(maxN <= requestedMax, "possible overflow detected"); | |
1044 return value.unwrap(); | |
1045 } | |
1046 | |
1047 template <uint64_t requestedMax, uint value> | |
1048 inline constexpr uint unboundMax(BoundedConst<value>) { | |
1049 // Explicitly ungaurd expecting a value that is at most `maxN`. | |
1050 static_assert(value <= requestedMax, "overflow detected"); | |
1051 return value; | |
1052 } | |
1053 | |
1054 template <uint bits, typename T> | |
1055 inline constexpr auto unboundMaxBits(T value) -> | |
1056 decltype(unboundMax<maxValueForBits<bits>()>(value)) { | |
1057 // Explicitly ungaurd expecting a value that fits into `bits` bits. | |
1058 return unboundMax<maxValueForBits<bits>()>(value); | |
1059 } | |
1060 | |
1061 #define OP(op) \ | |
1062 template <uint64_t maxN, typename T, typename U> \ | |
1063 inline constexpr auto operator op(T a, SafeUnwrapper<maxN, U> b) -> decltype(a op (T)b) { \ | |
1064 return a op (AtLeastUInt<sizeof(T)*8>)b; \ | |
1065 } \ | |
1066 template <uint64_t maxN, typename T, typename U> \ | |
1067 inline constexpr auto operator op(SafeUnwrapper<maxN, U> b, T a) -> decltype((T)b op a) { \ | |
1068 return (AtLeastUInt<sizeof(T)*8>)b op a; \ | |
1069 } \ | |
1070 template <uint64_t value, typename T> \ | |
1071 inline constexpr auto operator op(T a, SafeConstUnwrapper<value> b) -> decltype(a op (T)b) { \ | |
1072 return a op (AtLeastUInt<sizeof(T)*8>)b; \ | |
1073 } \ | |
1074 template <uint64_t value, typename T> \ | |
1075 inline constexpr auto operator op(SafeConstUnwrapper<value> b, T a) -> decltype((T)b op a) { \ | |
1076 return (AtLeastUInt<sizeof(T)*8>)b op a; \ | |
1077 } | |
1078 | |
1079 OP(+) | |
1080 OP(-) | |
1081 OP(*) | |
1082 OP(/) | |
1083 OP(%) | |
1084 OP(<<) | |
1085 OP(>>) | |
1086 OP(&) | |
1087 OP(|) | |
1088 OP(==) | |
1089 OP(!=) | |
1090 OP(<=) | |
1091 OP(>=) | |
1092 OP(<) | |
1093 OP(>) | |
1094 | |
1095 #undef OP | |
1096 | |
1097 // ------------------------------------------------------------------- | |
1098 | |
1099 template <uint64_t maxN, typename T> | |
1100 class Range<Bounded<maxN, T>> { | |
1101 public: | |
1102 inline constexpr Range(Bounded<maxN, T> begin, Bounded<maxN, T> end) | |
1103 : inner(unbound(begin), unbound(end)) {} | |
1104 inline explicit constexpr Range(Bounded<maxN, T> end) | |
1105 : inner(unbound(end)) {} | |
1106 | |
1107 class Iterator { | |
1108 public: | |
1109 Iterator() = default; | |
1110 inline explicit Iterator(typename Range<T>::Iterator inner): inner(inner) {} | |
1111 | |
1112 inline Bounded<maxN, T> operator* () const { return Bounded<maxN, T>(*inner, unsafe); } | |
1113 inline Iterator& operator++() { ++inner; return *this; } | |
1114 | |
1115 inline bool operator==(const Iterator& other) const { return inner == other.inner; } | |
1116 inline bool operator!=(const Iterator& other) const { return inner != other.inner; } | |
1117 | |
1118 private: | |
1119 typename Range<T>::Iterator inner; | |
1120 }; | |
1121 | |
1122 inline Iterator begin() const { return Iterator(inner.begin()); } | |
1123 inline Iterator end() const { return Iterator(inner.end()); } | |
1124 | |
1125 private: | |
1126 Range<T> inner; | |
1127 }; | |
1128 | |
1129 template <typename T, typename U> | |
1130 class Range<Quantity<T, U>> { | |
1131 public: | |
1132 inline constexpr Range(Quantity<T, U> begin, Quantity<T, U> end) | |
1133 : inner(begin / unit<Quantity<T, U>>(), end / unit<Quantity<T, U>>()) {} | |
1134 inline explicit constexpr Range(Quantity<T, U> end) | |
1135 : inner(end / unit<Quantity<T, U>>()) {} | |
1136 | |
1137 class Iterator { | |
1138 public: | |
1139 Iterator() = default; | |
1140 inline explicit Iterator(typename Range<T>::Iterator inner): inner(inner) {} | |
1141 | |
1142 inline Quantity<T, U> operator* () const { return *inner * unit<Quantity<T, U>>(); } | |
1143 inline Iterator& operator++() { ++inner; return *this; } | |
1144 | |
1145 inline bool operator==(const Iterator& other) const { return inner == other.inner; } | |
1146 inline bool operator!=(const Iterator& other) const { return inner != other.inner; } | |
1147 | |
1148 private: | |
1149 typename Range<T>::Iterator inner; | |
1150 }; | |
1151 | |
1152 inline Iterator begin() const { return Iterator(inner.begin()); } | |
1153 inline Iterator end() const { return Iterator(inner.end()); } | |
1154 | |
1155 private: | |
1156 Range<T> inner; | |
1157 }; | |
1158 | |
1159 template <uint value> | |
1160 inline constexpr Range<Bounded<value, uint>> zeroTo(BoundedConst<value> end) { | |
1161 return Range<Bounded<value, uint>>(end); | |
1162 } | |
1163 | |
1164 template <uint value, typename Unit> | |
1165 inline constexpr Range<Quantity<Bounded<value, uint>, Unit>> | |
1166 zeroTo(Quantity<BoundedConst<value>, Unit> end) { | |
1167 return Range<Quantity<Bounded<value, uint>, Unit>>(end); | |
1168 } | |
1169 | |
431 } // namespace kj | 1170 } // namespace kj |
432 | 1171 |
433 #endif // KJ_UNITS_H_ | 1172 #endif // KJ_UNITS_H_ |