Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/units.h @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 // This file contains types which are intended to help detect incorrect usage at compile | |
23 // time, but should then be optimized down to basic primitives (usually, integers) by the | |
24 // compiler. | |
25 | |
26 #pragma once | |
27 | |
28 #include "common.h" | |
29 #include <inttypes.h> | |
30 | |
31 KJ_BEGIN_HEADER | |
32 | |
33 namespace kj { | |
34 | |
35 // ======================================================================================= | |
36 // IDs | |
37 | |
38 template <typename UnderlyingType, typename Label> | |
39 struct Id { | |
40 // A type-safe numeric ID. `UnderlyingType` is the underlying integer representation. `Label` | |
41 // distinguishes this Id from other Id types. Sample usage: | |
42 // | |
43 // class Foo; | |
44 // typedef Id<uint, Foo> FooId; | |
45 // | |
46 // class Bar; | |
47 // typedef Id<uint, Bar> BarId; | |
48 // | |
49 // You can now use the FooId and BarId types without any possibility of accidentally using a | |
50 // FooId when you really wanted a BarId or vice-versa. | |
51 | |
52 UnderlyingType value; | |
53 | |
54 inline constexpr Id(): value(0) {} | |
55 inline constexpr explicit Id(int value): value(value) {} | |
56 | |
57 inline constexpr bool operator==(const Id& other) const { return value == other.value; } | |
58 inline constexpr bool operator!=(const Id& other) const { return value != other.value; } | |
59 inline constexpr bool operator<=(const Id& other) const { return value <= other.value; } | |
60 inline constexpr bool operator>=(const Id& other) const { return value >= other.value; } | |
61 inline constexpr bool operator< (const Id& other) const { return value < other.value; } | |
62 inline constexpr bool operator> (const Id& other) const { return value > other.value; } | |
63 }; | |
64 | |
65 // ======================================================================================= | |
66 // Quantity and UnitRatio -- implement unit analysis via the type system | |
67 | |
68 struct Unsafe_ {}; | |
69 constexpr Unsafe_ unsafe = Unsafe_(); | |
70 // Use as a parameter to constructors that are unsafe to indicate that you really do mean it. | |
71 | |
72 template <uint64_t maxN, typename T> | |
73 class Bounded; | |
74 template <uint value> | |
75 class BoundedConst; | |
76 | |
77 template <typename T> | |
78 struct IsIntegralOrBounded_ { static constexpr bool value = isIntegral<T>(); }; | |
79 template <uint64_t m, typename T> | |
80 struct IsIntegralOrBounded_<Bounded<m, T>> { static constexpr bool value = true; }; | |
81 template <uint v> | |
82 struct IsIntegralOrBounded_<BoundedConst<v>> { static constexpr bool value = true; }; | |
83 | |
84 template <typename T> | |
85 inline constexpr bool isIntegralOrBounded() { return IsIntegralOrBounded_<T>::value; } | |
86 | |
87 template <typename Number, typename Unit1, typename Unit2> | |
88 class UnitRatio { | |
89 // A multiplier used to convert Quantities of one unit to Quantities of another unit. See | |
90 // Quantity, below. | |
91 // | |
92 // Construct this type by dividing one Quantity by another of a different unit. Use this type | |
93 // by multiplying it by a Quantity, or dividing a Quantity by it. | |
94 | |
95 static_assert(isIntegralOrBounded<Number>(), | |
96 "Underlying type for UnitRatio must be integer."); | |
97 | |
98 public: | |
99 inline UnitRatio() {} | |
100 | |
101 constexpr UnitRatio(Number unit1PerUnit2, decltype(unsafe)): unit1PerUnit2(unit1PerUnit2) {} | |
102 // This constructor was intended to be private, but GCC complains about it being private in a | |
103 // bunch of places that don't appear to even call it, so I made it public. Oh well. | |
104 | |
105 template <typename OtherNumber> | |
106 inline constexpr UnitRatio(const UnitRatio<OtherNumber, Unit1, Unit2>& other) | |
107 : unit1PerUnit2(other.unit1PerUnit2) {} | |
108 | |
109 template <typename OtherNumber> | |
110 inline constexpr UnitRatio<decltype(Number()+OtherNumber()), Unit1, Unit2> | |
111 operator+(UnitRatio<OtherNumber, Unit1, Unit2> other) const { | |
112 return UnitRatio<decltype(Number()+OtherNumber()), Unit1, Unit2>( | |
113 unit1PerUnit2 + other.unit1PerUnit2, unsafe); | |
114 } | |
115 template <typename OtherNumber> | |
116 inline constexpr UnitRatio<decltype(Number()-OtherNumber()), Unit1, Unit2> | |
117 operator-(UnitRatio<OtherNumber, Unit1, Unit2> other) const { | |
118 return UnitRatio<decltype(Number()-OtherNumber()), Unit1, Unit2>( | |
119 unit1PerUnit2 - other.unit1PerUnit2, unsafe); | |
120 } | |
121 | |
122 template <typename OtherNumber, typename Unit3> | |
123 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2> | |
124 operator*(UnitRatio<OtherNumber, Unit3, Unit1> other) const { | |
125 // U1 / U2 * U3 / U1 = U3 / U2 | |
126 return UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2>( | |
127 unit1PerUnit2 * other.unit1PerUnit2, unsafe); | |
128 } | |
129 template <typename OtherNumber, typename Unit3> | |
130 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3> | |
131 operator*(UnitRatio<OtherNumber, Unit2, Unit3> other) const { | |
132 // U1 / U2 * U2 / U3 = U1 / U3 | |
133 return UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3>( | |
134 unit1PerUnit2 * other.unit1PerUnit2, unsafe); | |
135 } | |
136 | |
137 template <typename OtherNumber, typename Unit3> | |
138 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2> | |
139 operator/(UnitRatio<OtherNumber, Unit1, Unit3> other) const { | |
140 // (U1 / U2) / (U1 / U3) = U3 / U2 | |
141 return UnitRatio<decltype(Number()*OtherNumber()), Unit3, Unit2>( | |
142 unit1PerUnit2 / other.unit1PerUnit2, unsafe); | |
143 } | |
144 template <typename OtherNumber, typename Unit3> | |
145 inline constexpr UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3> | |
146 operator/(UnitRatio<OtherNumber, Unit3, Unit2> other) const { | |
147 // (U1 / U2) / (U3 / U2) = U1 / U3 | |
148 return UnitRatio<decltype(Number()*OtherNumber()), Unit1, Unit3>( | |
149 unit1PerUnit2 / other.unit1PerUnit2, unsafe); | |
150 } | |
151 | |
152 template <typename OtherNumber> | |
153 inline decltype(Number() / OtherNumber()) | |
154 operator/(UnitRatio<OtherNumber, Unit1, Unit2> other) const { | |
155 return unit1PerUnit2 / other.unit1PerUnit2; | |
156 } | |
157 | |
158 template <typename OtherNumber> | |
159 inline constexpr bool operator==(const UnitRatio<OtherNumber, Unit1, Unit2>& other) const { | |
160 return unit1PerUnit2 == other.unit1PerUnit2; | |
161 } | |
162 template <typename OtherNumber> | |
163 inline constexpr bool operator!=(const UnitRatio<OtherNumber, Unit1, Unit2>& other) const { | |
164 return unit1PerUnit2 != other.unit1PerUnit2; | |
165 } | |
166 | |
167 private: | |
168 Number unit1PerUnit2; | |
169 | |
170 template <typename OtherNumber, typename OtherUnit> | |
171 friend class Quantity; | |
172 template <typename OtherNumber, typename OtherUnit1, typename OtherUnit2> | |
173 friend class UnitRatio; | |
174 | |
175 template <typename N1, typename N2, typename U1, typename U2, typename> | |
176 friend inline constexpr UnitRatio<decltype(N1() * N2()), U1, U2> | |
177 operator*(N1, UnitRatio<N2, U1, U2>); | |
178 }; | |
179 | |
180 template <typename N1, typename N2, typename U1, typename U2, | |
181 typename = EnableIf<isIntegralOrBounded<N1>() && isIntegralOrBounded<N2>()>> | |
182 inline constexpr UnitRatio<decltype(N1() * N2()), U1, U2> | |
183 operator*(N1 n, UnitRatio<N2, U1, U2> r) { | |
184 return UnitRatio<decltype(N1() * N2()), U1, U2>(n * r.unit1PerUnit2, unsafe); | |
185 } | |
186 | |
187 template <typename Number, typename Unit> | |
188 class Quantity { | |
189 // A type-safe numeric quantity, specified in terms of some unit. Two Quantities cannot be used | |
190 // in arithmetic unless they use the same unit. The `Unit` type parameter is only used to prevent | |
191 // accidental mixing of units; this type is never instantiated and can very well be incomplete. | |
192 // `Number` is the underlying primitive numeric type. | |
193 // | |
194 // Quantities support most basic arithmetic operators, intelligently handling units, and | |
195 // automatically casting the underlying type in the same way that the compiler would. | |
196 // | |
197 // To convert a primitive number to a Quantity, multiply it by unit<Quantity<N, U>>(). | |
198 // To convert a Quantity to a primitive number, divide it by unit<Quantity<N, U>>(). | |
199 // To convert a Quantity of one unit to another unit, multiply or divide by a UnitRatio. | |
200 // | |
201 // The Quantity class is not well-suited to hardcore physics as it does not allow multiplying | |
202 // one quantity by another. For example, multiplying meters by meters won't get you square | |
203 // meters; it will get you a compiler error. It would be interesting to see if template | |
204 // metaprogramming could properly deal with such things but this isn't needed for the present | |
205 // use case. | |
206 // | |
207 // Sample usage: | |
208 // | |
209 // class SecondsLabel; | |
210 // typedef Quantity<double, SecondsLabel> Seconds; | |
211 // constexpr Seconds SECONDS = unit<Seconds>(); | |
212 // | |
213 // class MinutesLabel; | |
214 // typedef Quantity<double, MinutesLabel> Minutes; | |
215 // constexpr Minutes MINUTES = unit<Minutes>(); | |
216 // | |
217 // constexpr UnitRatio<double, SecondsLabel, MinutesLabel> SECONDS_PER_MINUTE = | |
218 // 60 * SECONDS / MINUTES; | |
219 // | |
220 // void waitFor(Seconds seconds) { | |
221 // sleep(seconds / SECONDS); | |
222 // } | |
223 // void waitFor(Minutes minutes) { | |
224 // waitFor(minutes * SECONDS_PER_MINUTE); | |
225 // } | |
226 // | |
227 // void waitThreeMinutes() { | |
228 // waitFor(3 * MINUTES); | |
229 // } | |
230 | |
231 static_assert(isIntegralOrBounded<Number>(), | |
232 "Underlying type for Quantity must be integer."); | |
233 | |
234 public: | |
235 inline constexpr Quantity() = default; | |
236 | |
237 inline constexpr Quantity(MaxValue_): value(maxValue) {} | |
238 inline constexpr Quantity(MinValue_): value(minValue) {} | |
239 // Allow initialization from maxValue and minValue. | |
240 // TODO(msvc): decltype(maxValue) and decltype(minValue) deduce unknown-type for these function | |
241 // parameters, causing the compiler to complain of a duplicate constructor definition, so we | |
242 // specify MaxValue_ and MinValue_ types explicitly. | |
243 | |
244 inline constexpr Quantity(Number value, decltype(unsafe)): value(value) {} | |
245 // This constructor was intended to be private, but GCC complains about it being private in a | |
246 // bunch of places that don't appear to even call it, so I made it public. Oh well. | |
247 | |
248 template <typename OtherNumber> | |
249 inline constexpr Quantity(const Quantity<OtherNumber, Unit>& other) | |
250 : value(other.value) {} | |
251 | |
252 template <typename OtherNumber> | |
253 inline Quantity& operator=(const Quantity<OtherNumber, Unit>& other) { | |
254 value = other.value; | |
255 return *this; | |
256 } | |
257 | |
258 template <typename OtherNumber> | |
259 inline constexpr Quantity<decltype(Number() + OtherNumber()), Unit> | |
260 operator+(const Quantity<OtherNumber, Unit>& other) const { | |
261 return Quantity<decltype(Number() + OtherNumber()), Unit>(value + other.value, unsafe); | |
262 } | |
263 template <typename OtherNumber> | |
264 inline constexpr Quantity<decltype(Number() - OtherNumber()), Unit> | |
265 operator-(const Quantity<OtherNumber, Unit>& other) const { | |
266 return Quantity<decltype(Number() - OtherNumber()), Unit>(value - other.value, unsafe); | |
267 } | |
268 template <typename OtherNumber, typename = EnableIf<isIntegralOrBounded<OtherNumber>()>> | |
269 inline constexpr Quantity<decltype(Number() * OtherNumber()), Unit> | |
270 operator*(OtherNumber other) const { | |
271 return Quantity<decltype(Number() * other), Unit>(value * other, unsafe); | |
272 } | |
273 template <typename OtherNumber, typename = EnableIf<isIntegralOrBounded<OtherNumber>()>> | |
274 inline constexpr Quantity<decltype(Number() / OtherNumber()), Unit> | |
275 operator/(OtherNumber other) const { | |
276 return Quantity<decltype(Number() / other), Unit>(value / other, unsafe); | |
277 } | |
278 template <typename OtherNumber> | |
279 inline constexpr decltype(Number() / OtherNumber()) | |
280 operator/(const Quantity<OtherNumber, Unit>& other) const { | |
281 return value / other.value; | |
282 } | |
283 template <typename OtherNumber> | |
284 inline constexpr Quantity<decltype(Number() % OtherNumber()), Unit> | |
285 operator%(const Quantity<OtherNumber, Unit>& other) const { | |
286 return Quantity<decltype(Number() % OtherNumber()), Unit>(value % other.value, unsafe); | |
287 } | |
288 | |
289 template <typename OtherNumber, typename OtherUnit> | |
290 inline constexpr Quantity<decltype(Number() * OtherNumber()), OtherUnit> | |
291 operator*(UnitRatio<OtherNumber, OtherUnit, Unit> ratio) const { | |
292 return Quantity<decltype(Number() * OtherNumber()), OtherUnit>( | |
293 value * ratio.unit1PerUnit2, unsafe); | |
294 } | |
295 template <typename OtherNumber, typename OtherUnit> | |
296 inline constexpr Quantity<decltype(Number() / OtherNumber()), OtherUnit> | |
297 operator/(UnitRatio<OtherNumber, Unit, OtherUnit> ratio) const { | |
298 return Quantity<decltype(Number() / OtherNumber()), OtherUnit>( | |
299 value / ratio.unit1PerUnit2, unsafe); | |
300 } | |
301 template <typename OtherNumber, typename OtherUnit> | |
302 inline constexpr Quantity<decltype(Number() % OtherNumber()), Unit> | |
303 operator%(UnitRatio<OtherNumber, Unit, OtherUnit> ratio) const { | |
304 return Quantity<decltype(Number() % OtherNumber()), Unit>( | |
305 value % ratio.unit1PerUnit2, unsafe); | |
306 } | |
307 template <typename OtherNumber, typename OtherUnit> | |
308 inline constexpr UnitRatio<decltype(Number() / OtherNumber()), Unit, OtherUnit> | |
309 operator/(Quantity<OtherNumber, OtherUnit> other) const { | |
310 return UnitRatio<decltype(Number() / OtherNumber()), Unit, OtherUnit>( | |
311 value / other.value, unsafe); | |
312 } | |
313 | |
314 template <typename OtherNumber> | |
315 inline constexpr bool operator==(const Quantity<OtherNumber, Unit>& other) const { | |
316 return value == other.value; | |
317 } | |
318 template <typename OtherNumber> | |
319 inline constexpr bool operator!=(const Quantity<OtherNumber, Unit>& other) const { | |
320 return value != other.value; | |
321 } | |
322 template <typename OtherNumber> | |
323 inline constexpr bool operator<=(const Quantity<OtherNumber, Unit>& other) const { | |
324 return value <= other.value; | |
325 } | |
326 template <typename OtherNumber> | |
327 inline constexpr bool operator>=(const Quantity<OtherNumber, Unit>& other) const { | |
328 return value >= other.value; | |
329 } | |
330 template <typename OtherNumber> | |
331 inline constexpr bool operator<(const Quantity<OtherNumber, Unit>& other) const { | |
332 return value < other.value; | |
333 } | |
334 template <typename OtherNumber> | |
335 inline constexpr bool operator>(const Quantity<OtherNumber, Unit>& other) const { | |
336 return value > other.value; | |
337 } | |
338 | |
339 template <typename OtherNumber> | |
340 inline Quantity& operator+=(const Quantity<OtherNumber, Unit>& other) { | |
341 value += other.value; | |
342 return *this; | |
343 } | |
344 template <typename OtherNumber> | |
345 inline Quantity& operator-=(const Quantity<OtherNumber, Unit>& other) { | |
346 value -= other.value; | |
347 return *this; | |
348 } | |
349 template <typename OtherNumber> | |
350 inline Quantity& operator*=(OtherNumber other) { | |
351 value *= other; | |
352 return *this; | |
353 } | |
354 template <typename OtherNumber> | |
355 inline Quantity& operator/=(OtherNumber other) { | |
356 value /= other.value; | |
357 return *this; | |
358 } | |
359 | |
360 private: | |
361 Number value; | |
362 | |
363 template <typename OtherNumber, typename OtherUnit> | |
364 friend class Quantity; | |
365 | |
366 template <typename Number1, typename Number2, typename Unit2, typename> | |
367 friend inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit2> b) | |
368 -> Quantity<decltype(Number1() * Number2()), Unit2>; | |
369 }; | |
370 | |
371 template <typename T> struct Unit_ { | |
372 static inline constexpr T get() { return T(1); } | |
373 }; | |
374 template <typename T, typename U> | |
375 struct Unit_<Quantity<T, U>> { | |
376 static inline constexpr Quantity<decltype(Unit_<T>::get()), U> get() { | |
377 return Quantity<decltype(Unit_<T>::get()), U>(Unit_<T>::get(), unsafe); | |
378 } | |
379 }; | |
380 | |
381 template <typename T> | |
382 inline constexpr auto unit() -> decltype(Unit_<T>::get()) { return Unit_<T>::get(); } | |
383 // unit<Quantity<T, U>>() returns a Quantity of value 1. It also, intentionally, works on basic | |
384 // numeric types. | |
385 | |
386 template <typename Number1, typename Number2, typename Unit, | |
387 typename = EnableIf<isIntegralOrBounded<Number1>()>> | |
388 inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit> b) | |
389 -> Quantity<decltype(Number1() * Number2()), Unit> { | |
390 return Quantity<decltype(Number1() * Number2()), Unit>(a * b.value, unsafe); | |
391 } | |
392 | |
393 template <typename Number1, typename Number2, typename Unit, typename Unit2> | |
394 inline constexpr auto operator*(UnitRatio<Number1, Unit2, Unit> ratio, | |
395 Quantity<Number2, Unit> measure) | |
396 -> decltype(measure * ratio) { | |
397 return measure * ratio; | |
398 } | |
399 | |
400 // ======================================================================================= | |
401 // Absolute measures | |
402 | |
403 template <typename T, typename Label> | |
404 class Absolute { | |
405 // Wraps some other value -- typically a Quantity -- but represents a value measured based on | |
406 // some absolute origin. For example, if `Duration` is a type representing a time duration, | |
407 // Absolute<Duration, UnixEpoch> might be a calendar date. | |
408 // | |
409 // Since Absolute represents measurements relative to some arbitrary origin, the only sensible | |
410 // arithmetic to perform on them is addition and subtraction. | |
411 | |
412 // TODO(someday): Do the same automatic expansion of integer width that Quantity does? Doesn't | |
413 // matter for our time use case, where we always use 64-bit anyway. Note that fixing this | |
414 // would implicitly allow things like multiplying an Absolute by a UnitRatio to change its | |
415 // units, which is actually totally logical and kind of neat. | |
416 | |
417 public: | |
418 inline constexpr Absolute(MaxValue_): value(maxValue) {} | |
419 inline constexpr Absolute(MinValue_): value(minValue) {} | |
420 // Allow initialization from maxValue and minValue. | |
421 // TODO(msvc): decltype(maxValue) and decltype(minValue) deduce unknown-type for these function | |
422 // parameters, causing the compiler to complain of a duplicate constructor definition, so we | |
423 // specify MaxValue_ and MinValue_ types explicitly. | |
424 | |
425 inline constexpr Absolute operator+(const T& other) const { return Absolute(value + other); } | |
426 inline constexpr Absolute operator-(const T& other) const { return Absolute(value - other); } | |
427 inline constexpr T operator-(const Absolute& other) const { return value - other.value; } | |
428 | |
429 inline Absolute& operator+=(const T& other) { value += other; return *this; } | |
430 inline Absolute& operator-=(const T& other) { value -= other; return *this; } | |
431 | |
432 inline constexpr bool operator==(const Absolute& other) const { return value == other.value; } | |
433 inline constexpr bool operator!=(const Absolute& other) const { return value != other.value; } | |
434 inline constexpr bool operator<=(const Absolute& other) const { return value <= other.value; } | |
435 inline constexpr bool operator>=(const Absolute& other) const { return value >= other.value; } | |
436 inline constexpr bool operator< (const Absolute& other) const { return value < other.value; } | |
437 inline constexpr bool operator> (const Absolute& other) const { return value > other.value; } | |
438 | |
439 private: | |
440 T value; | |
441 | |
442 explicit constexpr Absolute(T value): value(value) {} | |
443 | |
444 template <typename U> | |
445 friend inline constexpr U origin(); | |
446 }; | |
447 | |
448 template <typename T, typename Label> | |
449 inline constexpr Absolute<T, Label> operator+(const T& a, const Absolute<T, Label>& b) { | |
450 return b + a; | |
451 } | |
452 | |
453 template <typename T> struct UnitOf_ { typedef T Type; }; | |
454 template <typename T, typename Label> struct UnitOf_<Absolute<T, Label>> { typedef T Type; }; | |
455 template <typename T> | |
456 using UnitOf = typename UnitOf_<T>::Type; | |
457 // UnitOf<Absolute<T, U>> is T. UnitOf<AnythingElse> is AnythingElse. | |
458 | |
459 template <typename T> | |
460 inline constexpr T origin() { return T(0 * unit<UnitOf<T>>()); } | |
461 // origin<Absolute<T, U>>() returns an Absolute of value 0. It also, intentionally, works on basic | |
462 // numeric types. | |
463 | |
464 // ======================================================================================= | |
465 // Overflow avoidance | |
466 | |
467 template <uint64_t n, uint accum = 0> | |
468 struct BitCount_ { | |
469 static constexpr uint value = BitCount_<(n >> 1), accum + 1>::value; | |
470 }; | |
471 template <uint accum> | |
472 struct BitCount_<0, accum> { | |
473 static constexpr uint value = accum; | |
474 }; | |
475 | |
476 template <uint64_t n> | |
477 inline constexpr uint bitCount() { return BitCount_<n>::value; } | |
478 // Number of bits required to represent the number `n`. | |
479 | |
480 template <uint bitCountBitCount> struct AtLeastUInt_ { | |
481 static_assert(bitCountBitCount < 7, "don't know how to represent integers over 64 bits"); | |
482 }; | |
483 template <> struct AtLeastUInt_<0> { typedef uint8_t Type; }; | |
484 template <> struct AtLeastUInt_<1> { typedef uint8_t Type; }; | |
485 template <> struct AtLeastUInt_<2> { typedef uint8_t Type; }; | |
486 template <> struct AtLeastUInt_<3> { typedef uint8_t Type; }; | |
487 template <> struct AtLeastUInt_<4> { typedef uint16_t Type; }; | |
488 template <> struct AtLeastUInt_<5> { typedef uint32_t Type; }; | |
489 template <> struct AtLeastUInt_<6> { typedef uint64_t Type; }; | |
490 | |
491 template <uint bits> | |
492 using AtLeastUInt = typename AtLeastUInt_<bitCount<max(bits, 1) - 1>()>::Type; | |
493 // AtLeastUInt<n> is an unsigned integer of at least n bits. E.g. AtLeastUInt<12> is uint16_t. | |
494 | |
495 // ------------------------------------------------------------------- | |
496 | |
497 template <uint value> | |
498 class BoundedConst { | |
499 // A constant integer value on which we can do bit size analysis. | |
500 | |
501 public: | |
502 BoundedConst() = default; | |
503 | |
504 inline constexpr uint unwrap() const { return value; } | |
505 | |
506 #define OP(op, check) \ | |
507 template <uint other> \ | |
508 inline constexpr BoundedConst<(value op other)> \ | |
509 operator op(BoundedConst<other>) const { \ | |
510 static_assert(check, "overflow in BoundedConst arithmetic"); \ | |
511 return BoundedConst<(value op other)>(); \ | |
512 } | |
513 #define COMPARE_OP(op) \ | |
514 template <uint other> \ | |
515 inline constexpr bool operator op(BoundedConst<other>) const { \ | |
516 return value op other; \ | |
517 } | |
518 | |
519 OP(+, value + other >= value) | |
520 OP(-, value - other <= value) | |
521 OP(*, value * other / other == value) | |
522 OP(/, true) // div by zero already errors out; no other division ever overflows | |
523 OP(%, true) // mod by zero already errors out; no other modulus ever overflows | |
524 OP(<<, value << other >= value) | |
525 OP(>>, true) // right shift can't overflow | |
526 OP(&, true) // bitwise ops can't overflow | |
527 OP(|, true) // bitwise ops can't overflow | |
528 | |
529 COMPARE_OP(==) | |
530 COMPARE_OP(!=) | |
531 COMPARE_OP(< ) | |
532 COMPARE_OP(> ) | |
533 COMPARE_OP(<=) | |
534 COMPARE_OP(>=) | |
535 #undef OP | |
536 #undef COMPARE_OP | |
537 }; | |
538 | |
539 template <uint64_t m, typename T> | |
540 struct Unit_<Bounded<m, T>> { | |
541 static inline constexpr BoundedConst<1> get() { return BoundedConst<1>(); } | |
542 }; | |
543 | |
544 template <uint value> | |
545 struct Unit_<BoundedConst<value>> { | |
546 static inline constexpr BoundedConst<1> get() { return BoundedConst<1>(); } | |
547 }; | |
548 | |
549 template <uint value> | |
550 inline constexpr BoundedConst<value> bounded() { | |
551 return BoundedConst<value>(); | |
552 } | |
553 | |
554 template <uint64_t a, uint64_t b> | |
555 static constexpr uint64_t boundedAdd() { | |
556 static_assert(a + b >= a, "possible overflow detected"); | |
557 return a + b; | |
558 } | |
559 template <uint64_t a, uint64_t b> | |
560 static constexpr uint64_t boundedSub() { | |
561 static_assert(a - b <= a, "possible underflow detected"); | |
562 return a - b; | |
563 } | |
564 template <uint64_t a, uint64_t b> | |
565 static constexpr uint64_t boundedMul() { | |
566 static_assert(a * b / b == a, "possible overflow detected"); | |
567 return a * b; | |
568 } | |
569 template <uint64_t a, uint64_t b> | |
570 static constexpr uint64_t boundedLShift() { | |
571 static_assert(a << b >= a, "possible overflow detected"); | |
572 return a << b; | |
573 } | |
574 | |
575 template <uint a, uint b> | |
576 inline constexpr BoundedConst<kj::min(a, b)> min(BoundedConst<a>, BoundedConst<b>) { | |
577 return bounded<kj::min(a, b)>(); | |
578 } | |
579 template <uint a, uint b> | |
580 inline constexpr BoundedConst<kj::max(a, b)> max(BoundedConst<a>, BoundedConst<b>) { | |
581 return bounded<kj::max(a, b)>(); | |
582 } | |
583 // We need to override min() and max() between constants because the ternary operator in the | |
584 // default implementation would complain. | |
585 | |
586 // ------------------------------------------------------------------- | |
587 | |
588 template <uint64_t maxN, typename T> | |
589 class Bounded { | |
590 public: | |
591 static_assert(maxN <= T(kj::maxValue), "possible overflow detected"); | |
592 | |
593 Bounded() = default; | |
594 | |
595 Bounded(const Bounded& other) = default; | |
596 template <typename OtherInt, typename = EnableIf<isIntegral<OtherInt>()>> | |
597 inline constexpr Bounded(OtherInt value): value(value) { | |
598 static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); | |
599 } | |
600 template <uint64_t otherMax, typename OtherT> | |
601 inline constexpr Bounded(const Bounded<otherMax, OtherT>& other) | |
602 : value(other.value) { | |
603 static_assert(otherMax <= maxN, "possible overflow detected"); | |
604 } | |
605 template <uint otherValue> | |
606 inline constexpr Bounded(BoundedConst<otherValue>) | |
607 : value(otherValue) { | |
608 static_assert(otherValue <= maxN, "overflow detected"); | |
609 } | |
610 | |
611 Bounded& operator=(const Bounded& other) = default; | |
612 template <typename OtherInt, typename = EnableIf<isIntegral<OtherInt>()>> | |
613 Bounded& operator=(OtherInt other) { | |
614 static_assert(OtherInt(maxValue) <= maxN, "possible overflow detected"); | |
615 value = other; | |
616 return *this; | |
617 } | |
618 template <uint64_t otherMax, typename OtherT> | |
619 inline Bounded& operator=(const Bounded<otherMax, OtherT>& other) { | |
620 static_assert(otherMax <= maxN, "possible overflow detected"); | |
621 value = other.value; | |
622 return *this; | |
623 } | |
624 template <uint otherValue> | |
625 inline Bounded& operator=(BoundedConst<otherValue>) { | |
626 static_assert(otherValue <= maxN, "overflow detected"); | |
627 value = otherValue; | |
628 return *this; | |
629 } | |
630 | |
631 inline constexpr T unwrap() const { return value; } | |
632 | |
633 #define OP(op, newMax) \ | |
634 template <uint64_t otherMax, typename otherT> \ | |
635 inline constexpr Bounded<newMax, decltype(T() op otherT())> \ | |
636 operator op(const Bounded<otherMax, otherT>& other) const { \ | |
637 return Bounded<newMax, decltype(T() op otherT())>(value op other.value, unsafe); \ | |
638 } | |
639 #define COMPARE_OP(op) \ | |
640 template <uint64_t otherMax, typename OtherT> \ | |
641 inline constexpr bool operator op(const Bounded<otherMax, OtherT>& other) const { \ | |
642 return value op other.value; \ | |
643 } | |
644 | |
645 OP(+, (boundedAdd<maxN, otherMax>())) | |
646 OP(*, (boundedMul<maxN, otherMax>())) | |
647 OP(/, maxN) | |
648 OP(%, otherMax - 1) | |
649 | |
650 // operator- is intentionally omitted because we mostly use this with unsigned types, and | |
651 // subtraction requires proof that subtrahend is not greater than the minuend. | |
652 | |
653 COMPARE_OP(==) | |
654 COMPARE_OP(!=) | |
655 COMPARE_OP(< ) | |
656 COMPARE_OP(> ) | |
657 COMPARE_OP(<=) | |
658 COMPARE_OP(>=) | |
659 | |
660 #undef OP | |
661 #undef COMPARE_OP | |
662 | |
663 template <uint64_t newMax, typename ErrorFunc> | |
664 inline Bounded<newMax, T> assertMax(ErrorFunc&& func) const { | |
665 // Assert that the number is no more than `newMax`. Otherwise, call `func`. | |
666 static_assert(newMax < maxN, "this bounded size assertion is redundant"); | |
667 if (KJ_UNLIKELY(value > newMax)) func(); | |
668 return Bounded<newMax, T>(value, unsafe); | |
669 } | |
670 | |
671 template <uint64_t otherMax, typename OtherT, typename ErrorFunc> | |
672 inline Bounded<maxN, decltype(T() - OtherT())> subtractChecked( | |
673 const Bounded<otherMax, OtherT>& other, ErrorFunc&& func) const { | |
674 // Subtract a number, calling func() if the result would underflow. | |
675 if (KJ_UNLIKELY(value < other.value)) func(); | |
676 return Bounded<maxN, decltype(T() - OtherT())>(value - other.value, unsafe); | |
677 } | |
678 | |
679 template <uint otherValue, typename ErrorFunc> | |
680 inline Bounded<maxN - otherValue, T> subtractChecked( | |
681 BoundedConst<otherValue>, ErrorFunc&& func) const { | |
682 // Subtract a number, calling func() if the result would underflow. | |
683 static_assert(otherValue <= maxN, "underflow detected"); | |
684 if (KJ_UNLIKELY(value < otherValue)) func(); | |
685 return Bounded<maxN - otherValue, T>(value - otherValue, unsafe); | |
686 } | |
687 | |
688 template <uint64_t otherMax, typename OtherT> | |
689 inline Maybe<Bounded<maxN, decltype(T() - OtherT())>> trySubtract( | |
690 const Bounded<otherMax, OtherT>& other) const { | |
691 // Subtract a number, calling func() if the result would underflow. | |
692 if (value < other.value) { | |
693 return nullptr; | |
694 } else { | |
695 return Bounded<maxN, decltype(T() - OtherT())>(value - other.value, unsafe); | |
696 } | |
697 } | |
698 | |
699 template <uint otherValue> | |
700 inline Maybe<Bounded<maxN - otherValue, T>> trySubtract(BoundedConst<otherValue>) const { | |
701 // Subtract a number, calling func() if the result would underflow. | |
702 if (value < otherValue) { | |
703 return nullptr; | |
704 } else { | |
705 return Bounded<maxN - otherValue, T>(value - otherValue, unsafe); | |
706 } | |
707 } | |
708 | |
709 inline constexpr Bounded(T value, decltype(unsafe)): value(value) {} | |
710 template <uint64_t otherMax, typename OtherT> | |
711 inline constexpr Bounded(Bounded<otherMax, OtherT> value, decltype(unsafe)) | |
712 : value(value.value) {} | |
713 // Mainly for internal use. | |
714 // | |
715 // Only use these as a last resort, with ample commentary on why you think it's safe. | |
716 | |
717 private: | |
718 T value; | |
719 | |
720 template <uint64_t, typename> | |
721 friend class Bounded; | |
722 }; | |
723 | |
724 template <typename Number> | |
725 inline constexpr Bounded<Number(kj::maxValue), Number> bounded(Number value) { | |
726 return Bounded<Number(kj::maxValue), Number>(value, unsafe); | |
727 } | |
728 | |
729 inline constexpr Bounded<1, uint8_t> bounded(bool value) { | |
730 return Bounded<1, uint8_t>(value, unsafe); | |
731 } | |
732 | |
733 template <uint bits, typename Number> | |
734 inline constexpr Bounded<maxValueForBits<bits>(), Number> assumeBits(Number value) { | |
735 return Bounded<maxValueForBits<bits>(), Number>(value, unsafe); | |
736 } | |
737 | |
738 template <uint bits, uint64_t maxN, typename T> | |
739 inline constexpr Bounded<maxValueForBits<bits>(), T> assumeBits(Bounded<maxN, T> value) { | |
740 return Bounded<maxValueForBits<bits>(), T>(value, unsafe); | |
741 } | |
742 | |
743 template <uint bits, typename Number, typename Unit> | |
744 inline constexpr auto assumeBits(Quantity<Number, Unit> value) | |
745 -> Quantity<decltype(assumeBits<bits>(value / unit<Quantity<Number, Unit>>())), Unit> { | |
746 return Quantity<decltype(assumeBits<bits>(value / unit<Quantity<Number, Unit>>())), Unit>( | |
747 assumeBits<bits>(value / unit<Quantity<Number, Unit>>()), unsafe); | |
748 } | |
749 | |
750 template <uint64_t maxN, typename Number> | |
751 inline constexpr Bounded<maxN, Number> assumeMax(Number value) { | |
752 return Bounded<maxN, Number>(value, unsafe); | |
753 } | |
754 | |
755 template <uint64_t newMaxN, uint64_t maxN, typename T> | |
756 inline constexpr Bounded<newMaxN, T> assumeMax(Bounded<maxN, T> value) { | |
757 return Bounded<newMaxN, T>(value, unsafe); | |
758 } | |
759 | |
760 template <uint64_t maxN, typename Number, typename Unit> | |
761 inline constexpr auto assumeMax(Quantity<Number, Unit> value) | |
762 -> Quantity<decltype(assumeMax<maxN>(value / unit<Quantity<Number, Unit>>())), Unit> { | |
763 return Quantity<decltype(assumeMax<maxN>(value / unit<Quantity<Number, Unit>>())), Unit>( | |
764 assumeMax<maxN>(value / unit<Quantity<Number, Unit>>()), unsafe); | |
765 } | |
766 | |
767 template <uint maxN, typename Number> | |
768 inline constexpr Bounded<maxN, Number> assumeMax(BoundedConst<maxN>, Number value) { | |
769 return assumeMax<maxN>(value); | |
770 } | |
771 | |
772 template <uint newMaxN, uint64_t maxN, typename T> | |
773 inline constexpr Bounded<newMaxN, T> assumeMax(BoundedConst<maxN>, Bounded<maxN, T> value) { | |
774 return assumeMax<maxN>(value); | |
775 } | |
776 | |
777 template <uint maxN, typename Number, typename Unit> | |
778 inline constexpr auto assumeMax(Quantity<BoundedConst<maxN>, Unit>, Quantity<Number, Unit> value) | |
779 -> decltype(assumeMax<maxN>(value)) { | |
780 return assumeMax<maxN>(value); | |
781 } | |
782 | |
783 template <uint64_t newMax, uint64_t maxN, typename T, typename ErrorFunc> | |
784 inline Bounded<newMax, T> assertMax(Bounded<maxN, T> value, ErrorFunc&& errorFunc) { | |
785 // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() | |
786 // if not. | |
787 static_assert(newMax < maxN, "this bounded size assertion is redundant"); | |
788 return value.template assertMax<newMax>(kj::fwd<ErrorFunc>(errorFunc)); | |
789 } | |
790 | |
791 template <uint64_t newMax, uint64_t maxN, typename T, typename Unit, typename ErrorFunc> | |
792 inline Quantity<Bounded<newMax, T>, Unit> assertMax( | |
793 Quantity<Bounded<maxN, T>, Unit> value, ErrorFunc&& errorFunc) { | |
794 // Assert that the bounded value is less than or equal to the given maximum, calling errorFunc() | |
795 // if not. | |
796 static_assert(newMax < maxN, "this bounded size assertion is redundant"); | |
797 return (value / unit<decltype(value)>()).template assertMax<newMax>( | |
798 kj::fwd<ErrorFunc>(errorFunc)) * unit<decltype(value)>(); | |
799 } | |
800 | |
801 template <uint newMax, uint64_t maxN, typename T, typename ErrorFunc> | |
802 inline Bounded<newMax, T> assertMax( | |
803 BoundedConst<newMax>, Bounded<maxN, T> value, ErrorFunc&& errorFunc) { | |
804 return assertMax<newMax>(value, kj::mv(errorFunc)); | |
805 } | |
806 | |
807 template <uint newMax, uint64_t maxN, typename T, typename Unit, typename ErrorFunc> | |
808 inline Quantity<Bounded<newMax, T>, Unit> assertMax( | |
809 Quantity<BoundedConst<newMax>, Unit>, | |
810 Quantity<Bounded<maxN, T>, Unit> value, ErrorFunc&& errorFunc) { | |
811 return assertMax<newMax>(value, kj::mv(errorFunc)); | |
812 } | |
813 | |
814 template <uint64_t newBits, uint64_t maxN, typename T, typename ErrorFunc = ThrowOverflow> | |
815 inline Bounded<maxValueForBits<newBits>(), T> assertMaxBits( | |
816 Bounded<maxN, T> value, ErrorFunc&& errorFunc = ErrorFunc()) { | |
817 // Assert that the bounded value requires no more than the given number of bits, calling | |
818 // errorFunc() if not. | |
819 return assertMax<maxValueForBits<newBits>()>(value, kj::fwd<ErrorFunc>(errorFunc)); | |
820 } | |
821 | |
822 template <uint64_t newBits, uint64_t maxN, typename T, typename Unit, | |
823 typename ErrorFunc = ThrowOverflow> | |
824 inline Quantity<Bounded<maxValueForBits<newBits>(), T>, Unit> assertMaxBits( | |
825 Quantity<Bounded<maxN, T>, Unit> value, ErrorFunc&& errorFunc = ErrorFunc()) { | |
826 // Assert that the bounded value requires no more than the given number of bits, calling | |
827 // errorFunc() if not. | |
828 return assertMax<maxValueForBits<newBits>()>(value, kj::fwd<ErrorFunc>(errorFunc)); | |
829 } | |
830 | |
831 template <typename newT, uint64_t maxN, typename T> | |
832 inline constexpr Bounded<maxN, newT> upgradeBound(Bounded<maxN, T> value) { | |
833 return value; | |
834 } | |
835 | |
836 template <typename newT, uint64_t maxN, typename T, typename Unit> | |
837 inline constexpr Quantity<Bounded<maxN, newT>, Unit> upgradeBound( | |
838 Quantity<Bounded<maxN, T>, Unit> value) { | |
839 return value; | |
840 } | |
841 | |
842 template <uint64_t maxN, typename T, typename Other, typename ErrorFunc> | |
843 inline auto subtractChecked(Bounded<maxN, T> value, Other other, ErrorFunc&& errorFunc) | |
844 -> decltype(value.subtractChecked(other, kj::fwd<ErrorFunc>(errorFunc))) { | |
845 return value.subtractChecked(other, kj::fwd<ErrorFunc>(errorFunc)); | |
846 } | |
847 | |
848 template <typename T, typename U, typename Unit, typename ErrorFunc> | |
849 inline auto subtractChecked(Quantity<T, Unit> value, Quantity<U, Unit> other, ErrorFunc&& errorFunc) | |
850 -> Quantity<decltype(subtractChecked(T(), U(), kj::fwd<ErrorFunc>(errorFunc))), Unit> { | |
851 return subtractChecked(value / unit<Quantity<T, Unit>>(), | |
852 other / unit<Quantity<U, Unit>>(), | |
853 kj::fwd<ErrorFunc>(errorFunc)) | |
854 * unit<Quantity<T, Unit>>(); | |
855 } | |
856 | |
857 template <uint64_t maxN, typename T, typename Other> | |
858 inline auto trySubtract(Bounded<maxN, T> value, Other other) | |
859 -> decltype(value.trySubtract(other)) { | |
860 return value.trySubtract(other); | |
861 } | |
862 | |
863 template <typename T, typename U, typename Unit> | |
864 inline auto trySubtract(Quantity<T, Unit> value, Quantity<U, Unit> other) | |
865 -> Maybe<Quantity<decltype(subtractChecked(T(), U(), int())), Unit>> { | |
866 return trySubtract(value / unit<Quantity<T, Unit>>(), | |
867 other / unit<Quantity<U, Unit>>()) | |
868 .map([](decltype(subtractChecked(T(), U(), int())) x) { | |
869 return x * unit<Quantity<T, Unit>>(); | |
870 }); | |
871 } | |
872 | |
873 template <uint64_t aN, uint64_t bN, typename A, typename B> | |
874 inline constexpr Bounded<kj::min(aN, bN), WiderType<A, B>> | |
875 min(Bounded<aN, A> a, Bounded<bN, B> b) { | |
876 return Bounded<kj::min(aN, bN), WiderType<A, B>>(kj::min(a.unwrap(), b.unwrap()), unsafe); | |
877 } | |
878 template <uint64_t aN, uint64_t bN, typename A, typename B> | |
879 inline constexpr Bounded<kj::max(aN, bN), WiderType<A, B>> | |
880 max(Bounded<aN, A> a, Bounded<bN, B> b) { | |
881 return Bounded<kj::max(aN, bN), WiderType<A, B>>(kj::max(a.unwrap(), b.unwrap()), unsafe); | |
882 } | |
883 // We need to override min() and max() because: | |
884 // 1) WiderType<> might not choose the correct bounds. | |
885 // 2) One of the two sides of the ternary operator in the default implementation would fail to | |
886 // typecheck even though it is OK in practice. | |
887 | |
888 // ------------------------------------------------------------------- | |
889 // Operators between Bounded and BoundedConst | |
890 | |
891 #define OP(op, newMax) \ | |
892 template <uint64_t maxN, uint cvalue, typename T> \ | |
893 inline constexpr Bounded<(newMax), decltype(T() op uint())> operator op( \ | |
894 Bounded<maxN, T> value, BoundedConst<cvalue>) { \ | |
895 return Bounded<(newMax), decltype(T() op uint())>(value.unwrap() op cvalue, unsafe); \ | |
896 } | |
897 | |
898 #define REVERSE_OP(op, newMax) \ | |
899 template <uint64_t maxN, uint cvalue, typename T> \ | |
900 inline constexpr Bounded<(newMax), decltype(uint() op T())> operator op( \ | |
901 BoundedConst<cvalue>, Bounded<maxN, T> value) { \ | |
902 return Bounded<(newMax), decltype(uint() op T())>(cvalue op value.unwrap(), unsafe); \ | |
903 } | |
904 | |
905 #define COMPARE_OP(op) \ | |
906 template <uint64_t maxN, uint cvalue, typename T> \ | |
907 inline constexpr bool operator op(Bounded<maxN, T> value, BoundedConst<cvalue>) { \ | |
908 return value.unwrap() op cvalue; \ | |
909 } \ | |
910 template <uint64_t maxN, uint cvalue, typename T> \ | |
911 inline constexpr bool operator op(BoundedConst<cvalue>, Bounded<maxN, T> value) { \ | |
912 return cvalue op value.unwrap(); \ | |
913 } | |
914 | |
915 OP(+, (boundedAdd<maxN, cvalue>())) | |
916 REVERSE_OP(+, (boundedAdd<maxN, cvalue>())) | |
917 | |
918 OP(*, (boundedMul<maxN, cvalue>())) | |
919 REVERSE_OP(*, (boundedAdd<maxN, cvalue>())) | |
920 | |
921 OP(/, maxN / cvalue) | |
922 REVERSE_OP(/, cvalue) // denominator could be 1 | |
923 | |
924 OP(%, cvalue - 1) | |
925 REVERSE_OP(%, maxN - 1) | |
926 | |
927 OP(<<, (boundedLShift<maxN, cvalue>())) | |
928 REVERSE_OP(<<, (boundedLShift<cvalue, maxN>())) | |
929 | |
930 OP(>>, maxN >> cvalue) | |
931 REVERSE_OP(>>, cvalue >> maxN) | |
932 | |
933 OP(&, maxValueForBits<bitCount<maxN>()>() & cvalue) | |
934 REVERSE_OP(&, maxValueForBits<bitCount<maxN>()>() & cvalue) | |
935 | |
936 OP(|, maxN | cvalue) | |
937 REVERSE_OP(|, maxN | cvalue) | |
938 | |
939 COMPARE_OP(==) | |
940 COMPARE_OP(!=) | |
941 COMPARE_OP(< ) | |
942 COMPARE_OP(> ) | |
943 COMPARE_OP(<=) | |
944 COMPARE_OP(>=) | |
945 | |
946 #undef OP | |
947 #undef REVERSE_OP | |
948 #undef COMPARE_OP | |
949 | |
950 template <uint64_t maxN, uint cvalue, typename T> | |
951 inline constexpr Bounded<cvalue, decltype(uint() - T())> | |
952 operator-(BoundedConst<cvalue>, Bounded<maxN, T> value) { | |
953 // We allow subtraction of a variable from a constant only if the constant is greater than or | |
954 // equal to the maximum possible value of the variable. Since the variable could be zero, the | |
955 // result can be as large as the constant. | |
956 // | |
957 // We do not allow subtraction of a constant from a variable because there's never a guarantee it | |
958 // won't underflow (unless the constant is zero, which is silly). | |
959 static_assert(cvalue >= maxN, "possible underflow detected"); | |
960 return Bounded<cvalue, decltype(uint() - T())>(cvalue - value.unwrap(), unsafe); | |
961 } | |
962 | |
963 template <uint64_t aN, uint b, typename A> | |
964 inline constexpr Bounded<kj::min(aN, b), A> min(Bounded<aN, A> a, BoundedConst<b>) { | |
965 return Bounded<kj::min(aN, b), A>(kj::min(b, a.unwrap()), unsafe); | |
966 } | |
967 template <uint64_t aN, uint b, typename A> | |
968 inline constexpr Bounded<kj::min(aN, b), A> min(BoundedConst<b>, Bounded<aN, A> a) { | |
969 return Bounded<kj::min(aN, b), A>(kj::min(a.unwrap(), b), unsafe); | |
970 } | |
971 template <uint64_t aN, uint b, typename A> | |
972 inline constexpr Bounded<kj::max(aN, b), A> max(Bounded<aN, A> a, BoundedConst<b>) { | |
973 return Bounded<kj::max(aN, b), A>(kj::max(b, a.unwrap()), unsafe); | |
974 } | |
975 template <uint64_t aN, uint b, typename A> | |
976 inline constexpr Bounded<kj::max(aN, b), A> max(BoundedConst<b>, Bounded<aN, A> a) { | |
977 return Bounded<kj::max(aN, b), A>(kj::max(a.unwrap(), b), unsafe); | |
978 } | |
979 // We need to override min() between a Bounded and a constant since: | |
980 // 1) WiderType<> might choose BoundedConst over a 1-byte Bounded, which is wrong. | |
981 // 2) To clamp the bounds of the output type. | |
982 // 3) Same ternary operator typechecking issues. | |
983 | |
984 // ------------------------------------------------------------------- | |
985 | |
986 template <uint64_t maxN, typename T> | |
987 class SafeUnwrapper { | |
988 public: | |
989 inline explicit constexpr SafeUnwrapper(Bounded<maxN, T> value): value(value.unwrap()) {} | |
990 | |
991 template <typename U, typename = EnableIf<isIntegral<U>()>> | |
992 inline constexpr operator U() const { | |
993 static_assert(maxN <= U(maxValue), "possible truncation detected"); | |
994 return value; | |
995 } | |
996 | |
997 inline constexpr operator bool() const { | |
998 static_assert(maxN <= 1, "possible truncation detected"); | |
999 return value; | |
1000 } | |
1001 | |
1002 private: | |
1003 T value; | |
1004 }; | |
1005 | |
1006 template <uint64_t maxN, typename T> | |
1007 inline constexpr SafeUnwrapper<maxN, T> unbound(Bounded<maxN, T> bounded) { | |
1008 // Unwraps the bounded value, returning a value that can be implicitly cast to any integer type. | |
1009 // If this implicit cast could truncate, a compile-time error will be raised. | |
1010 return SafeUnwrapper<maxN, T>(bounded); | |
1011 } | |
1012 | |
1013 template <uint64_t value> | |
1014 class SafeConstUnwrapper { | |
1015 public: | |
1016 template <typename T, typename = EnableIf<isIntegral<T>()>> | |
1017 inline constexpr operator T() const { | |
1018 static_assert(value <= T(maxValue), "this operation will truncate"); | |
1019 return value; | |
1020 } | |
1021 | |
1022 inline constexpr operator bool() const { | |
1023 static_assert(value <= 1, "this operation will truncate"); | |
1024 return value; | |
1025 } | |
1026 }; | |
1027 | |
1028 template <uint value> | |
1029 inline constexpr SafeConstUnwrapper<value> unbound(BoundedConst<value>) { | |
1030 return SafeConstUnwrapper<value>(); | |
1031 } | |
1032 | |
1033 template <typename T, typename U> | |
1034 inline constexpr T unboundAs(U value) { | |
1035 return unbound(value); | |
1036 } | |
1037 | |
1038 template <uint64_t requestedMax, uint64_t maxN, typename T> | |
1039 inline constexpr T unboundMax(Bounded<maxN, T> value) { | |
1040 // Explicitly unguard expecting a value that is at most `maxN`. | |
1041 static_assert(maxN <= requestedMax, "possible overflow detected"); | |
1042 return value.unwrap(); | |
1043 } | |
1044 | |
1045 template <uint64_t requestedMax, uint value> | |
1046 inline constexpr uint unboundMax(BoundedConst<value>) { | |
1047 // Explicitly unguard expecting a value that is at most `maxN`. | |
1048 static_assert(value <= requestedMax, "overflow detected"); | |
1049 return value; | |
1050 } | |
1051 | |
1052 template <uint bits, typename T> | |
1053 inline constexpr auto unboundMaxBits(T value) -> | |
1054 decltype(unboundMax<maxValueForBits<bits>()>(value)) { | |
1055 // Explicitly unguard expecting a value that fits into `bits` bits. | |
1056 return unboundMax<maxValueForBits<bits>()>(value); | |
1057 } | |
1058 | |
1059 #define OP(op) \ | |
1060 template <uint64_t maxN, typename T, typename U> \ | |
1061 inline constexpr auto operator op(T a, SafeUnwrapper<maxN, U> b) -> decltype(a op (T)b) { \ | |
1062 return a op (AtLeastUInt<sizeof(T)*8>)b; \ | |
1063 } \ | |
1064 template <uint64_t maxN, typename T, typename U> \ | |
1065 inline constexpr auto operator op(SafeUnwrapper<maxN, U> b, T a) -> decltype((T)b op a) { \ | |
1066 return (AtLeastUInt<sizeof(T)*8>)b op a; \ | |
1067 } \ | |
1068 template <uint64_t value, typename T> \ | |
1069 inline constexpr auto operator op(T a, SafeConstUnwrapper<value> b) -> decltype(a op (T)b) { \ | |
1070 return a op (AtLeastUInt<sizeof(T)*8>)b; \ | |
1071 } \ | |
1072 template <uint64_t value, typename T> \ | |
1073 inline constexpr auto operator op(SafeConstUnwrapper<value> b, T a) -> decltype((T)b op a) { \ | |
1074 return (AtLeastUInt<sizeof(T)*8>)b op a; \ | |
1075 } | |
1076 | |
1077 OP(+) | |
1078 OP(-) | |
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 | |
1093 #undef OP | |
1094 | |
1095 // ------------------------------------------------------------------- | |
1096 | |
1097 template <uint64_t maxN, typename T> | |
1098 class Range<Bounded<maxN, T>> { | |
1099 public: | |
1100 inline constexpr Range(Bounded<maxN, T> begin, Bounded<maxN, T> end) | |
1101 : inner(unbound(begin), unbound(end)) {} | |
1102 inline explicit constexpr Range(Bounded<maxN, T> end) | |
1103 : inner(unbound(end)) {} | |
1104 | |
1105 class Iterator { | |
1106 public: | |
1107 Iterator() = default; | |
1108 inline explicit Iterator(typename Range<T>::Iterator inner): inner(inner) {} | |
1109 | |
1110 inline Bounded<maxN, T> operator* () const { return Bounded<maxN, T>(*inner, unsafe); } | |
1111 inline Iterator& operator++() { ++inner; return *this; } | |
1112 | |
1113 inline bool operator==(const Iterator& other) const { return inner == other.inner; } | |
1114 inline bool operator!=(const Iterator& other) const { return inner != other.inner; } | |
1115 | |
1116 private: | |
1117 typename Range<T>::Iterator inner; | |
1118 }; | |
1119 | |
1120 inline Iterator begin() const { return Iterator(inner.begin()); } | |
1121 inline Iterator end() const { return Iterator(inner.end()); } | |
1122 | |
1123 private: | |
1124 Range<T> inner; | |
1125 }; | |
1126 | |
1127 template <typename T, typename U> | |
1128 class Range<Quantity<T, U>> { | |
1129 public: | |
1130 inline constexpr Range(Quantity<T, U> begin, Quantity<T, U> end) | |
1131 : inner(begin / unit<Quantity<T, U>>(), end / unit<Quantity<T, U>>()) {} | |
1132 inline explicit constexpr Range(Quantity<T, U> end) | |
1133 : inner(end / unit<Quantity<T, U>>()) {} | |
1134 | |
1135 class Iterator { | |
1136 public: | |
1137 Iterator() = default; | |
1138 inline explicit Iterator(typename Range<T>::Iterator inner): inner(inner) {} | |
1139 | |
1140 inline Quantity<T, U> operator* () const { return *inner * unit<Quantity<T, U>>(); } | |
1141 inline Iterator& operator++() { ++inner; return *this; } | |
1142 | |
1143 inline bool operator==(const Iterator& other) const { return inner == other.inner; } | |
1144 inline bool operator!=(const Iterator& other) const { return inner != other.inner; } | |
1145 | |
1146 private: | |
1147 typename Range<T>::Iterator inner; | |
1148 }; | |
1149 | |
1150 inline Iterator begin() const { return Iterator(inner.begin()); } | |
1151 inline Iterator end() const { return Iterator(inner.end()); } | |
1152 | |
1153 private: | |
1154 Range<T> inner; | |
1155 }; | |
1156 | |
1157 template <uint value> | |
1158 inline constexpr Range<Bounded<value, uint>> zeroTo(BoundedConst<value> end) { | |
1159 return Range<Bounded<value, uint>>(end); | |
1160 } | |
1161 | |
1162 template <uint value, typename Unit> | |
1163 inline constexpr Range<Quantity<Bounded<value, uint>, Unit>> | |
1164 zeroTo(Quantity<BoundedConst<value>, Unit> end) { | |
1165 return Range<Quantity<Bounded<value, uint>, Unit>>(end); | |
1166 } | |
1167 | |
1168 } // namespace kj | |
1169 | |
1170 KJ_END_HEADER |