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_