annotate osx/include/kj/units.h @ 83:ae30d91d2ffe

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