Unsigned Integer Types
Description
The library provides safe unsigned integer types that detect overflow, underflow, and other undefined behavior at runtime. These types are drop-in replacements for the standard unsigned integer types with added safety guarantees.
| Type | Underlying Type | Width | Min | Max |
|---|---|---|---|---|
|
|
8 bits |
0 |
255 |
|
|
16 bits |
0 |
65,535 |
|
|
32 bits |
0 |
4,294,967,295 |
|
|
64 bits |
0 |
18,446,744,073,709,551,615 |
|
|
128 bits |
0 |
340,282,366,920,938,463,463,374,607,431,768,211,455 |
Each type exposes a basis_type member type alias that refers to the underlying integer type, allowing conversion back to built-in types when needed.
#include <boost/safe_numbers/unsigned_integers.hpp>
namespace boost::safe_numbers {
using u8 = detail::unsigned_integer_basis<std::uint8_t>;
using u16 = detail::unsigned_integer_basis<std::uint16_t>;
using u32 = detail::unsigned_integer_basis<std::uint32_t>;
using u64 = detail::unsigned_integer_basis<std::uint64_t>;
using u128 = detail::unsigned_integer_basis<int128::uint128_t>;
template <unsigned_integral BasisType>
class unsigned_integer_basis {
public:
using basis_type = BasisType;
// Construction
constexpr unsigned_integer_basis() noexcept = default;
explicit constexpr unsigned_integer_basis(BasisType val) noexcept;
template <typename T>
requires std::is_same_v<T, bool>
explicit constexpr unsigned_integer_basis(T) noexcept = delete; // bool prohibited
// Conversion to underlying types
template <unsigned_integral OtherBasis>
explicit constexpr operator OtherBasis() const noexcept;
// Comparison operators
friend constexpr auto operator<=>(unsigned_integer_basis lhs, unsigned_integer_basis rhs) noexcept
-> std::strong_ordering = default;
// Compound assignment operators
template <unsigned_integral OtherBasis>
constexpr auto operator+=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator-=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator*=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator/=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator%=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
// Increment and decrement operators
constexpr auto operator++() -> unsigned_integer_basis&;
constexpr auto operator++(int) -> unsigned_integer_basis;
constexpr auto operator--() -> unsigned_integer_basis&;
constexpr auto operator--(int) -> unsigned_integer_basis;
}; // class unsigned_integer_basis
// Arithmetic operators (throw on overflow/underflow)
template <unsigned_integral BasisType>
constexpr auto operator+(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator-(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator*(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator/(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator%(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
// Saturating arithmetic (clamp to min/max on overflow/underflow)
template <UnsignedLibType T>
constexpr T saturating_add(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T saturating_sub(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T saturating_mul(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T saturating_div(T lhs, T rhs);
template <UnsignedLibType T>
constexpr T saturating_mod(T lhs, T rhs);
// Overflowing arithmetic (wrap and return overflow flag)
template <UnsignedLibType T>
constexpr std::pair<T, bool> overflowing_add(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr std::pair<T, bool> overflowing_sub(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr std::pair<T, bool> overflowing_mul(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr std::pair<T, bool> overflowing_div(T lhs, T rhs);
template <UnsignedLibType T>
constexpr std::pair<T, bool> overflowing_mod(T lhs, T rhs);
// Checked arithmetic (return std::nullopt on overflow/underflow)
template <UnsignedLibType T>
constexpr std::optional<T> checked_add(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr std::optional<T> checked_sub(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr std::optional<T> checked_mul(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr std::optional<T> checked_div(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr std::optional<T> checked_mod(T lhs, T rhs) noexcept;
// Wrapping arithmetic (wrap without indication)
template <UnsignedLibType T>
constexpr T wrapping_add(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T wrapping_sub(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T wrapping_mul(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T wrapping_div(T lhs, T rhs);
template <UnsignedLibType T>
constexpr T wrapping_mod(T lhs, T rhs);
// Strict arithmetic (call std::exit(EXIT_FAILURE) on error)
template <UnsignedLibType T>
constexpr T strict_add(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T strict_sub(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T strict_mul(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T strict_div(T lhs, T rhs) noexcept;
template <UnsignedLibType T>
constexpr T strict_mod(T lhs, T rhs) noexcept;
// Generic policy-parameterized arithmetic
template <overflow_policy Policy, UnsignedLibType T>
constexpr auto add(T lhs, T rhs);
template <overflow_policy Policy, UnsignedLibType T>
constexpr auto sub(T lhs, T rhs);
template <overflow_policy Policy, UnsignedLibType T>
constexpr auto mul(T lhs, T rhs);
template <overflow_policy Policy, UnsignedLibType T>
constexpr auto div(T lhs, T rhs);
template <overflow_policy Policy, UnsignedLibType T>
constexpr auto mod(T lhs, T rhs);
} // namespace boost::safe_numbers
Operator Behavior
Default Construction
constexpr unsigned_integer_basis() noexcept = default;
Values are default-initialized to zero.
Construction from Underlying Type
explicit constexpr unsigned_integer_basis(BasisType val) noexcept;
Construction from the underlying type is explicit to prevent accidental conversions.
Construction from bool
template <typename T>
requires std::is_same_v<T, bool>
explicit constexpr unsigned_integer_basis(T) noexcept = delete;
Constructing from bool is a compile-time error.
Conversion to Underlying Types
template <unsigned_integral OtherBasis>
explicit constexpr operator OtherBasis() const noexcept;
Conversion to other unsigned integral types is explicit. Narrowing conversions cause a compile-time error.
Comparison Operators
friend constexpr auto operator<=>(unsigned_integer_basis lhs, unsigned_integer_basis rhs) noexcept
-> std::strong_ordering = default;
Full three-way comparison is supported via operator<=>, which returns std::strong_ordering.
All comparison operators (<, ⇐, >, >=, ==, !=) are available.
Arithmetic Operators
template <unsigned_integral BasisType>
constexpr auto operator+(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator-(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator*(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator/(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
template <unsigned_integral BasisType>
constexpr auto operator%(unsigned_integer_basis<BasisType> lhs,
unsigned_integer_basis<BasisType> rhs) -> unsigned_integer_basis<BasisType>;
All arithmetic operators perform runtime checks and throw exceptions when undefined behavior would occur:
-
+: Throwsstd::overflow_errorif the result exceeds the maximum representable value -
-: Throwsstd::underflow_errorif the result would be negative (wrap around) -
*: Throwsstd::overflow_errorif the result exceeds the maximum representable value -
/: Throwsstd::domain_errorif dividing by zero -
%: Throwsstd::domain_errorif the divisor is zero
Compound Assignment Operators
template <unsigned_integral OtherBasis>
constexpr auto operator+=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator-=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator*=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator/=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
template <unsigned_integral OtherBasis>
constexpr auto operator%=(unsigned_integer_basis<OtherBasis> rhs) -> unsigned_integer_basis&;
Compound assignment operators follow the same exception behavior as their corresponding arithmetic operators.
Increment and Decrement Operators
constexpr auto operator++() -> unsigned_integer_basis&;
constexpr auto operator++(int) -> unsigned_integer_basis;
constexpr auto operator--() -> unsigned_integer_basis&;
constexpr auto operator--(int) -> unsigned_integer_basis;
-
++(pre/post): Throwsstd::overflow_errorif the value is already at the maximum -
--(pre/post): Throwsstd::underflow_errorif the value is already zero
Alternative Arithmetic Functions
For cases where throwing exceptions is not desired, alternative arithmetic functions are provided with different overflow handling policies. See Overflow Policies for full documentation of all policies, named arithmetic functions, and the generic policy-parameterized interface.