1# `base/numerics` 2 3This directory contains a dependency-free, header-only library of templates 4providing well-defined semantics for safely and performantly handling a variety 5of numeric operations, including most common arithmetic operations and 6conversions. 7 8The public API is broken out into the following header files: 9 10* `checked_math.h` contains the `CheckedNumeric` template class and helper 11 functions for performing arithmetic and conversion operations that detect 12 errors and boundary conditions (e.g. overflow, truncation, etc.). 13* `clamped_math.h` contains the `ClampedNumeric` template class and 14 helper functions for performing fast, clamped (i.e. non-sticky saturating) 15 arithmetic operations and conversions. 16* `safe_conversions.h` contains the `StrictNumeric` template class and 17 a collection of custom casting templates and helper functions for safely 18 converting between a range of numeric types. 19* `safe_math.h` includes all of the previously mentioned headers. 20 21*** aside 22**Note:** The `Numeric` template types implicitly convert from C numeric types 23and `Numeric` templates that are convertable to an underlying C numeric type. 24The conversion priority for `Numeric` type coercions is: 25 26* `StrictNumeric` coerces to `ClampedNumeric` and `CheckedNumeric` 27* `ClampedNumeric` coerces to `CheckedNumeric` 28*** 29 30[TOC] 31 32## Common patterns and use-cases 33 34The following covers the preferred style for the most common uses of this 35library. Please don't cargo-cult from anywhere else. 36 37### Performing checked arithmetic conversions 38 39The `checked_cast` template converts between arbitrary arithmetic types, and is 40used for cases where a conversion failure should result in program termination: 41 42```cpp 43// Crash if signed_value is out of range for buff_size. 44size_t buff_size = checked_cast<size_t>(signed_value); 45``` 46 47### Performing saturated (clamped) arithmetic conversions 48 49The `saturated_cast` template converts between arbitrary arithmetic types, and 50is used in cases where an out-of-bounds source value should be saturated to the 51corresponding maximum or minimum of the destination type: 52 53```cpp 54// Convert from float with saturation to INT_MAX, INT_MIN, or 0 for NaN. 55int int_value = saturated_cast<int>(floating_point_value); 56``` 57 58### Enforcing arithmetic conversions at compile-time 59 60The `strict_cast` enforces type restrictions at compile-time and results in 61emitted code that is identical to a normal `static_cast`. However, a 62`strict_cast` assignment will fail to compile if the destination type cannot 63represent the full range of the source type: 64 65```cpp 66// Throw a compiler error if byte_value is changed to an out-of-range-type. 67int int_value = strict_cast<int>(byte_value); 68``` 69 70You can also enforce these compile-time restrictions on function parameters by 71using the `StrictNumeric` template: 72 73```cpp 74// Throw a compiler error if the size argument cannot be represented by a 75// size_t (e.g. passing an int will fail to compile). 76bool AllocateBuffer(void** buffer, StrictCast<size_t> size); 77``` 78 79### Comparing values between arbitrary arithmetic types 80 81Both the `StrictNumeric` and `ClampedNumeric` types provide well defined 82comparisons between arbitrary arithmetic types. This allows you to perform 83comparisons that are not legal or would trigger compiler warnings or errors 84under the normal arithmetic promotion rules: 85 86```cpp 87bool foo(unsigned value, int upper_bound) { 88 // Converting to StrictNumeric allows this comparison to work correctly. 89 if (MakeStrictNum(value) >= upper_bound) 90 return false; 91``` 92 93*** note 94**Warning:** Do not perform manual conversions using the comparison operators. 95Instead, use the cast templates described in the previous sections, or the 96constexpr template functions `IsValueInRangeForNumericType` and 97`IsTypeInRangeForNumericType`, as these templates properly handle the full range 98of corner cases and employ various optimizations. 99*** 100 101### Calculating a buffer size (checked arithmetic) 102 103When making exact calculations—such as for buffer lengths—it's often necessary 104to know when those calculations trigger an overflow, undefined behavior, or 105other boundary conditions. The `CheckedNumeric` template does this by storing 106a bit determining whether or not some arithmetic operation has occured that 107would put the variable in an "invalid" state. Attempting to extract the value 108from a variable in an invalid state will trigger a check/trap condition, that 109by default will result in process termination. 110 111Here's an example of a buffer calculation using a `CheckedNumeric` type (note: 112the AssignIfValid method will trigger a compile error if the result is ignored). 113 114```cpp 115// Calculate the buffer size and detect if an overflow occurs. 116size_t size; 117if (!CheckAdd(kHeaderSize, CheckMul(count, kItemSize)).AssignIfValid(&size)) { 118 // Handle an overflow error... 119} 120``` 121 122### Calculating clamped coordinates (non-sticky saturating arithmetic) 123 124Certain classes of calculations—such as coordinate calculations—require 125well-defined semantics that always produce a valid result on boundary 126conditions. The `ClampedNumeric` template addresses this by providing 127performant, non-sticky saturating arithmetic operations. 128 129Here's an example of using a `ClampedNumeric` to calculate an operation 130insetting a rectangle. 131 132```cpp 133// Use clamped arithmetic since inset calculations might overflow. 134void Rect::Inset(int left, int top, int right, int bottom) { 135 origin_ += Vector2d(left, top); 136 set_width(ClampSub(width(), ClampAdd(left, right))); 137 set_height(ClampSub(height(), ClampAdd(top, bottom))); 138} 139``` 140 141*** note 142The `ClampedNumeric` type is not "sticky", which means the saturation is not 143retained across individual operations. As such, one arithmetic operation may 144result in a saturated value, while the next operation may then "desaturate" 145the value. Here's an example: 146 147```cpp 148ClampedNumeric<int> value = INT_MAX; 149++value; // value is still INT_MAX, due to saturation. 150--value; // value is now (INT_MAX - 1), because saturation is not sticky. 151``` 152 153*** 154 155## Conversion functions and StrictNumeric<> in safe_conversions.h 156 157This header includes a collection of helper `constexpr` templates for safely 158performing a range of conversions, assignments, and tests. 159 160### Safe casting templates 161 162* `as_signed()` - Returns the supplied integral value as a signed type of 163 the same width. 164* `as_unsigned()` - Returns the supplied integral value as an unsigned type 165 of the same width. 166* `checked_cast<>()` - Analogous to `static_cast<>` for numeric types, except 167 that by default it will trigger a crash on an out-of-bounds conversion (e.g. 168 overflow, underflow, NaN to integral) or a compile error if the conversion 169 error can be detected at compile time. The crash handler can be overridden 170 to perform a behavior other than crashing. 171* `saturated_cast<>()` - Analogous to `static_cast` for numeric types, except 172 that it returns a saturated result when the specified numeric conversion 173 would otherwise overflow or underflow. An NaN source returns 0 by 174 default, but can be overridden to return a different result. 175* `strict_cast<>()` - Analogous to `static_cast` for numeric types, except 176 this causes a compile failure if the destination type is not large 177 enough to contain any value in the source type. It performs no runtime 178 checking and thus introduces no runtime overhead. 179 180### Other helper and conversion functions 181 182* `IsValueInRangeForNumericType<>()` - A convenience function that returns 183 true if the type supplied as the template parameter can represent the value 184 passed as an argument to the function. 185* `IsTypeInRangeForNumericType<>()` - A convenience function that evaluates 186 entirely at compile-time and returns true if the destination type (first 187 template parameter) can represent the full range of the source type 188 (second template parameter). 189* `IsValueNegative()` - A convenience function that will accept any 190 arithmetic type as an argument and will return whether the value is less 191 than zero. Unsigned types always return false. 192* `SafeUnsignedAbs()` - Returns the absolute value of the supplied integer 193 parameter as an unsigned result (thus avoiding an overflow if the value 194 is the signed, two's complement minimum). 195 196### StrictNumeric<> 197 198`StrictNumeric<>` is a wrapper type that performs assignments and copies via 199the `strict_cast` template, and can perform valid arithmetic comparisons 200across any range of arithmetic types. `StrictNumeric` is the return type for 201values extracted from a `CheckedNumeric` class instance. The raw numeric value 202is extracted via `static_cast` to the underlying type or any type with 203sufficient range to represent the underlying type. 204 205* `MakeStrictNum()` - Creates a new `StrictNumeric` from the underlying type 206 of the supplied arithmetic or StrictNumeric type. 207* `SizeT` - Alias for `StrictNumeric<size_t>`. 208 209## CheckedNumeric<> in checked_math.h 210 211`CheckedNumeric<>` implements all the logic and operators for detecting integer 212boundary conditions such as overflow, underflow, and invalid conversions. 213The `CheckedNumeric` type implicitly converts from floating point and integer 214data types, and contains overloads for basic arithmetic operations (i.e.: `+`, 215`-`, `*`, `/` for all types and `%`, `<<`, `>>`, `&`, `|`, `^` for integers). 216However, *the [variadic template functions 217](#CheckedNumeric_in-checked_math_h-Non_member-helper-functions) 218are the prefered API,* as they remove type ambiguities and help prevent a number 219of common errors. The variadic functions can also be more performant, as they 220eliminate redundant expressions that are unavoidable with the with the operator 221overloads. (Ideally the compiler should optimize those away, but better to avoid 222them in the first place.) 223 224Type promotions are a slightly modified version of the [standard C/C++ numeric 225promotions 226](http://en.cppreference.com/w/cpp/language/implicit_conversion#Numeric_promotions) 227with the two differences being that *there is no default promotion to int* 228and *bitwise logical operations always return an unsigned of the wider type.* 229 230### Members 231 232The unary negation, increment, and decrement operators are supported, along 233with the following unary arithmetic methods, which return a new 234`CheckedNumeric` as a result of the operation: 235 236* `Abs()` - Absolute value. 237* `UnsignedAbs()` - Absolute value as an equal-width unsigned underlying type 238 (valid for only integral types). 239* `Max()` - Returns whichever is greater of the current instance or argument. 240 The underlying return type is whichever has the greatest magnitude. 241* `Min()` - Returns whichever is lowest of the current instance or argument. 242 The underlying return type is whichever has can represent the lowest 243 number in the smallest width (e.g. int8_t over unsigned, int over 244 int8_t, and float over int). 245 246The following are for converting `CheckedNumeric` instances: 247 248* `type` - The underlying numeric type. 249* `AssignIfValid()` - Assigns the underlying value to the supplied 250 destination pointer if the value is currently valid and within the 251 range supported by the destination type. Returns true on success. 252* `Cast<>()` - Instance method returning a `CheckedNumeric` derived from 253 casting the current instance to a `CheckedNumeric` of the supplied 254 destination type. 255 256*** aside 257The following member functions return a `StrictNumeric`, which is valid for 258comparison and assignment operations, but will trigger a compile failure on 259attempts to assign to a type of insufficient range. The underlying value can 260be extracted by an explicit `static_cast` to the underlying type or any type 261with sufficient range to represent the underlying type. 262*** 263 264* `IsValid()` - Returns true if the underlying numeric value is valid (i.e. 265 has not wrapped or saturated and is not the result of an invalid 266 conversion). 267* `ValueOrDie()` - Returns the underlying value. If the state is not valid 268 this call will trigger a crash by default (but may be overridden by 269 supplying an alternate handler to the template). 270* `ValueOrDefault()` - Returns the current value, or the supplied default if 271 the state is not valid (but will not crash). 272 273**Comparison operators are explicitly not provided** for `CheckedNumeric` 274types because they could result in a crash if the type is not in a valid state. 275Patterns like the following should be used instead: 276 277```cpp 278// Either input or padding (or both) may be arbitrary sizes. 279size_t buff_size; 280if (!CheckAdd(input, padding, kHeaderLength).AssignIfValid(&buff_size) || 281 buff_size >= kMaxBuffer) { 282 // Handle an error... 283} else { 284 // Do stuff on success... 285} 286``` 287 288### Non-member helper functions 289 290The following variadic convenience functions, which accept standard arithmetic 291or `CheckedNumeric` types, perform arithmetic operations, and return a 292`CheckedNumeric` result. The supported functions are: 293 294* `CheckAdd()` - Addition. 295* `CheckSub()` - Subtraction. 296* `CheckMul()` - Multiplication. 297* `CheckDiv()` - Division. 298* `CheckMod()` - Modulus (integer only). 299* `CheckLsh()` - Left integer shift (integer only). 300* `CheckRsh()` - Right integer shift (integer only). 301* `CheckAnd()` - Bitwise AND (integer only with unsigned result). 302* `CheckOr()` - Bitwise OR (integer only with unsigned result). 303* `CheckXor()` - Bitwise XOR (integer only with unsigned result). 304* `CheckMax()` - Maximum of supplied arguments. 305* `CheckMin()` - Minimum of supplied arguments. 306 307The following wrapper functions can be used to avoid the template 308disambiguator syntax when converting a destination type. 309 310* `IsValidForType<>()` in place of: `a.template IsValid<>()` 311* `ValueOrDieForType<>()` in place of: `a.template ValueOrDie<>()` 312* `ValueOrDefaultForType<>()` in place of: `a.template ValueOrDefault<>()` 313 314The following general utility methods is are useful for converting from 315arithmetic types to `CheckedNumeric` types: 316 317* `MakeCheckedNum()` - Creates a new `CheckedNumeric` from the underlying type 318 of the supplied arithmetic or directly convertible type. 319 320## ClampedNumeric<> in clamped_math.h 321 322`ClampedNumeric<>` implements all the logic and operators for clamped 323(non-sticky saturating) arithmetic operations and conversions. The 324`ClampedNumeric` type implicitly converts back and forth between floating point 325and integer data types, saturating on assignment as appropriate. It contains 326overloads for basic arithmetic operations (i.e.: `+`, `-`, `*`, `/` for 327all types and `%`, `<<`, `>>`, `&`, `|`, `^` for integers) along with comparison 328operators for arithmetic types of any size. However, *the [variadic template 329functions 330](#ClampedNumeric_in-clamped_math_h-Non_member-helper-functions) 331are the prefered API,* as they remove type ambiguities and help prevent 332a number of common errors. The variadic functions can also be more performant, 333as they eliminate redundant expressions that are unavoidable with the operator 334overloads. (Ideally the compiler should optimize those away, but better to avoid 335them in the first place.) 336 337Type promotions are a slightly modified version of the [standard C/C++ numeric 338promotions 339](http://en.cppreference.com/w/cpp/language/implicit_conversion#Numeric_promotions) 340with the two differences being that *there is no default promotion to int* 341and *bitwise logical operations always return an unsigned of the wider type.* 342 343*** aside 344Most arithmetic operations saturate normally, to the numeric limit in the 345direction of the sign. The potentially unusual cases are: 346 347* **Division:** Division by zero returns the saturated limit in the direction 348 of sign of the dividend (first argument). The one exception is 0/0, which 349 returns zero (although logically is NaN). 350* **Modulus:** Division by zero returns the dividend (first argument). 351* **Left shift:** Non-zero values saturate in the direction of the signed 352 limit (max/min), even for shifts larger than the bit width. 0 shifted any 353 amount results in 0. 354* **Right shift:** Negative values saturate to -1. Positive or 0 saturates 355 to 0. (Effectively just an unbounded arithmetic-right-shift.) 356* **Bitwise operations:** No saturation; bit pattern is identical to 357 non-saturated bitwise operations. 358*** 359 360### Members 361 362The unary negation, increment, and decrement operators are supported, along 363with the following unary arithmetic methods, which return a new 364`ClampedNumeric` as a result of the operation: 365 366* `Abs()` - Absolute value. 367* `UnsignedAbs()` - Absolute value as an equal-width unsigned underlying type 368 (valid for only integral types). 369* `Max()` - Returns whichever is greater of the current instance or argument. 370 The underlying return type is whichever has the greatest magnitude. 371* `Min()` - Returns whichever is lowest of the current instance or argument. 372 The underlying return type is whichever has can represent the lowest 373 number in the smallest width (e.g. int8_t over unsigned, int over 374 int8_t, and float over int). 375 376The following are for converting `ClampedNumeric` instances: 377 378* `type` - The underlying numeric type. 379* `RawValue()` - Returns the raw value as the underlying arithmetic type. This 380 is useful when e.g. assigning to an auto type or passing as a deduced 381 template parameter. 382* `Cast<>()` - Instance method returning a `ClampedNumeric` derived from 383 casting the current instance to a `ClampedNumeric` of the supplied 384 destination type. 385 386### Non-member helper functions 387 388The following variadic convenience functions, which accept standard arithmetic 389or `ClampedNumeric` types, perform arithmetic operations, and return a 390`ClampedNumeric` result. The supported functions are: 391 392* `ClampAdd()` - Addition. 393* `ClampSub()` - Subtraction. 394* `ClampMul()` - Multiplication. 395* `ClampDiv()` - Division. 396* `ClampMod()` - Modulus (integer only). 397* `ClampLsh()` - Left integer shift (integer only). 398* `ClampRsh()` - Right integer shift (integer only). 399* `ClampAnd()` - Bitwise AND (integer only with unsigned result). 400* `ClampOr()` - Bitwise OR (integer only with unsigned result). 401* `ClampXor()` - Bitwise XOR (integer only with unsigned result). 402* `ClampMax()` - Maximum of supplied arguments. 403* `ClampMin()` - Minimum of supplied arguments. 404 405The following is a general utility method that is useful for converting 406to a `ClampedNumeric` type: 407 408* `MakeClampedNum()` - Creates a new `ClampedNumeric` from the underlying type 409 of the supplied arithmetic or directly convertible type. 410