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