Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
888f975
Add a basis for a verified type
mborland Feb 12, 2026
9f44d64
Add concrete types
mborland Feb 12, 2026
57b8ef0
Add static and runtime testing of the verified types
mborland Feb 12, 2026
8e93935
Overload type traits for our base class
mborland Feb 12, 2026
1abe195
Add testing of ostream operator
mborland Feb 12, 2026
52a5c4a
Change istream concept to not allow consteval type
mborland Feb 12, 2026
b44bebd
Mark all the bit functions as [[nodiscard]]
mborland Feb 12, 2026
b066994
Add testing of the bit functions
mborland Feb 12, 2026
525c768
Add consteval only overloads for the verified types
mborland Feb 12, 2026
8929861
Test charconv and add consteval from_chars
mborland Feb 12, 2026
5829f69
Test integration with {fmt}
mborland Feb 12, 2026
ed506ca
Test integration with <format>
mborland Feb 12, 2026
2f24db3
Add numeric limits specialization
mborland Feb 12, 2026
6552c3e
Add testing of numeric limits
mborland Feb 12, 2026
747e7de
Add examples of new verified integers
mborland Feb 12, 2026
9cdd713
Add new page for the verified integers
mborland Feb 12, 2026
3f1b5db
Update types and headers
mborland Feb 12, 2026
34e22e9
Add examples of new types
mborland Feb 12, 2026
1f2b301
Document special behavior of these types
mborland Feb 12, 2026
e24b5fc
Fix copy-paste error
mborland Feb 12, 2026
f54a138
Fix example
mborland Feb 12, 2026
abbac7d
Improve mixed operations warnings
mborland Feb 12, 2026
27482cb
Add macro for comparisons for basic unsigned integers
mborland Feb 12, 2026
9d5faa0
Improve error message of comparison operators
mborland Feb 12, 2026
f2c46be
Remove runners that aren't actually running
mborland Feb 12, 2026
e0ec3bc
Drop clang-13, 14, and 15 due to consteval ICE
mborland Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ jobs:
uses: boostorg/boost-ci/.github/workflows/reusable.yml@master
with:
exclude_compiler: 'clang-3.5,clang-3.6,clang-3.7,clang-3.8,clang-3.9,clang-4.0,clang-5.0,clang-6.0,clang-7,
clang-8,clang-9,clang-10,
gcc-4.7,gcc-4.8,gcc-4.9,gcc-5,gcc-6,gcc-7,gcc-8'
clang-8,clang-9,clang-10,clang-11,clang-12,clang-13,clang-14,clang-15,
gcc-4.7,gcc-4.8,gcc-4.9,gcc-5,gcc-6,gcc-7,gcc-8,gcc-9,gcc-10'
# Example of customization:
# with:
# enable_reflection: true
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A safe and fully featured replacement for C++ builtin numeric types.

This library requires C++20 and is tested on the following platforms:

* GCC 9 and later
* Clang 11 and later
* GCC 11 and later
* Clang 16 and later
* Visual Studio 2022 and later
* Intel OneAPI DPC++
5 changes: 5 additions & 0 deletions doc/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
** xref:examples.adoc#examples_fmt_format[Formatting]
** xref:examples.adoc#examples_iostream[Stream I/O]
** xref:examples.adoc#examples_bit[Bit Manipulation]
** xref:examples.adoc#examples_verified_construction[Verified Types: Construction]
** xref:examples.adoc#examples_verified_arithmetic[Verified Types: Arithmetic]
** xref:examples.adoc#examples_verified_runtime[Verified Types: Runtime Capabilities]
** xref:examples.adoc#examples_verified_compile_fail[Verified Types: Compile-Time Overflow]
* xref:pretty_printers.adoc[]
* xref:api_reference.adoc[]
** xref:api_reference.adoc#api_types[Types]
Expand All @@ -22,6 +26,7 @@
* xref:policies.adoc[]
* xref:unsigned_integers.adoc[]
* xref:bounded_uint.adoc[]
* xref:verified_integers.adoc[]
* xref:literals.adoc[]
* xref:limits.adoc[]
* xref:format.adoc[]
Expand Down
28 changes: 28 additions & 0 deletions doc/modules/ROOT/pages/api_reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@ https://www.boost.org/LICENSE_1_0.txt
| Safe unsigned integer constrained to a compile-time range `[Min, Max]`
|===

=== Verified Integer Types

[cols="1,2", options="header"]
|===
| Type | Description

| xref:verified_integers.adoc[`verified_u8`]
| Compile-time verified safe unsigned 8-bit integer

| xref:verified_integers.adoc[`verified_u16`]
| Compile-time verified safe unsigned 16-bit integer

| xref:verified_integers.adoc[`verified_u32`]
| Compile-time verified safe unsigned 32-bit integer

| xref:verified_integers.adoc[`verified_u64`]
| Compile-time verified safe unsigned 64-bit integer

| xref:verified_integers.adoc[`verified_u128`]
| Compile-time verified safe unsigned 128-bit integer

| xref:verified_integers.adoc[`verified_bounded_integer<Min, Max>`]
| Compile-time verified bounded unsigned integer constrained to `[Min, Max]`
|===

=== Enumerations

[cols="1,2", options="header"]
Expand Down Expand Up @@ -197,4 +222,7 @@ This header is not included in the convenience header since it requires external

| `<boost/safe_numbers/bounded_integers.hpp>`
| Bounded unsigned integer type (`bounded_uint<Min, Max>`)

| `<boost/safe_numbers/verified_integers.hpp>`
| Verified integer types (`verified_u8`, `verified_u16`, `verified_u32`, `verified_u64`, `verified_u128`, `verified_bounded_integer<Min, Max>`)
|===
25 changes: 25 additions & 0 deletions doc/modules/ROOT/pages/bit.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,31 @@ See https://en.cppreference.com/w/cpp/numeric/byteswap.html[`std::byteswap`].

NOTE: `byteswap` is not available for `bounded_uint` types. Byte reversal can produce values outside the valid bounded range, making the operation semantically meaningless for bounded integers.

== Verified Types

The bit functions have special behavior with xref:verified_integers.adoc[verified types]:

Functions that return `int` or `bool` (`has_single_bit`, `bit_width`, `countl_zero`, `countl_one`, `countr_zero`, `countr_one`, `popcount`) work at runtime with verified types.
These functions only read the value via the `constexpr` conversion operator.

Functions that return the safe type (`bit_ceil`, `bit_floor`, `rotl`, `rotr`, `byteswap`) have `consteval` overloads for verified types, meaning they can only be called at compile time.
The `consteval` overloads use a `requires` clause to distinguish them:

[source,c++]
----
// Runtime overload (non-verified types)
template <unsigned_library_type UnsignedInt>
requires (!is_verified_type_v<UnsignedInt>)
constexpr auto bit_ceil(UnsignedInt x) noexcept -> UnsignedInt;

// Compile-time overload (verified types only)
template <unsigned_library_type UnsignedInt>
requires is_verified_type_v<UnsignedInt>
consteval auto bit_ceil(UnsignedInt x) noexcept -> UnsignedInt;
----

The same pattern applies to `bit_floor`, `rotl`, `rotr`, and `byteswap`.

== Examples

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/bit.cpp[example] demonstrates the bit manipulation functions.
Expand Down
22 changes: 22 additions & 0 deletions doc/modules/ROOT/pages/charconv.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,28 @@ Returns `boost::charconv::from_chars_result` with:
- `ptr` pointing to the first character not matching the pattern
- `ec` set to `std::errc{}` on success, `std::errc::invalid_argument` if no valid conversion, or `std::errc::result_out_of_range` if the value overflows

== Verified Types

`to_chars` works at runtime with xref:verified_integers.adoc[verified types] since it only reads the value.

`from_chars` has a `consteval` overload for verified types -- it can only be used at compile time.
The two overloads are distinguished via a `requires` clause:

[source,c++]
----
// Runtime overload (non-verified types)
template <detail::library_type T>
requires (!detail::is_verified_type_v<T>)
constexpr auto from_chars(const char* first, const char* last,
T& value, int base = 10) -> charconv::from_chars_result;

// Compile-time overload (verified types only)
template <detail::library_type T>
requires detail::is_verified_type_v<T>
consteval auto from_chars(const char* first, const char* last,
T& value, int base = 10) -> charconv::from_chars_result;
----

== Examples

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/charconv.cpp[example] demonstrates how to use `to_chars` and `from_chars` with safe integer types.
Expand Down
111 changes: 111 additions & 0 deletions doc/modules/ROOT/pages/examples.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,117 @@ shr<checked>(u32(8), 1) = 4
----
====

[#examples_verified_construction]
== Verified Types: Construction and Runtime Usage

Verified types use `consteval` constructors and arithmetic, guaranteeing that all values are validated at compile time.
At runtime, verified types are read-only constants that support output streaming, explicit conversions, and comparisons.

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/verified_construction.cpp[example] demonstrates construction and runtime use of verified types.
====
[source, c++]
----
include::example$verified_construction.cpp[]
----

Output:
----
verified_u8: 42
verified_u16: 1000
verified_u32: 100000
verified_u64: 9999999999
verified_u32: 42

Converted to uint32_t: 100000
42 < 50000: true
42 == 42: true

percent: 50
----
====

[#examples_verified_arithmetic]
== Verified Types: Compile-Time Arithmetic

All arithmetic on verified types (`+`, `-`, `*`, `/`, `%`, `+=`, `++`, etc.) is `consteval` -- evaluated entirely by the compiler.
If an operation overflows, it produces a compile error instead of a runtime exception.

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/verified_arithmetic.cpp[example] demonstrates compile-time arithmetic with verified types.
====
[source, c++]
----
include::example$verified_arithmetic.cpp[]
----

Output:
----
100 + 200 = 300
200 - 100 = 100
15 * 20 = 300
300 / 10 = 30
17 % 5 = 2

10 after ++: 11
0 + 100 + 200 + 300 = 600

bounded 500 + 400 = 900
----
====

[#examples_verified_runtime]
== Verified Types: Runtime Capabilities

While construction and arithmetic are compile-time only, verified types support a wide range of runtime operations:
output streaming, explicit conversions, comparisons, `to_chars`, bit queries, and `std::numeric_limits`.

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/verified_runtime_usage.cpp[example] shows what verified types can do at runtime.
====
[source, c++]
----
include::example$verified_runtime_usage.cpp[]
----

Output:
----
Value: 1024
As uint32_t: 1024
As u32: 1024

10 == 10: true
10 != 50000: true
10 < 50000: true
10 >= 50000: false

to_chars (base 10): 1024
to_chars (base 16): 400

has_single_bit(1024) = true
bit_width(1024) = 11
countl_zero(1024) = 21
popcount(1024) = 1
bit_ceil(48) = 64
bit_floor(48) = 32

numeric_limits<verified_u8>::min() = 0
numeric_limits<verified_u8>::max() = 255
numeric_limits<verified_u32>::digits = 32
----
====

[#examples_verified_compile_fail]
== Verified Types: Compile-Time Overflow Detection

Verified types catch overflow at compile time.
Attempting to overflow a verified type produces a compiler error rather than a runtime exception.

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/compile_fail_verified_overflow.cpp[example] fails to compile because `u8(255) + u8(1)` overflows.
====
[source, c++]
----
include::example$compile_fail_verified_overflow.cpp[]
----
====

[#examples_policy_comparison]
== Policy Comparison

Expand Down
5 changes: 5 additions & 0 deletions doc/modules/ROOT/pages/format.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ The full format specifier order is:
{[fill][align][sign][#][0][width][.precision][L][type]}
----

== Verified Types

Formatting works with xref:verified_integers.adoc[verified types] through the `library_type` concept.
Both `std::format` and `pass:[{fmt}]` work at runtime via the `constexpr` conversion operator, since the formatter only reads the value.

== Examples

IMPORTANT: The header `<boost/safe_numbers/fmt_format.hpp>` is *NOT* part of the convenience header, because it is an optional dependency on a potentially compiled library.
Expand Down
17 changes: 17 additions & 0 deletions doc/modules/ROOT/pages/iostream.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@ Standard stream manipulators (`std::hex`, `std::oct`, `std::dec`, `std::setw`, e

For `u8`, the input is read as a `std::uint32_t` to avoid character interpretation, then narrowed to `std::uint8_t`.

== Verified Types

`operator>>` is not available for xref:verified_integers.adoc[verified types].
The overload is excluded via a `requires` clause:

[source,c++]
----
template <typename charT, typename traits, library_type LibType>
requires (!is_verified_type_v<LibType>)
auto operator>>(std::basic_istream<charT, traits>& is, LibType& v)
-> std::basic_istream<charT, traits>&;
----

This is by design: verified types can only be constructed at compile time, so reading a value from a stream into a verified type is not meaningful.

`operator<<` works normally with verified types via their `constexpr` conversion operator, since output only reads the value.

== Examples

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/iostream.cpp[example] demonstrates stream I/O with safe integer types.
Expand Down
31 changes: 31 additions & 0 deletions doc/modules/ROOT/pages/limits.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,37 @@ class numeric_limits<boost::safe_numbers::bounded_uint<Min, Max>>

NOTE: The non-applicable member functions (`epsilon`, `round_error`, `infinity`, `quiet_NaN`, `signaling_NaN`, `denorm_min`) return `min()` rather than a zero-constructed value, since zero may fall outside the valid range for types with a non-zero lower bound.

== Verified Integer Specialization

A partial specialization of `std::numeric_limits` is provided for all `verified_type_basis<BasisType>` types, including both `verified_u8`-`verified_u128` and `verified_bounded_integer<Min, Max>`.

[source,c++]
----
namespace std {

template <boost::safe_numbers::detail::library_type BasisType>
class numeric_limits<boost::safe_numbers::detail::verified_type_basis<BasisType>>
{
using type = boost::safe_numbers::detail::verified_type_basis<BasisType>;
using basis_limits = std::numeric_limits<BasisType>;

// Static member constants delegate to std::numeric_limits<BasisType>
// ...

static constexpr type min();
static constexpr type max();
static constexpr type lowest();
// ... remaining functions delegate to basis_limits
};

} // namespace std
----

Static properties and functions delegate to `std::numeric_limits<BasisType>` (the safe integer basis type, not the underlying fundamental type).
This means verified bounded types correctly report their bounded `min()` and `max()` values.

The `static constexpr` member functions work because constructing the verified type with a constant expression invokes the `consteval` constructor as an immediate invocation, which is permitted in a `constexpr` context.

=== Example

.This https://github.com/boostorg/safe_numbers/blob/develop/examples/bounded_limits.cpp[example] demonstrates `std::numeric_limits` with bounded integer types.
Expand Down
4 changes: 2 additions & 2 deletions doc/modules/ROOT/pages/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Safety critical applications
Boost.safe_numbers is tested natively on Ubuntu (x86_64, x86_32, s390x, aarch64, ARM32v7), macOS (x86_64, and Apple Silicon), and Windows (x86_64, x86_32, and ARM64);
as well as emulated PPC64LE using QEMU with the following compilers:

* GCC 9 and later
* Clang 11 and later
* GCC 11 and later
* Clang 16 and later
* Visual Studio 2022 (14.3) and later
* Intel OneAPI DPC++ 2024.2 and later

Expand Down
Loading