Skip to content

Commit 517f760

Browse files
authored
Merge pull request #167 from cppalliance/131
Add policy based free functions for signed integers
2 parents 77df19f + e7b1876 commit 517f760

24 files changed

Lines changed: 3826 additions & 105 deletions

doc/modules/ROOT/pages/signed_integers.adoc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,91 @@ auto b = i32{200};
148148
// auto result = a + b; // Compile error: mismatched types
149149
auto result = static_cast<i32>(a) + b; // OK: explicit promotion
150150
----
151+
152+
== Policy-Based Arithmetic Functions
153+
154+
In addition to the default operators (which throw on overflow/underflow), signed integer types support the same policy-based free functions as unsigned types.
155+
See xref:policies.adoc[] for a detailed description of each overflow policy.
156+
157+
=== Saturating Arithmetic
158+
159+
Saturating operations clamp the result to `std::numeric_limits<T>::max()` on overflow or `std::numeric_limits<T>::min()` on underflow, rather than throwing.
160+
161+
[source,c++]
162+
----
163+
template <SignedLibType T> constexpr T saturating_add(T lhs, T rhs) noexcept;
164+
template <SignedLibType T> constexpr T saturating_sub(T lhs, T rhs) noexcept;
165+
template <SignedLibType T> constexpr T saturating_mul(T lhs, T rhs) noexcept;
166+
template <SignedLibType T> constexpr T saturating_div(T lhs, T rhs); // throws on div-by-zero
167+
template <SignedLibType T> constexpr T saturating_mod(T lhs, T rhs); // throws on mod-by-zero
168+
----
169+
170+
NOTE: Division by zero always throws `std::domain_error`, even with the saturating policy. The `min / -1` overflow case saturates to `max()`. The `min % -1` case returns `0`.
171+
172+
=== Overflowing Arithmetic
173+
174+
Overflowing operations return a `std::pair<T, bool>` where the bool indicates whether overflow or underflow occurred. The result wraps on overflow (two's complement behavior).
175+
176+
[source,c++]
177+
----
178+
template <SignedLibType T> constexpr std::pair<T, bool> overflowing_add(T lhs, T rhs) noexcept;
179+
template <SignedLibType T> constexpr std::pair<T, bool> overflowing_sub(T lhs, T rhs) noexcept;
180+
template <SignedLibType T> constexpr std::pair<T, bool> overflowing_mul(T lhs, T rhs) noexcept;
181+
template <SignedLibType T> constexpr std::pair<T, bool> overflowing_div(T lhs, T rhs); // throws on div-by-zero
182+
template <SignedLibType T> constexpr std::pair<T, bool> overflowing_mod(T lhs, T rhs); // throws on mod-by-zero
183+
----
184+
185+
NOTE: Division by zero still throws `std::domain_error`. The `min / -1` case returns `(min, true)`. The `min % -1` case returns `(0, true)`.
186+
187+
=== Checked Arithmetic
188+
189+
Checked operations return `std::optional<T>`. If the operation would overflow, underflow, or divide by zero, `std::nullopt` is returned.
190+
191+
[source,c++]
192+
----
193+
template <SignedLibType T> constexpr std::optional<T> checked_add(T lhs, T rhs) noexcept;
194+
template <SignedLibType T> constexpr std::optional<T> checked_sub(T lhs, T rhs) noexcept;
195+
template <SignedLibType T> constexpr std::optional<T> checked_mul(T lhs, T rhs) noexcept;
196+
template <SignedLibType T> constexpr std::optional<T> checked_div(T lhs, T rhs) noexcept;
197+
template <SignedLibType T> constexpr std::optional<T> checked_mod(T lhs, T rhs) noexcept;
198+
----
199+
200+
NOTE: All checked operations are `noexcept`. Division by zero and `min / -1` both return `std::nullopt`.
201+
202+
=== Strict Arithmetic
203+
204+
Strict operations call `std::exit(EXIT_FAILURE)` on overflow, underflow, or (for div/mod) division by zero.
205+
206+
[source,c++]
207+
----
208+
template <SignedLibType T> constexpr T strict_add(T lhs, T rhs) noexcept;
209+
template <SignedLibType T> constexpr T strict_sub(T lhs, T rhs) noexcept;
210+
template <SignedLibType T> constexpr T strict_mul(T lhs, T rhs) noexcept;
211+
template <SignedLibType T> constexpr T strict_div(T lhs, T rhs) noexcept;
212+
template <SignedLibType T> constexpr T strict_mod(T lhs, T rhs) noexcept;
213+
----
214+
215+
=== Widening Arithmetic
216+
217+
Widening operations return the result in the next wider signed integer type, guaranteeing no overflow. Only available for addition and multiplication.
218+
219+
[source,c++]
220+
----
221+
template <SignedLibType T> constexpr auto widening_add(T lhs, T rhs) noexcept;
222+
template <SignedLibType T> constexpr auto widening_mul(T lhs, T rhs) noexcept;
223+
----
224+
225+
NOTE: Widening is not supported for `i128` (there is no wider signed type). Attempting to use it with `i128` is a compile-time error.
226+
227+
=== Generic Policy-Parameterized Arithmetic
228+
229+
These functions accept an `overflow_policy` template parameter and dispatch to the corresponding named function above.
230+
231+
[source,c++]
232+
----
233+
template <overflow_policy Policy, SignedLibType T> constexpr auto add(T lhs, T rhs);
234+
template <overflow_policy Policy, SignedLibType T> constexpr auto sub(T lhs, T rhs);
235+
template <overflow_policy Policy, SignedLibType T> constexpr auto mul(T lhs, T rhs);
236+
template <overflow_policy Policy, SignedLibType T> constexpr auto div(T lhs, T rhs);
237+
template <overflow_policy Policy, SignedLibType T> constexpr auto mod(T lhs, T rhs);
238+
----

0 commit comments

Comments
 (0)