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