Skip to content

Commit 03c19e9

Browse files
H-G-HristovZingammordante
authored
[libc++][numeric] P0543R3: Saturation arithmetic (#77967)
Implements: https://wg21.link/P0543R3 - https://eel.is/c++draft/numeric.sat Additional references: - Division: https://eel.is/c++draft/expr.mul#4 - Arithmetic conversions: https://eel.is/c++draft/expr.arith.conv#1 - Clang builtins: https://clang.llvm.org/docs/LanguageExtensions.html#builtin-functions Depends on: #78086 --------- Co-authored-by: Zingam <zingam@outlook.com> Co-authored-by: Mark de Wever <zar-rpg@xs4all.nl>
1 parent 85337df commit 03c19e9

24 files changed

+1697
-29
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ Status
432432
--------------------------------------------------- -----------------
433433
``__cpp_lib_rcu`` *unimplemented*
434434
--------------------------------------------------- -----------------
435-
``__cpp_lib_saturation_arithmetic`` *unimplemented*
435+
``__cpp_lib_saturation_arithmetic`` ``202311L``
436436
--------------------------------------------------- -----------------
437437
``__cpp_lib_smart_ptr_owner_equality`` *unimplemented*
438438
--------------------------------------------------- -----------------

libcxx/docs/ReleaseNotes/18.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Implemented Papers
7575
- P2909R4 - Fix formatting of code units as integers (Dude, where’s my ``char``?)
7676
- P2821R5 - ``span.at()``
7777
- P0521R0 - Proposed Resolution for CA 14 (``shared_ptr`` ``use_count/unique``)
78+
- P0543R3 - Saturation arithmetic
7879
- P1759R6 - Native handles and file streams
7980
- P2868R3 - Remove Deprecated ``std::allocator`` Typedef From C++26
8081
- P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply``

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"`P2714R1 <https://wg21.link/P2714R1>`__","LWG","Bind front and back to NTTP callables","Varna June 2023","","",""
2828
"`P2630R4 <https://wg21.link/P2630R4>`__","LWG","``submdspan``","Varna June 2023","","",""
2929
"","","","","","",""
30-
"`P0543R3 <https://wg21.link/P0543R3>`__","LWG","Saturation arithmetic","Kona November 2023","","",""
30+
"`P0543R3 <https://wg21.link/P0543R3>`__","LWG","Saturation arithmetic","Kona November 2023","|Complete|","18.0",""
3131
"`P2407R5 <https://wg21.link/P2407R5>`__","LWG","Freestanding Library: Partial Classes","Kona November 2023","","",""
3232
"`P2546R5 <https://wg21.link/P2546R5>`__","LWG","Debugging Support","Kona November 2023","","",""
3333
"`P2905R2 <https://wg21.link/P2905R2>`__","LWG","Runtime format strings","Kona November 2023","|Complete|","18.0","|format| |DR|"

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ set(files
569569
__numeric/pstl_reduce.h
570570
__numeric/pstl_transform_reduce.h
571571
__numeric/reduce.h
572+
__numeric/saturation_arithmetic.h
572573
__numeric/transform_exclusive_scan.h
573574
__numeric/transform_inclusive_scan.h
574575
__numeric/transform_reduce.h
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
11+
#define _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
12+
13+
#include <__concepts/arithmetic.h>
14+
#include <__config>
15+
#include <__utility/cmp.h>
16+
#include <limits>
17+
18+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19+
# pragma GCC system_header
20+
#endif
21+
22+
_LIBCPP_BEGIN_NAMESPACE_STD
23+
24+
#if _LIBCPP_STD_VER >= 26
25+
26+
template <__libcpp_integer _Tp>
27+
_LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept {
28+
if (_Tp __sum; !__builtin_add_overflow(__x, __y, &__sum))
29+
return __sum;
30+
// Handle overflow
31+
if constexpr (__libcpp_unsigned_integer<_Tp>) {
32+
return std::numeric_limits<_Tp>::max();
33+
} else {
34+
// Signed addition overflow
35+
if (__x > 0)
36+
// Overflows if (x > 0 && y > 0)
37+
return std::numeric_limits<_Tp>::max();
38+
else
39+
// Overflows if (x < 0 && y < 0)
40+
return std::numeric_limits<_Tp>::min();
41+
}
42+
}
43+
44+
template <__libcpp_integer _Tp>
45+
_LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept {
46+
if (_Tp __sub; !__builtin_sub_overflow(__x, __y, &__sub))
47+
return __sub;
48+
// Handle overflow
49+
if constexpr (__libcpp_unsigned_integer<_Tp>) {
50+
// Overflows if (x < y)
51+
return std::numeric_limits<_Tp>::min();
52+
} else {
53+
// Signed subtration overflow
54+
if (__x >= 0)
55+
// Overflows if (x >= 0 && y < 0)
56+
return std::numeric_limits<_Tp>::max();
57+
else
58+
// Overflows if (x < 0 && y > 0)
59+
return std::numeric_limits<_Tp>::min();
60+
}
61+
}
62+
63+
template <__libcpp_integer _Tp>
64+
_LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept {
65+
if (_Tp __mul; !__builtin_mul_overflow(__x, __y, &__mul))
66+
return __mul;
67+
// Handle overflow
68+
if constexpr (__libcpp_unsigned_integer<_Tp>) {
69+
return std::numeric_limits<_Tp>::max();
70+
} else {
71+
// Signed multiplication overflow
72+
if ((__x > 0 && __y > 0) || (__x < 0 && __y < 0))
73+
return std::numeric_limits<_Tp>::max();
74+
// Overflows if (x < 0 && y > 0) || (x > 0 && y < 0)
75+
return std::numeric_limits<_Tp>::min();
76+
}
77+
}
78+
79+
template <__libcpp_integer _Tp>
80+
_LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept {
81+
_LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined");
82+
if constexpr (__libcpp_unsigned_integer<_Tp>) {
83+
return __x / __y;
84+
} else {
85+
// Handle signed division overflow
86+
if (__x == std::numeric_limits<_Tp>::min() && __y == _Tp{-1})
87+
return std::numeric_limits<_Tp>::max();
88+
return __x / __y;
89+
}
90+
}
91+
92+
template <__libcpp_integer _Rp, __libcpp_integer _Tp>
93+
_LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept {
94+
// Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be
95+
// optimized out by the compiler.
96+
97+
// Handle overflow
98+
if (std::cmp_less(__x, std::numeric_limits<_Rp>::min()))
99+
return std::numeric_limits<_Rp>::min();
100+
if (std::cmp_greater(__x, std::numeric_limits<_Rp>::max()))
101+
return std::numeric_limits<_Rp>::max();
102+
// No overflow
103+
return static_cast<_Rp>(__x);
104+
}
105+
106+
#endif // _LIBCPP_STD_VER >= 26
107+
108+
_LIBCPP_END_NAMESPACE_STD
109+
110+
#endif // _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H

libcxx/include/libcxx.imp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@
559559
{ include: [ "<__numeric/pstl_reduce.h>", "private", "<numeric>", "public" ] },
560560
{ include: [ "<__numeric/pstl_transform_reduce.h>", "private", "<numeric>", "public" ] },
561561
{ include: [ "<__numeric/reduce.h>", "private", "<numeric>", "public" ] },
562+
{ include: [ "<__numeric/saturation_arithmetic.h>", "private", "<numeric>", "public" ] },
562563
{ include: [ "<__numeric/transform_exclusive_scan.h>", "private", "<numeric>", "public" ] },
563564
{ include: [ "<__numeric/transform_inclusive_scan.h>", "private", "<numeric>", "public" ] },
564565
{ include: [ "<__numeric/transform_reduce.h>", "private", "<numeric>", "public" ] },

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,7 @@ module std_private_numeric_pstl_transform_reduce [system] {
15801580
export *
15811581
}
15821582
module std_private_numeric_reduce [system] { header "__numeric/reduce.h" }
1583+
module std_private_numeric_saturation_arithmetic [system] { header "__numeric/saturation_arithmetic.h" }
15831584
module std_private_numeric_transform_exclusive_scan [system] { header "__numeric/transform_exclusive_scan.h" }
15841585
module std_private_numeric_transform_inclusive_scan [system] { header "__numeric/transform_inclusive_scan.h" }
15851586
module std_private_numeric_transform_reduce [system] { header "__numeric/transform_reduce.h" }

libcxx/include/numeric

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,18 @@ template<class T>
140140
template<class T>
141141
constexpr T* midpoint(T* a, T* b); // C++20
142142
143+
// [numeric.sat], saturation arithmetic
144+
template<class T>
145+
constexpr T add_sat(T x, T y) noexcept; // freestanding, Since C++26
146+
template<class T>
147+
constexpr T sub_sat(T x, T y) noexcept; // freestanding, Since C++26
148+
template<class T>
149+
constexpr T mul_sat(T x, T y) noexcept; // freestanding, Since C++26
150+
template<class T>
151+
constexpr T div_sat(T x, T y) noexcept; // freestanding, Since C++26
152+
template<class T, class U>
153+
constexpr T saturate_cast(U x) noexcept; // freestanding, Since C++26
154+
143155
} // std
144156
145157
*/
@@ -160,6 +172,7 @@ template<class T>
160172
#include <__numeric/pstl_reduce.h>
161173
#include <__numeric/pstl_transform_reduce.h>
162174
#include <__numeric/reduce.h>
175+
#include <__numeric/saturation_arithmetic.h>
163176
#include <__numeric/transform_exclusive_scan.h>
164177
#include <__numeric/transform_inclusive_scan.h>
165178
#include <__numeric/transform_reduce.h>

libcxx/include/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
504504
// # define __cpp_lib_out_ptr 202311L
505505
# define __cpp_lib_ratio 202306L
506506
// # define __cpp_lib_rcu 202306L
507-
// # define __cpp_lib_saturation_arithmetic 202311L
507+
# define __cpp_lib_saturation_arithmetic 202311L
508508
// # define __cpp_lib_smart_ptr_owner_equality 202306L
509509
# define __cpp_lib_span_at 202311L
510510
# define __cpp_lib_span_initializer_list 202311L

libcxx/modules/std/numeric.inc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,14 @@ export namespace std {
5454

5555
// [numeric.ops.midpoint], midpoint
5656
using std::midpoint;
57+
58+
#if _LIBCPP_STD_VER >= 26
59+
// [numeric.sat], saturation arithmetic
60+
using std::add_sat;
61+
using std::div_sat;
62+
using std::mul_sat;
63+
using std::saturate_cast;
64+
using std::sub_sat;
65+
#endif
66+
5767
} // namespace std

0 commit comments

Comments
 (0)