Skip to content

[libc++][numeric] P0543R3: Saturation arithmetic #77967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 71 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
48c4463
[libc++][numeric] P0543R3: Saturation arithmetic
Zingam Jan 10, 2024
2c939cc
Cleanup
Zingam Jan 12, 2024
f5db95e
Fixed "code formatter" error
Zingam Jan 12, 2024
db3e72e
Cleanup
Zingam Jan 12, 2024
880ca3a
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 13, 2024
30a1593
WIP: prepare to address comments
Zingam Jan 13, 2024
2793acb
WIP: Cleaned up tests
Zingam Jan 13, 2024
540cfec
WIP: Test `constexpr`
Zingam Jan 13, 2024
83fff64
WIP: Optimized `saturate_cast`
Zingam Jan 13, 2024
2cab21a
Renamed test
Zingam Jan 14, 2024
68cbc9f
WIP: `add_sat` - edge case tests
Zingam Jan 14, 2024
e284255
WIP: Added extended integers types to tests
Zingam Jan 14, 2024
fb43978
WIP: Added `check_constexpr.h`
Zingam Jan 14, 2024
39837d6
WIP: Fixed code formatter error
Zingam Jan 14, 2024
e8e21ce
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
H-G-Hristov Jan 14, 2024
3fbec01
WIP: Addtional tests `sat_sub`
Zingam Jan 14, 2024
ea68a59
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 16, 2024
a77d603
WIP: `add_sat` - additional test cases
Zingam Jan 16, 2024
faf1173
Completed SFINAE tests
Zingam Jan 16, 2024
b66f034
WIP: Temporary static tests
Zingam Jan 16, 2024
248531a
WIP: Cleanup
Zingam Jan 16, 2024
14fb0cf
Updated tests: `add_sat`
Zingam Jan 17, 2024
179ebaa
Updated tests: `div_sat`
Zingam Jan 17, 2024
191970d
Cleanup
Zingam Jan 17, 2024
6b661d6
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 17, 2024
b24b4a6
Updated tests: `mul_sat`
Zingam Jan 17, 2024
e108b3f
Fix CI
Zingam Jan 17, 2024
1517f67
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 17, 2024
3b8f712
Fix CI
Zingam Jan 17, 2024
9bf023c
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 19, 2024
2289b24
Move release notes entry to avoid merge conflict.
Zingam Jan 19, 2024
ed4e571
Addressed some comments - `TEST_HAS_NO_INT128`
Zingam Jan 19, 2024
eb6b908
Updated `add_sat.pass`
Zingam Jan 19, 2024
20de72c
Updated tests `div_sat.pass`
Zingam Jan 19, 2024
3dfb7a0
Updated test `mul_sat.pass`
Zingam Jan 19, 2024
a6435a9
Updated test `sub_sat.pass`
Zingam Jan 19, 2024
6312da8
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 20, 2024
80483e7
Updated test `saturate_cast.pass`
Zingam Jan 20, 2024
1c2316b
Updated test `saturate_cast.pass`
Zingam Jan 20, 2024
fdff569
Updated test: `saturate_cast.pass`
Zingam Jan 20, 2024
38f4157
Updated test `saturation_cast.pass`
Zingam Jan 20, 2024
2f76f02
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 20, 2024
453e681
Minor tweak
Zingam Jan 20, 2024
8261422
More tweaks
Zingam Jan 20, 2024
e930967
More tweaks
Zingam Jan 20, 2024
d97311b
More tweaks
Zingam Jan 20, 2024
ddfd2fc
More tweaks
Zingam Jan 20, 2024
deb78c6
Unsupport Clang-17
Zingam Jan 20, 2024
b6c2924
Fixed formatting
Zingam Jan 20, 2024
34bd4ba
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
H-G-Hristov Jan 20, 2024
cdd5992
Added `"test_macros.h` to fix 32-bit CI
Zingam Jan 21, 2024
9487d18
Improved implementation of `mul_sat`
Zingam Jan 21, 2024
8a67964
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 21, 2024
bcf6e7e
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 21, 2024
e2eaf0c
Reformatted `saturate_cast`
Zingam Jan 21, 2024
a79ca6c
Updated test `add_sat`
Zingam Jan 21, 2024
82ef906
Updated test `div_sat`
Zingam Jan 21, 2024
5d1af8c
Updated test `sub_sat`
Zingam Jan 21, 2024
fc15282
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
H-G-Hristov Jan 21, 2024
efb7355
Minor tweaks to comments
Zingam Jan 21, 2024
75c08b7
Re-introduced `[[maybe_unused]]` and re-enabled the tests
Zingam Jan 21, 2024
8ce388c
Updated `saturate_cast.pass`
Zingam Jan 21, 2024
51166ff
Cleanup
Zingam Jan 21, 2024
43a9b27
Final update and cleanup
Zingam Jan 21, 2024
eaa0168
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
Zingam Jan 21, 2024
b06e016
DEBUG
Zingam Jan 21, 2024
71a10a0
Debug 32-bit
Zingam Jan 21, 2024
71c1cb5
Try again
Zingam Jan 21, 2024
0066189
Try to fix CI
Zingam Jan 21, 2024
618d6e4
Merge branch 'main' into hgh/libcxx/P0543R3-Saturation-arithmetic
H-G-Hristov Jan 21, 2024
fc9af61
Update libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_…
H-G-Hristov Jan 21, 2024
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
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_rcu`` *unimplemented*
--------------------------------------------------- -----------------
``__cpp_lib_saturation_arithmetic`` *unimplemented*
``__cpp_lib_saturation_arithmetic`` ``202311L``
--------------------------------------------------- -----------------
``__cpp_lib_smart_ptr_owner_equality`` *unimplemented*
--------------------------------------------------- -----------------
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/18.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Implemented Papers
- P2909R4 - Fix formatting of code units as integers (Dude, where’s my ``char``?)
- P2821R5 - ``span.at()``
- P0521R0 - Proposed Resolution for CA 14 (``shared_ptr`` ``use_count/unique``)
- P0543R3 - Saturation arithmetic
- P1759R6 - Native handles and file streams
- P2868R3 - Remove Deprecated ``std::allocator`` Typedef From C++26
- P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply``
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"`P2714R1 <https://wg21.link/P2714R1>`__","LWG","Bind front and back to NTTP callables","Varna June 2023","","",""
"`P2630R4 <https://wg21.link/P2630R4>`__","LWG","``submdspan``","Varna June 2023","","",""
"","","","","","",""
"`P0543R3 <https://wg21.link/P0543R3>`__","LWG","Saturation arithmetic","Kona November 2023","","",""
"`P0543R3 <https://wg21.link/P0543R3>`__","LWG","Saturation arithmetic","Kona November 2023","|Complete|","18.0",""
"`P2407R5 <https://wg21.link/P2407R5>`__","LWG","Freestanding Library: Partial Classes","Kona November 2023","","",""
"`P2546R5 <https://wg21.link/P2546R5>`__","LWG","Debugging Support","Kona November 2023","","",""
"`P2905R2 <https://wg21.link/P2905R2>`__","LWG","Runtime format strings","Kona November 2023","|Complete|","18.0","|format| |DR|"
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ set(files
__numeric/pstl_reduce.h
__numeric/pstl_transform_reduce.h
__numeric/reduce.h
__numeric/saturation_arithmetic.h
__numeric/transform_exclusive_scan.h
__numeric/transform_inclusive_scan.h
__numeric/transform_reduce.h
Expand Down
110 changes: 110 additions & 0 deletions libcxx/include/__numeric/saturation_arithmetic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
#define _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H

#include <__concepts/arithmetic.h>
#include <__config>
#include <__utility/cmp.h>
#include <limits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER >= 26

template <__libcpp_integer _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept {
if (_Tp __sum; !__builtin_add_overflow(__x, __y, &__sum))
return __sum;
// Handle overflow
if constexpr (__libcpp_unsigned_integer<_Tp>) {
return std::numeric_limits<_Tp>::max();
} else {
// Signed addition overflow
if (__x > 0)
// Overflows if (x > 0 && y > 0)
return std::numeric_limits<_Tp>::max();
else
// Overflows if (x < 0 && y < 0)
return std::numeric_limits<_Tp>::min();
}
}

template <__libcpp_integer _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept {
if (_Tp __sub; !__builtin_sub_overflow(__x, __y, &__sub))
return __sub;
// Handle overflow
if constexpr (__libcpp_unsigned_integer<_Tp>) {
// Overflows if (x < y)
return std::numeric_limits<_Tp>::min();
} else {
// Signed subtration overflow
if (__x >= 0)
// Overflows if (x >= 0 && y < 0)
return std::numeric_limits<_Tp>::max();
else
// Overflows if (x < 0 && y > 0)
return std::numeric_limits<_Tp>::min();
}
}

template <__libcpp_integer _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept {
if (_Tp __mul; !__builtin_mul_overflow(__x, __y, &__mul))
return __mul;
// Handle overflow
if constexpr (__libcpp_unsigned_integer<_Tp>) {
return std::numeric_limits<_Tp>::max();
} else {
// Signed multiplication overflow
if ((__x > 0 && __y > 0) || (__x < 0 && __y < 0))
return std::numeric_limits<_Tp>::max();
// Overflows if (x < 0 && y > 0) || (x > 0 && y < 0)
return std::numeric_limits<_Tp>::min();
}
}

template <__libcpp_integer _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept {
_LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined");
if constexpr (__libcpp_unsigned_integer<_Tp>) {
return __x / __y;
} else {
// Handle signed division overflow
if (__x == std::numeric_limits<_Tp>::min() && __y == _Tp{-1})
return std::numeric_limits<_Tp>::max();
return __x / __y;
}
}

template <__libcpp_integer _Rp, __libcpp_integer _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept {
// Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be
// optimized out by the compiler.

// Handle overflow
if (std::cmp_less(__x, std::numeric_limits<_Rp>::min()))
return std::numeric_limits<_Rp>::min();
if (std::cmp_greater(__x, std::numeric_limits<_Rp>::max()))
return std::numeric_limits<_Rp>::max();
// No overflow
return static_cast<_Rp>(__x);
}

#endif // _LIBCPP_STD_VER >= 26

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H
1 change: 1 addition & 0 deletions libcxx/include/libcxx.imp
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@
{ include: [ "<__numeric/pstl_reduce.h>", "private", "<numeric>", "public" ] },
{ include: [ "<__numeric/pstl_transform_reduce.h>", "private", "<numeric>", "public" ] },
{ include: [ "<__numeric/reduce.h>", "private", "<numeric>", "public" ] },
{ include: [ "<__numeric/saturation_arithmetic.h>", "private", "<numeric>", "public" ] },
{ include: [ "<__numeric/transform_exclusive_scan.h>", "private", "<numeric>", "public" ] },
{ include: [ "<__numeric/transform_inclusive_scan.h>", "private", "<numeric>", "public" ] },
{ include: [ "<__numeric/transform_reduce.h>", "private", "<numeric>", "public" ] },
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,7 @@ module std_private_numeric_pstl_transform_reduce [system] {
export *
}
module std_private_numeric_reduce [system] { header "__numeric/reduce.h" }
module std_private_numeric_saturation_arithmetic [system] { header "__numeric/saturation_arithmetic.h" }
module std_private_numeric_transform_exclusive_scan [system] { header "__numeric/transform_exclusive_scan.h" }
module std_private_numeric_transform_inclusive_scan [system] { header "__numeric/transform_inclusive_scan.h" }
module std_private_numeric_transform_reduce [system] { header "__numeric/transform_reduce.h" }
Expand Down
13 changes: 13 additions & 0 deletions libcxx/include/numeric
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,18 @@ template<class T>
template<class T>
constexpr T* midpoint(T* a, T* b); // C++20

// [numeric.sat], saturation arithmetic
template<class T>
constexpr T add_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T>
constexpr T sub_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T>
constexpr T mul_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T>
constexpr T div_sat(T x, T y) noexcept; // freestanding, Since C++26
template<class T, class U>
constexpr T saturate_cast(U x) noexcept; // freestanding, Since C++26

} // std

*/
Expand All @@ -160,6 +172,7 @@ template<class T>
#include <__numeric/pstl_reduce.h>
#include <__numeric/pstl_transform_reduce.h>
#include <__numeric/reduce.h>
#include <__numeric/saturation_arithmetic.h>
#include <__numeric/transform_exclusive_scan.h>
#include <__numeric/transform_inclusive_scan.h>
#include <__numeric/transform_reduce.h>
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
// # define __cpp_lib_out_ptr 202311L
# define __cpp_lib_ratio 202306L
// # define __cpp_lib_rcu 202306L
// # define __cpp_lib_saturation_arithmetic 202311L
# define __cpp_lib_saturation_arithmetic 202311L
// # define __cpp_lib_smart_ptr_owner_equality 202306L
# define __cpp_lib_span_at 202311L
# define __cpp_lib_span_initializer_list 202311L
Expand Down
10 changes: 10 additions & 0 deletions libcxx/modules/std/numeric.inc
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,14 @@ export namespace std {

// [numeric.ops.midpoint], midpoint
using std::midpoint;

#if _LIBCPP_STD_VER >= 26
// [numeric.sat], saturation arithmetic
using std::add_sat;
using std::div_sat;
using std::mul_sat;
using std::saturate_cast;
using std::sub_sat;
#endif

} // namespace std
Original file line number Diff line number Diff line change
Expand Up @@ -263,17 +263,11 @@
# endif
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_saturation_arithmetic
# error "__cpp_lib_saturation_arithmetic should be defined in c++26"
# endif
# if __cpp_lib_saturation_arithmetic != 202311L
# error "__cpp_lib_saturation_arithmetic should have the value 202311L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_saturation_arithmetic
# error "__cpp_lib_saturation_arithmetic should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_saturation_arithmetic
# error "__cpp_lib_saturation_arithmetic should be defined in c++26"
# endif
# if __cpp_lib_saturation_arithmetic != 202311L
# error "__cpp_lib_saturation_arithmetic should have the value 202311L in c++26"
# endif

#endif // TEST_STD_VER > 23
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7167,17 +7167,11 @@
# error "__cpp_lib_sample should have the value 201603L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_saturation_arithmetic
# error "__cpp_lib_saturation_arithmetic should be defined in c++26"
# endif
# if __cpp_lib_saturation_arithmetic != 202311L
# error "__cpp_lib_saturation_arithmetic should have the value 202311L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_saturation_arithmetic
# error "__cpp_lib_saturation_arithmetic should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_saturation_arithmetic
# error "__cpp_lib_saturation_arithmetic should be defined in c++26"
# endif
# if __cpp_lib_saturation_arithmetic != 202311L
# error "__cpp_lib_saturation_arithmetic should have the value 202311L in c++26"
# endif

# ifndef __cpp_lib_scoped_lock
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23

// <numeric>

// template<class T>
// constexpr T add_sat(T x, T y) noexcept; // freestanding

#include <concepts>
#include <numeric>

#include "test_macros.h"

template <typename T, typename U>
concept CanDo = requires(T x, U y) {
{ std::add_sat(x, y) } -> std::same_as<T>;
};

template <typename T, typename U>
constexpr void test_constraint_success() {
static_assert(CanDo<T, T>);
static_assert(!CanDo<U, T>);
static_assert(!CanDo<T, U>);
}

template <typename T>
constexpr void test_constraint_fail() {
using I = int;
static_assert(!CanDo<T, T>);
static_assert(!CanDo<I, T>);
static_assert(!CanDo<T, I>);
}

constexpr void test() {
// Contraint success - Signed
using SI = long long int;
test_constraint_success<signed char, SI>();
test_constraint_success<short int, SI>();
test_constraint_success<signed char, SI>();
test_constraint_success<short int, SI>();
test_constraint_success<int, SI>();
test_constraint_success<long int, SI>();
test_constraint_success<long long int, int>();
#ifndef TEST_HAS_NO_INT128
test_constraint_success<__int128_t, SI>();
#endif
// Contraint success - Unsigned
using UI = unsigned long long int;
test_constraint_success<unsigned char, UI>();
test_constraint_success<unsigned short int, UI>();
test_constraint_success<unsigned int, UI>();
test_constraint_success<unsigned long int, UI>();
test_constraint_success<unsigned long long int, unsigned int>();
#ifndef TEST_HAS_NO_INT128
test_constraint_success<__uint128_t, UI>();
#endif

// Contraint failure
test_constraint_fail<bool>();
test_constraint_fail<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test_constraint_fail<wchar_t>();
#endif
test_constraint_fail<char8_t>();
test_constraint_fail<char16_t>();
test_constraint_fail<char32_t>();
test_constraint_fail<float>();
test_constraint_fail<double>();
test_constraint_fail<long double>();
}
Loading