There is a new version of this funcitonality under a new name: PSsMOIN (simpe modulo arithmetic integers) with 2 C++20 only implementations, one same as this one with enum class types and another one with class types wrapping the integers. While as of today both gcc and clang generate (almost) identical code for both versions, other compilers create much less efficient code for the class types than for the enumeration types. Note, types should only be a compile-time thing (unless they aren't).
The error handling is still somehow configurable but with fewer knobs. You either get an exception throwing a char const * with an error message or one can opt for getting a signal SIGFPE for invalid operations.
PSsMOIN is accompanied by updated versions of the following variations of safer integer replacement types:
It turned out that signed integer division and sign extension is harder to get right than I naïvely thought. However, more test cases helped to figure out the corner cases either not covered, or causing UB. If you are already using this library, please update!
A C++20 implementation of safe (wrap around) integers following MISRA C++ rules.
An #ifdefed C++17 implementation is available in branch C++17.
It provides the following types in namspace psssint and corresponding UDL operators in namespace psssint::literals:
// unsigned
enum class ui8; auto a = 1_ui8;
enum class ui16; auto b = 2_ui16;
enum class ui32; auto c = 3_ui32;
enum class ui64; auto d = 4_ui64;
// signed
enum class si8; auto e = 5_si8;
enum class si16; auto f = 6_si16;
enum class si32; auto g = 7_si32;
enum class si64; auto h = 8_si64;You can play around with it on compiler explorer starting here
Some extra features:
- an output operator is defined and will output
ui8andsi8as integer values. - The UDL operators check for range.
- not recommended features:
to_int(val)promotes the safe integer val to built-in integer keeping its signednessto_underlying(val)allows access to the underlying-type's value, use with care in operations because of promotion. This is useful for existing function overloads.from_int(val)converts one of the allowed integer type's value to corresponding safe integer type. This is useful for integration with not-yet adapted code. Prevents conversion fromcharandbool, Note that depending on the definition of the types in<cstdint>not all built-in integer types will convert, for example, ifstd::int32_tis defined asintandstd::int64_tis defined aslong long, you cannot convert a42L, because its conversion rank differs from both.from_int_to<safeinttype>(val)converts integer to safe integer type with range check (throws if mismatch).
The following MISRA C++ recommendations for integer usage are implemented:
- No mixing of signed and unsigned types or with any standard-defined arithmetic types
- Integral promotion (only when mixing types in operations) will keep signedness
- Operations using the same operand type result in said type (no implicit promotion)
- Operations using mixed types of the same signedness promote to the bigger type first
- All operations wrap safely (2's complement), even for signed operands and small unsigned operands
- Bitwise operations are only defined for unsigned types
- Negation is only defined for signed types
- Comparison is only available through operands of the same type, using built-in comparison (
<=>in 20)
What else do you want?