README.md
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