diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 1447261645a7b..94342eb4a4f0a 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -508,7 +508,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_reference_wrapper`` ``202403L`` ---------------------------------------------------------- ----------------- - ``__cpp_lib_saturation_arithmetic`` ``202311L`` + ``__cpp_lib_saturation_arithmetic`` ``202603L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_senders`` *unimplemented* ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst index c28af1522240c..c21b378f7db4b 100644 --- a/libcxx/docs/ReleaseNotes/23.rst +++ b/libcxx/docs/ReleaseNotes/23.rst @@ -41,6 +41,7 @@ Implemented Papers - P2440R1: ``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right`` (`Github `__) - P3936R1: Safer ``atomic_ref::address`` (`Github `__) - P3953R3: Rename ``std::runtime_format`` (`Github `__) +- P4052R0: Renaming saturation arithmetic functions (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 4258193c78902..7adf5a2122e62 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -208,7 +208,7 @@ "`P3980R1 `__","Task's Allocator Use","2026-03 (Croydon)","","","`#189621 `__","" "`P4156R0 `__","Rename meta::has_ellipsis_parameter to meta::is_vararg_function","2026-03 (Croydon)","","","`#189622 `__","" "`P3953R3 `__","Rename ``std::runtime_format``","2026-03 (Croydon)","|Complete|","23","`#189624 `__","" -"`P4052R0 `__","Renaming saturation arithmetic functions","2026-03 (Croydon)","","","`#189589 `__","" +"`P4052R0 `__","Renaming saturation arithmetic functions","2026-03 (Croydon)","|Complete|","23","`#189589 `__","" "`P3941R4 `__","Scheduler Affinity","2026-03 (Croydon)","","","`#189627 `__","" "`P3856R8 `__","New reflection metafunction - is_structural_type (US NB comment 49)","2026-03 (Croydon)","","","`#189625 `__","" "`P3927R2 `__","``task_scheduler`` support for parallel ``bulk`` execution","2026-03 (Croydon)","","","`#189629 `__","" diff --git a/libcxx/include/__numeric/saturation_arithmetic.h b/libcxx/include/__numeric/saturation_arithmetic.h index 4491bab2b1479..34f784e4a9cf1 100644 --- a/libcxx/include/__numeric/saturation_arithmetic.h +++ b/libcxx/include/__numeric/saturation_arithmetic.h @@ -29,7 +29,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { +_LIBCPP_HIDE_FROM_ABI constexpr _Tp __saturating_add(_Tp __x, _Tp __y) noexcept { # if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101 return __builtin_elementwise_add_sat(__x, __y); # else @@ -51,7 +51,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { } template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { +_LIBCPP_HIDE_FROM_ABI constexpr _Tp __saturating_sub(_Tp __x, _Tp __y) noexcept { # if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101 return __builtin_elementwise_sub_sat(__x, __y); # else @@ -74,7 +74,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { } template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept { +_LIBCPP_HIDE_FROM_ABI constexpr _Tp __saturating_mul(_Tp __x, _Tp __y) noexcept { if (_Tp __mul; !__builtin_mul_overflow(__x, __y, std::addressof(__mul))) return __mul; // Handle overflow @@ -90,7 +90,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept { } template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept { +_LIBCPP_HIDE_FROM_ABI constexpr _Tp __saturating_div(_Tp __x, _Tp __y) noexcept { _LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined"); if constexpr (__unsigned_integer<_Tp>) { return __x / __y; @@ -103,7 +103,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept { } template <__signed_or_unsigned_integer _Rp, __signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept { +_LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturating_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. @@ -121,28 +121,28 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept { #if _LIBCPP_STD_VER >= 26 template <__signed_or_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { - return std::__add_sat(__x, __y); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp saturating_add(_Tp __x, _Tp __y) noexcept { + return std::__saturating_add(__x, __y); } template <__signed_or_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { - return std::__sub_sat(__x, __y); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp saturating_sub(_Tp __x, _Tp __y) noexcept { + return std::__saturating_sub(__x, __y); } template <__signed_or_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { - return std::__mul_sat(__x, __y); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp saturating_mul(_Tp __x, _Tp __y) noexcept { + return std::__saturating_mul(__x, __y); } template <__signed_or_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { - return std::__div_sat(__x, __y); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp saturating_div(_Tp __x, _Tp __y) noexcept { + return std::__saturating_div(__x, __y); } template <__signed_or_unsigned_integer _Rp, __signed_or_unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept { - return std::__saturate_cast<_Rp>(__x); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturating_cast(_Tp __x) noexcept { + return std::__saturating_cast<_Rp>(__x); } #endif // _LIBCPP_STD_VER >= 26 diff --git a/libcxx/include/numeric b/libcxx/include/numeric index 48c330fcb009c..64111b88d3538 100644 --- a/libcxx/include/numeric +++ b/libcxx/include/numeric @@ -142,15 +142,15 @@ template // [numeric.sat], saturation arithmetic template -constexpr T add_sat(T x, T y) noexcept; // freestanding, Since C++26 +constexpr T saturating_add(T x, T y) noexcept; // freestanding, Since C++26 template -constexpr T sub_sat(T x, T y) noexcept; // freestanding, Since C++26 +constexpr T saturating_sub(T x, T y) noexcept; // freestanding, Since C++26 template -constexpr T mul_sat(T x, T y) noexcept; // freestanding, Since C++26 +constexpr T saturating_mul(T x, T y) noexcept; // freestanding, Since C++26 template -constexpr T div_sat(T x, T y) noexcept; // freestanding, Since C++26 +constexpr T saturating_div(T x, T y) noexcept; // freestanding, Since C++26 template -constexpr T saturate_cast(U x) noexcept; // freestanding, Since C++26 +constexpr T saturating_cast(U x) noexcept; // freestanding, Since C++26 } // std diff --git a/libcxx/include/version b/libcxx/include/version index 105a04545da0e..395330df7f237 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -227,7 +227,7 @@ __cpp_lib_remove_cvref 201711L __cpp_lib_result_of_sfinae 201210L __cpp_lib_robust_nonmodifying_seq_ops 201304L __cpp_lib_sample 201603L -__cpp_lib_saturation_arithmetic 202311L +__cpp_lib_saturation_arithmetic 202603L __cpp_lib_scoped_lock 201703L __cpp_lib_semaphore 201907L __cpp_lib_senders 202406L @@ -612,7 +612,7 @@ __cpp_lib_void_t 201411L # define __cpp_lib_ratio 202306L // # define __cpp_lib_rcu 202306L # define __cpp_lib_reference_wrapper 202403L -# define __cpp_lib_saturation_arithmetic 202311L +# define __cpp_lib_saturation_arithmetic 202603L // # define __cpp_lib_senders 202406L // # define __cpp_lib_smart_ptr_owner_equality 202306L # define __cpp_lib_span_at 202311L diff --git a/libcxx/modules/std/numeric.inc b/libcxx/modules/std/numeric.inc index 5a549552081d2..e0edff9dfb0a5 100644 --- a/libcxx/modules/std/numeric.inc +++ b/libcxx/modules/std/numeric.inc @@ -61,11 +61,11 @@ export namespace std { #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; + using std::saturating_add; + using std::saturating_cast; + using std::saturating_div; + using std::saturating_mul; + using std::saturating_sub; #endif } // namespace std diff --git a/libcxx/test/libcxx/numerics/nodiscard.verify.cpp b/libcxx/test/libcxx/numerics/nodiscard.verify.cpp index fe59e6a6a3fa7..089ebb73b1502 100644 --- a/libcxx/test/libcxx/numerics/nodiscard.verify.cpp +++ b/libcxx/test/libcxx/numerics/nodiscard.verify.cpp @@ -25,11 +25,11 @@ void test() { // clang-format off #if TEST_STD_VER >= 26 // [numeric.sat] - std::add_sat(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::sub_sat(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::mul_sat(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::div_sat(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - std::saturate_cast(49); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::saturating_add(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::saturating_sub(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::saturating_mul(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::saturating_div(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::saturating_cast(49); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} #endif // TEST_STD_VER >= 26 // clang-format on diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp index cafbd2cac2ccf..d629407c9b645 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/numeric.version.compile.pass.cpp @@ -245,8 +245,8 @@ # 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" +# if __cpp_lib_saturation_arithmetic != 202603L +# error "__cpp_lib_saturation_arithmetic should have the value 202603L in c++26" # endif #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 71b9d573a1778..d1c571a9d1a8c 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -7782,8 +7782,8 @@ # 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" +# if __cpp_lib_saturation_arithmetic != 202603L +# error "__cpp_lib_saturation_arithmetic should have the value 202603L in c++26" # endif # if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp deleted file mode 100644 index f49e19acf0234..0000000000000 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.pass.cpp +++ /dev/null @@ -1,171 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// REQUIRES: std-at-least-c++26 - -// - -// template -// constexpr T add_sat(T x, T y) noexcept; // freestanding - -#include -#include -#include -#include - -#include "test_macros.h" - -template -constexpr bool test_signed() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::add_sat(minVal, maxVal); - - static_assert(noexcept(std::add_sat(minVal, maxVal))); - - // clang-format off - - // Limit values (-1, 0, 1, min, max) - - assert(std::add_sat(IntegerT{-1}, IntegerT{-1}) == IntegerT{-2}); - assert(std::add_sat(IntegerT{-1}, IntegerT{ 0}) == IntegerT{-1}); - assert(std::add_sat(IntegerT{-1}, IntegerT{ 1}) == IntegerT{ 0}); - assert(std::add_sat(IntegerT{-1}, minVal) == minVal); // saturated - assert(std::add_sat(IntegerT{-1}, maxVal) == IntegerT{-1} + maxVal); - - assert(std::add_sat(IntegerT{ 0}, IntegerT{-1}) == IntegerT{-1}); - assert(std::add_sat(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0}); - assert(std::add_sat(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 1}); - assert(std::add_sat(IntegerT{ 0}, minVal) == minVal); - assert(std::add_sat(IntegerT{ 0}, maxVal) == maxVal); - - assert(std::add_sat(IntegerT{ 1}, IntegerT{-1}) == IntegerT{ 0}); - assert(std::add_sat(IntegerT{ 1}, IntegerT{ 0}) == IntegerT{ 1}); - assert(std::add_sat(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 2}); - assert(std::add_sat(IntegerT{ 1}, minVal) == IntegerT{ 1} + minVal); - assert(std::add_sat(IntegerT{ 1}, maxVal) == maxVal); // saturated - - assert(std::add_sat( minVal, IntegerT{-1}) == minVal); // saturated - assert(std::add_sat( minVal, IntegerT{ 0}) == minVal); - assert(std::add_sat( minVal, IntegerT{ 1}) == minVal + IntegerT{ 1}); - assert(std::add_sat( minVal, minVal) == minVal); // saturated - assert(std::add_sat( minVal, maxVal) == IntegerT{-1}); - - assert(std::add_sat( maxVal, IntegerT{-1}) == maxVal + IntegerT{-1}); - assert(std::add_sat( maxVal, IntegerT{ 0}) == maxVal); - assert(std::add_sat( maxVal, IntegerT{ 1}) == maxVal); // saturated - assert(std::add_sat( maxVal, minVal) == IntegerT{-1}); - assert(std::add_sat( maxVal, maxVal) == maxVal); // saturated - - // No saturation (no limit values) - - assert(std::add_sat(IntegerT{-27}, IntegerT{28})== IntegerT{ 1}); - assert(std::add_sat(IntegerT{ 27}, IntegerT{28})== IntegerT{55}); - { - constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::add_sat(x, y) == maxVal); - } - - // Saturation (no limit values) - - { - constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{-27}; - constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{-28}; - assert(std::add_sat(x, y) == minVal); // saturated - } - { - constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::add_sat(x, y) == maxVal); // saturated - } - - // clang-format on - - return true; -} - -template -constexpr bool test_unsigned() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::add_sat(minVal, maxVal); - - static_assert(noexcept(std::add_sat(minVal, maxVal))); - - // clang-format off - - // Litmit values (0, 1, min, max) - - assert(std::add_sat(IntegerT{0}, IntegerT{0}) == IntegerT{0}); - assert(std::add_sat(IntegerT{0}, IntegerT{1}) == IntegerT{1}); - assert(std::add_sat(IntegerT{0}, minVal) == IntegerT{0}); - assert(std::add_sat(IntegerT{0}, maxVal) == maxVal); - assert(std::add_sat(IntegerT{1}, IntegerT{0}) == IntegerT{1}); - assert(std::add_sat(IntegerT{1}, IntegerT{1}) == IntegerT{2}); - assert(std::add_sat(IntegerT{1}, minVal) == IntegerT{1}); - assert(std::add_sat(IntegerT{1}, maxVal) == maxVal); // saturated - assert(std::add_sat( minVal, IntegerT{0}) == IntegerT{0}); - assert(std::add_sat( minVal, IntegerT{1}) == IntegerT{1}); - assert(std::add_sat( minVal, minVal) == minVal); - assert(std::add_sat( minVal, maxVal) == maxVal); - assert(std::add_sat( maxVal, IntegerT{0}) == maxVal); - assert(std::add_sat( maxVal, IntegerT{1}) == maxVal); // saturated - assert(std::add_sat( maxVal, minVal) == maxVal); - assert(std::add_sat( maxVal, maxVal) == maxVal); // saturated - - // No saturation (no limit values) - - assert(std::add_sat(IntegerT{27}, IntegerT{28}) == IntegerT{55}); - - // Saturation (no limit values) - - { - constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::add_sat( x, y) == maxVal); // saturated - assert(std::add_sat( x, maxVal) == maxVal); // saturated - assert(std::add_sat(maxVal, y) == maxVal); // saturated - } - - // clang-format on - - return true; -} - -constexpr bool test() { - // Signed - test_signed(); - test_signed(); - test_signed(); - test_signed(); - test_signed(); -#ifndef TEST_HAS_NO_INT128 - test_signed<__int128_t>(); -#endif - // Unsigned - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); -#ifndef TEST_HAS_NO_INT128 - test_unsigned<__uint128_t>(); -#endif - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp deleted file mode 100644 index 0789213163847..0000000000000 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.pass.cpp +++ /dev/null @@ -1,155 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// REQUIRES: std-at-least-c++26 - -// - -// template -// constexpr T div_sat(T x, T y) noexcept; // freestanding - -#include -#include -#include -#include - -#include "test_macros.h" - -template -constexpr bool test_signed() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::div_sat(minVal, maxVal); - - static_assert(noexcept(std::div_sat(minVal, maxVal))); - - // clang-format off - - // Limit values (-1, 0, 1, min, max) - - assert(std::div_sat(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 1}); - assert(std::div_sat(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-1}); - assert(std::div_sat(IntegerT{-1}, minVal) == IntegerT{ 0}); - assert(std::div_sat(IntegerT{-1}, maxVal) == IntegerT{ 0}); - assert(std::div_sat(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 0}); - assert(std::div_sat(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 0}); - assert(std::div_sat(IntegerT{ 0}, minVal) == IntegerT{ 0}); - assert(std::div_sat(IntegerT{ 0}, maxVal) == IntegerT{ 0}); - assert(std::div_sat(IntegerT{ 1}, IntegerT{-1}) == IntegerT{-1}); - assert(std::div_sat(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 1}); - assert(std::div_sat(IntegerT{ 1}, minVal) == IntegerT{ 0}); - assert(std::div_sat(IntegerT{ 1}, maxVal) == IntegerT{ 0}); - assert(std::div_sat( minVal, IntegerT{ 1}) == minVal); - assert(std::div_sat( minVal, IntegerT{-1}) == maxVal); // saturated - assert(std::div_sat( minVal, minVal) == IntegerT{ 1}); - assert(std::div_sat( minVal, maxVal) == (minVal / maxVal)); - assert(std::div_sat( maxVal, IntegerT{-1}) == -maxVal); - assert(std::div_sat( maxVal, IntegerT{ 1}) == maxVal); - assert(std::div_sat( maxVal, minVal) == IntegerT{ 0}); - assert(std::div_sat( maxVal, maxVal) == IntegerT{ 1}); - - // No saturation (no limit values) - - assert(std::div_sat(IntegerT{27}, IntegerT{28}) == IntegerT{0}); - assert(std::div_sat(IntegerT{28}, IntegerT{27}) == IntegerT{1}); - { - constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{-28}; - constexpr IntegerT biggerVal = minVal / IntegerT{2} + IntegerT{-27}; - assert(std::div_sat(lesserVal, biggerVal) == IntegerT{1}); - assert(std::div_sat(biggerVal, lesserVal) == IntegerT{0}); - } - { - constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{-27}; - constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::div_sat(lesserVal, biggerVal) == IntegerT{-1}); - assert(std::div_sat(biggerVal, lesserVal) == IntegerT{-1}); - } - { - constexpr IntegerT lesserVal = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::div_sat(lesserVal, biggerVal) == IntegerT{0}); - assert(std::div_sat(biggerVal, lesserVal) == IntegerT{1}); - } - - // clang-format on - - return true; -} - -template -constexpr bool test_unsigned() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::div_sat(minVal, maxVal); - static_assert(noexcept(std::div_sat(minVal, maxVal))); - - // clang-format off - - // No limit values (0, 1, min, max) - - assert(std::div_sat(IntegerT{0}, IntegerT{1}) == IntegerT{0}); - assert(std::div_sat(IntegerT{0}, maxVal) == IntegerT{0}); - - assert(std::div_sat(IntegerT{1}, IntegerT{1}) == IntegerT{1}); - assert(std::div_sat(IntegerT{1}, maxVal) == IntegerT{0}); - - assert(std::div_sat( minVal, IntegerT{1}) == minVal); - assert(std::div_sat( minVal, maxVal) == IntegerT{0}); - - assert(std::div_sat( maxVal, IntegerT{1}) == maxVal); - assert(std::div_sat( maxVal, maxVal) == IntegerT{1}); - - // No saturation (no limit values) - - assert(std::div_sat(IntegerT{27}, IntegerT{28}) == IntegerT{0}); - assert(std::div_sat(IntegerT{28}, IntegerT{27}) == IntegerT{1}); - { - constexpr IntegerT lesserVal = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::div_sat(lesserVal, biggerVal) == IntegerT{0}); - assert(std::div_sat(biggerVal, lesserVal) == IntegerT{1}); - } - - // Unsigned integer division never overflows - - // clang-format on - - return true; -} - -constexpr bool test() { - // Signed - test_signed(); - test_signed(); - test_signed(); - test_signed(); - test_signed(); -#ifndef TEST_HAS_NO_INT128 - test_signed<__int128_t>(); -#endif - // Unsigned - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); -#ifndef TEST_HAS_NO_INT128 - test_unsigned<__uint128_t>(); -#endif - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp deleted file mode 100644 index f09bf30771102..0000000000000 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.pass.cpp +++ /dev/null @@ -1,177 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// REQUIRES: std-at-least-c++26 - -// - -// template -// constexpr T mul_sat(T x, T y) noexcept; // freestanding - -#include -#include -#include -#include - -#include "test_macros.h" - -template -constexpr bool test_signed() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::mul_sat(minVal, maxVal); - - static_assert(noexcept(std::mul_sat(minVal, maxVal))); - - // clang-format off - - // Limit values (-1, 0, 1, min, max) - - assert(std::mul_sat(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 1}); - assert(std::mul_sat(IntegerT{-1}, IntegerT{ 0}) == IntegerT{ 0}); - assert(std::mul_sat(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-1}); - assert(std::mul_sat(IntegerT{-1}, minVal) == maxVal); // saturated - assert(std::mul_sat(IntegerT{-1}, maxVal) == -maxVal); - - assert(std::mul_sat(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 0}); - assert(std::mul_sat(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0}); - assert(std::mul_sat(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 0}); - assert(std::mul_sat(IntegerT{ 0}, minVal) == IntegerT{ 0}); - assert(std::mul_sat(IntegerT{ 0}, maxVal) == IntegerT{ 0}); - - assert(std::mul_sat(IntegerT{ 1}, IntegerT{-1}) == IntegerT{-1}); - assert(std::mul_sat(IntegerT{ 1}, IntegerT{ 0}) == IntegerT{ 0}); - assert(std::mul_sat(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 1}); - assert(std::mul_sat(IntegerT{ 1}, minVal) == minVal); - assert(std::mul_sat(IntegerT{ 1}, maxVal) == maxVal); - - assert(std::mul_sat( minVal, IntegerT{-1}) == maxVal); // saturated - assert(std::mul_sat( minVal, IntegerT{ 0}) == IntegerT{ 0}); - assert(std::mul_sat( minVal, IntegerT{ 1}) == minVal); - assert(std::mul_sat( minVal, minVal) == maxVal); // saturated - assert(std::mul_sat( minVal, maxVal) == minVal); // saturated - - assert(std::mul_sat( maxVal, IntegerT{-1}) == -maxVal); - assert(std::mul_sat( maxVal, IntegerT{ 0}) == IntegerT{ 0}); - assert(std::mul_sat( maxVal, IntegerT{ 1}) == maxVal); // saturated - assert(std::mul_sat( maxVal, minVal) == minVal); // saturated - assert(std::mul_sat( maxVal, maxVal) == maxVal); // saturated - - // No saturation (no limit values) - - assert(std::mul_sat(IntegerT{27}, IntegerT{ 2}) == IntegerT{54}); - assert(std::mul_sat(IntegerT{ 2}, IntegerT{28}) == IntegerT{56}); - - // Saturation (no limit values) - - { - constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28}; - assert(std::mul_sat(x, y) == maxVal); // saturated - } - { - constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::mul_sat(x, y) == minVal); // saturated - } - { - constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28}; - assert(std::mul_sat(x, y) == minVal); // saturated - } - { - constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::mul_sat(x, y) == maxVal); // saturated - } - - // clang-format on - - return true; -} - -template -constexpr bool test_unsigned() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::mul_sat(minVal, maxVal); - - static_assert(noexcept(std::mul_sat(minVal, maxVal))); - - // clang-format off - - // No saturation (0, 1) - - assert(std::mul_sat(IntegerT{0}, IntegerT{0}) == IntegerT{0}); - assert(std::mul_sat(IntegerT{0}, IntegerT{1}) == IntegerT{0}); - assert(std::mul_sat(IntegerT{0}, minVal) == IntegerT{0}); - assert(std::mul_sat(IntegerT{0}, maxVal) == IntegerT{0}); - - assert(std::mul_sat(IntegerT{1}, IntegerT{0}) == IntegerT{0}); - assert(std::mul_sat(IntegerT{1}, IntegerT{1}) == IntegerT{1}); - assert(std::mul_sat(IntegerT{1}, minVal) == minVal); - assert(std::mul_sat(IntegerT{1}, maxVal) == maxVal); - - assert(std::mul_sat( minVal, IntegerT{0}) == IntegerT{0}); - assert(std::mul_sat( minVal, IntegerT{1}) == minVal); - assert(std::mul_sat( minVal, maxVal) == minVal); - assert(std::mul_sat( minVal, maxVal) == minVal); - - assert(std::mul_sat( maxVal, IntegerT{0}) == IntegerT{0}); - assert(std::mul_sat( maxVal, IntegerT{1}) == maxVal); - assert(std::mul_sat( maxVal, minVal) == IntegerT{0}); - assert(std::mul_sat( maxVal, maxVal) == maxVal); // saturated - - // No saturation (no limit values) - - assert(std::mul_sat(IntegerT{28}, IntegerT{2}) == IntegerT{56}); - - // Saturation (no limit values - - { - constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::mul_sat(x, y) == maxVal); // saturated - } - - // clang-format on - - return true; -} - -constexpr bool test() { - // Signed - test_signed(); - test_signed(); - test_signed(); - test_signed(); - test_signed(); -#ifndef TEST_HAS_NO_INT128 - test_signed<__int128_t>(); -#endif - // Unsigned - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); -#ifndef TEST_HAS_NO_INT128 - test_unsigned<__uint128_t>(); -#endif - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp deleted file mode 100644 index 86e2e61647be8..0000000000000 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.pass.cpp +++ /dev/null @@ -1,394 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// REQUIRES: std-at-least-c++26 - -// - -// template -// constexpr R saturate_cast(T x) noexcept; // freestanding - -#include -#include -#include -#include -#include - -#include "test_macros.h" - -// Smaller to larger -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); - -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); - -// Same type -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); - -// Larger to smaller -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); - -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); -static_assert(noexcept(std::saturate_cast(std::numeric_limits::max()))); - -// Tests - -constexpr bool test() { - // clang-format off - -#ifndef TEST_HAS_NO_INT128 - using SIntT = __int128_t; - using UIntT = __uint128_t; -#else - using SIntT = long long int; - using UIntT = unsigned long long int; -#endif - - // Constants the values of which depend on the context (platform) - - constexpr auto sBigMin = std::numeric_limits::min(); - constexpr auto sZero = SIntT{0}; - constexpr auto sBigMax = std::numeric_limits::max(); - - constexpr auto uZero = UIntT{0}; - constexpr auto uBigMax = std::numeric_limits::max(); - - // Constants to avoid casting in place - - constexpr auto O_C = static_cast(0); - constexpr auto O_UC = static_cast(0); - - constexpr auto O_S = static_cast(0); - constexpr auto O_US = static_cast(0); - - // signed char - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == SCHAR_MIN); - assert(std::saturate_cast( O_C) == O_C); - assert(std::saturate_cast(SCHAR_MAX) == SCHAR_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == O_C); - assert(std::saturate_cast(UCHAR_MAX) == SCHAR_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast(sBigMin) == SCHAR_MIN); // saturated - assert(std::saturate_cast( sZero) == O_C); - assert(std::saturate_cast(sBigMax) == SCHAR_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == O_C); - assert(std::saturate_cast(uBigMax) == SCHAR_MAX); // saturated - - // short - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); - assert(std::saturate_cast( O_C) == O_S); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == O_S); - assert(std::saturate_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(SHRT_MAX); - assert(std::saturate_cast( SHRT_MIN) == SHRT_MIN); - assert(std::saturate_cast( O_S) == O_S); - assert(std::saturate_cast( SHRT_MAX) == SHRT_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(USHRT_MAX); - assert(std::saturate_cast( O_US) == O_S); - assert(std::saturate_cast(USHRT_MAX) == SHRT_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == SHRT_MIN); // saturated - assert(std::saturate_cast( sZero) == O_S); - assert(std::saturate_cast( sBigMax) == SHRT_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == O_S); - assert(std::saturate_cast( uBigMax) == SHRT_MAX); // saturated - - // int - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); - assert(std::saturate_cast( O_C) == 0); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == 0); - assert(std::saturate_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(INT_MAX); - assert(std::saturate_cast( INT_MIN) == INT_MIN); - assert(std::saturate_cast( 0) == 0); - assert(std::saturate_cast( INT_MAX) == INT_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(UINT_MAX); - assert(std::saturate_cast( 0) == 0); - assert(std::saturate_cast(UINT_MAX) == INT_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == INT_MIN); // saturated - assert(std::saturate_cast( sZero) == 0); - assert(std::saturate_cast( sBigMax) == INT_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == 0); - assert(std::saturate_cast( uBigMax) == INT_MAX); // saturated - - // long - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); - assert(std::saturate_cast( O_C) == 0L); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == 0L); - assert(std::saturate_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(LONG_MAX); - assert(std::saturate_cast( LONG_MIN) == LONG_MIN); - assert(std::saturate_cast( 0L) == 0L); - assert(std::saturate_cast( LONG_MAX) == LONG_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(ULONG_MAX); - assert(std::saturate_cast( 0UL) == 0L); - assert(std::saturate_cast(ULONG_MAX) == LONG_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == LONG_MIN); // saturated - assert(std::saturate_cast( sZero) == 0L); - assert(std::saturate_cast( sBigMax) == LONG_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == 0L); - assert(std::saturate_cast( uBigMax) == LONG_MAX); // saturated - - // long long - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); - assert(std::saturate_cast( 0LL) == 0LL); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == 0LL); - assert(std::saturate_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(LLONG_MIN); - assert(std::saturate_cast(LLONG_MIN) == LLONG_MIN); - assert(std::saturate_cast( 0LL) == 0LL); - assert(std::saturate_cast(LLONG_MAX) == LLONG_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(ULLONG_MAX); - assert(std::saturate_cast( 0ULL) == 0LL); - assert(std::saturate_cast(ULLONG_MAX) == LLONG_MAX); // saturated - -#ifndef TEST_HAS_NO_INT128 - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == LLONG_MIN); // (128-bit) saturated - assert(std::saturate_cast( sZero) == 0LL); - assert(std::saturate_cast( sBigMax) == LLONG_MAX); // (128-bit) saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == 0LL); - assert(std::saturate_cast( uBigMax) == LLONG_MAX); // (128-bit) saturated - - std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(SCHAR_MAX); - assert(std::saturate_cast<__int128_t>(SCHAR_MIN) == static_cast<__int128_t>(SCHAR_MIN)); - assert(std::saturate_cast<__int128_t>( O_C) == sZero); - assert(std::saturate_cast<__int128_t>(SCHAR_MAX) == static_cast<__int128_t>(SCHAR_MAX)); - - std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(UCHAR_MAX); - assert(std::saturate_cast<__int128_t>( O_UC) == sZero); - assert(std::saturate_cast<__int128_t>(UCHAR_MAX) == static_cast<__int128_t>(UCHAR_MAX)); - - std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(sBigMax); - assert(std::saturate_cast<__int128_t>( sBigMin) == sBigMin); - assert(std::saturate_cast<__int128_t>( sZero) == sZero); - assert(std::saturate_cast<__int128_t>( sBigMax) == sBigMax); - - std::same_as<__int128_t> decltype(auto) _ = std::saturate_cast<__int128_t>(uBigMax); - assert(std::saturate_cast<__int128_t>( uZero) == sZero); - assert(std::saturate_cast<__int128_t>( uBigMax) == sBigMax); // saturated -#endif - - // unsigned char - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == O_UC); - assert(std::saturate_cast( O_C) == O_UC); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == O_UC); - assert(std::saturate_cast(UCHAR_MAX) == UCHAR_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == O_UC); // saturated - assert(std::saturate_cast( sZero) == O_UC); - assert(std::saturate_cast( sBigMax) == UCHAR_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == O_UC); - assert(std::saturate_cast( uBigMax) == UCHAR_MAX); // saturated - - // unsigned short - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == O_US); - assert(std::saturate_cast( O_C) == O_US); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == O_US); - assert(std::saturate_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MIN); - assert(std::saturate_cast( SHRT_MIN) == O_US); - assert(std::saturate_cast( O_S) == O_US); - assert(std::saturate_cast( SHRT_MAX) == static_cast(SHRT_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_US) == O_US); - assert(std::saturate_cast(USHRT_MAX) == USHRT_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == O_US); // saturated - assert(std::saturate_cast( sZero) == O_US); - assert(std::saturate_cast( sBigMax) == USHRT_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == O_US); - assert(std::saturate_cast( uBigMax) == USHRT_MAX); // saturated - - // unsigned int - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == O_US); - assert(std::saturate_cast( O_UC) == 0U); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == 0U); - assert(std::saturate_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(INT_MAX); - assert(std::saturate_cast( INT_MIN) == 0U); - assert(std::saturate_cast( 0) == 0U); - assert(std::saturate_cast( INT_MAX) == static_cast(INT_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UINT_MAX); - assert(std::saturate_cast( 0U) == 0U); - assert(std::saturate_cast( UINT_MAX) == UINT_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == 0U); // saturated - assert(std::saturate_cast( sZero) == 0U); - assert(std::saturate_cast( sBigMax) == UINT_MAX); // saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == 0U); - assert(std::saturate_cast( uBigMax) == UINT_MAX); // saturated - - // unsigned long - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast(SCHAR_MIN) == 0UL); - assert(std::saturate_cast( O_C) == 0UL); - assert(std::saturate_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == 0UL); - assert(std::saturate_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(LONG_MAX); - assert(std::saturate_cast( LONG_MIN) == 0UL); - assert(std::saturate_cast( 0L) == 0UL); - assert(std::saturate_cast( LONG_MAX) == static_cast(LONG_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(ULONG_MAX); - assert(std::saturate_cast( 0UL) == 0UL); - assert(std::saturate_cast(ULONG_MAX) == ULONG_MAX); - - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == 0UL); // saturated - assert(std::saturate_cast( sZero) == 0UL); - assert(std::saturate_cast( sBigMax) == (sizeof(UIntT) > sizeof(unsigned long int) ? ULONG_MAX : LONG_MAX)); // saturated depending on underlying types - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == 0UL); - assert(std::saturate_cast( uBigMax) == ULONG_MAX); // saturated - - // unsigned long long - - std::same_as decltype(auto) _ = std::saturate_cast(SCHAR_MAX); - assert(std::saturate_cast( SCHAR_MIN) == 0ULL); - assert(std::saturate_cast( O_C) == 0ULL); - assert(std::saturate_cast( SCHAR_MAX) == static_cast(SCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(UCHAR_MAX); - assert(std::saturate_cast( O_UC) == 0ULL); - assert(std::saturate_cast( UCHAR_MAX) == static_cast(UCHAR_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(LLONG_MAX); - assert(std::saturate_cast( LLONG_MIN) == 0ULL); - assert(std::saturate_cast( 0LL) == 0ULL); - assert(std::saturate_cast( LLONG_MAX) == static_cast(LLONG_MAX)); - - std::same_as decltype(auto) _ = std::saturate_cast(ULLONG_MAX); - assert(std::saturate_cast( 0ULL) == 0ULL); - assert(std::saturate_cast(ULLONG_MAX) == ULLONG_MAX); - -#ifndef TEST_HAS_NO_INT128 - std::same_as decltype(auto) _ = std::saturate_cast(sBigMax); - assert(std::saturate_cast( sBigMin) == 0ULL); // (128-bit) saturated - assert(std::saturate_cast( sZero) == 0ULL); - assert(std::saturate_cast( sBigMax) == ULLONG_MAX); // (128-bit) saturated - - std::same_as decltype(auto) _ = std::saturate_cast(uBigMax); - assert(std::saturate_cast( uZero) == 0ULL); - assert(std::saturate_cast( uBigMax) == ULLONG_MAX); // (128-bit) saturated - - std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(SCHAR_MIN); - assert(std::saturate_cast<__uint128_t>(SCHAR_MIN) == uZero); - assert(std::saturate_cast<__uint128_t>( O_C) == uZero); - assert(std::saturate_cast<__uint128_t>(SCHAR_MAX) == static_cast<__uint128_t>(SCHAR_MAX)); - - std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(UCHAR_MAX); - assert(std::saturate_cast<__uint128_t>( O_UC) == uZero); - assert(std::saturate_cast<__uint128_t>(UCHAR_MAX) == static_cast<__uint128_t>(UCHAR_MAX)); - - std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(sBigMax); - assert(std::saturate_cast<__uint128_t>( sBigMin) == uZero); // saturated - assert(std::saturate_cast<__uint128_t>( sZero) == uZero); - assert(std::saturate_cast<__uint128_t>( sBigMax) == static_cast<__uint128_t>(sBigMax)); - - std::same_as<__uint128_t> decltype(auto) _ = std::saturate_cast<__uint128_t>(uBigMax); - assert(std::saturate_cast<__uint128_t>( uZero) == uZero); - assert(std::saturate_cast<__uint128_t>( uBigMax) == uBigMax); -#endif - - // clang-format on - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.compile.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_add.compile.pass.cpp similarity index 94% rename from libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.compile.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_add.compile.pass.cpp index 23f780cfc2b5e..03c7dc724acfb 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/add_sat.compile.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_add.compile.pass.cpp @@ -11,7 +11,7 @@ // // template -// constexpr T add_sat(T x, T y) noexcept; // freestanding +// constexpr T saturating_add(T x, T y) noexcept; // freestanding #include #include @@ -20,7 +20,7 @@ template concept CanDo = requires(T x, U y) { - { std::add_sat(x, y) } -> std::same_as; + { std::saturating_add(x, y) } -> std::same_as; }; template diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_add.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_add.pass.cpp new file mode 100644 index 0000000000000..fb05119f7c220 --- /dev/null +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_add.pass.cpp @@ -0,0 +1,171 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// constexpr T saturating_add(T x, T y) noexcept; // freestanding + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr bool test_signed() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_add(minVal, maxVal); + + static_assert(noexcept(std::saturating_add(minVal, maxVal))); + + // clang-format off + + // Limit values (-1, 0, 1, min, max) + + assert(std::saturating_add(IntegerT{-1}, IntegerT{-1}) == IntegerT{-2}); + assert(std::saturating_add(IntegerT{-1}, IntegerT{ 0}) == IntegerT{-1}); + assert(std::saturating_add(IntegerT{-1}, IntegerT{ 1}) == IntegerT{ 0}); + assert(std::saturating_add(IntegerT{-1}, minVal) == minVal); // saturated + assert(std::saturating_add(IntegerT{-1}, maxVal) == IntegerT{-1} + maxVal); + + assert(std::saturating_add(IntegerT{ 0}, IntegerT{-1}) == IntegerT{-1}); + assert(std::saturating_add(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0}); + assert(std::saturating_add(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 1}); + assert(std::saturating_add(IntegerT{ 0}, minVal) == minVal); + assert(std::saturating_add(IntegerT{ 0}, maxVal) == maxVal); + + assert(std::saturating_add(IntegerT{ 1}, IntegerT{-1}) == IntegerT{ 0}); + assert(std::saturating_add(IntegerT{ 1}, IntegerT{ 0}) == IntegerT{ 1}); + assert(std::saturating_add(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 2}); + assert(std::saturating_add(IntegerT{ 1}, minVal) == IntegerT{ 1} + minVal); + assert(std::saturating_add(IntegerT{ 1}, maxVal) == maxVal); // saturated + + assert(std::saturating_add( minVal, IntegerT{-1}) == minVal); // saturated + assert(std::saturating_add( minVal, IntegerT{ 0}) == minVal); + assert(std::saturating_add( minVal, IntegerT{ 1}) == minVal + IntegerT{ 1}); + assert(std::saturating_add( minVal, minVal) == minVal); // saturated + assert(std::saturating_add( minVal, maxVal) == IntegerT{-1}); + + assert(std::saturating_add( maxVal, IntegerT{-1}) == maxVal + IntegerT{-1}); + assert(std::saturating_add( maxVal, IntegerT{ 0}) == maxVal); + assert(std::saturating_add( maxVal, IntegerT{ 1}) == maxVal); // saturated + assert(std::saturating_add( maxVal, minVal) == IntegerT{-1}); + assert(std::saturating_add( maxVal, maxVal) == maxVal); // saturated + + // No saturation (no limit values) + + assert(std::saturating_add(IntegerT{-27}, IntegerT{28})== IntegerT{ 1}); + assert(std::saturating_add(IntegerT{ 27}, IntegerT{28})== IntegerT{55}); + { + constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_add(x, y) == maxVal); + } + + // Saturation (no limit values) + + { + constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{-27}; + constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{-28}; + assert(std::saturating_add(x, y) == minVal); // saturated + } + { + constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_add(x, y) == maxVal); // saturated + } + + // clang-format on + + return true; +} + +template +constexpr bool test_unsigned() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_add(minVal, maxVal); + + static_assert(noexcept(std::saturating_add(minVal, maxVal))); + + // clang-format off + + // Litmit values (0, 1, min, max) + + assert(std::saturating_add(IntegerT{0}, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_add(IntegerT{0}, IntegerT{1}) == IntegerT{1}); + assert(std::saturating_add(IntegerT{0}, minVal) == IntegerT{0}); + assert(std::saturating_add(IntegerT{0}, maxVal) == maxVal); + assert(std::saturating_add(IntegerT{1}, IntegerT{0}) == IntegerT{1}); + assert(std::saturating_add(IntegerT{1}, IntegerT{1}) == IntegerT{2}); + assert(std::saturating_add(IntegerT{1}, minVal) == IntegerT{1}); + assert(std::saturating_add(IntegerT{1}, maxVal) == maxVal); // saturated + assert(std::saturating_add( minVal, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_add( minVal, IntegerT{1}) == IntegerT{1}); + assert(std::saturating_add( minVal, minVal) == minVal); + assert(std::saturating_add( minVal, maxVal) == maxVal); + assert(std::saturating_add( maxVal, IntegerT{0}) == maxVal); + assert(std::saturating_add( maxVal, IntegerT{1}) == maxVal); // saturated + assert(std::saturating_add( maxVal, minVal) == maxVal); + assert(std::saturating_add( maxVal, maxVal) == maxVal); // saturated + + // No saturation (no limit values) + + assert(std::saturating_add(IntegerT{27}, IntegerT{28}) == IntegerT{55}); + + // Saturation (no limit values) + + { + constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_add( x, y) == maxVal); // saturated + assert(std::saturating_add( x, maxVal) == maxVal); // saturated + assert(std::saturating_add(maxVal, y) == maxVal); // saturated + } + + // clang-format on + + return true; +} + +constexpr bool test() { + // Signed + test_signed(); + test_signed(); + test_signed(); + test_signed(); + test_signed(); +#ifndef TEST_HAS_NO_INT128 + test_signed<__int128_t>(); +#endif + // Unsigned + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); +#ifndef TEST_HAS_NO_INT128 + test_unsigned<__uint128_t>(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.compile.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_cast.compile.pass.cpp similarity index 94% rename from libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.compile.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_cast.compile.pass.cpp index 237deb0c7c138..b8d015811798b 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturate_cast.compile.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_cast.compile.pass.cpp @@ -11,7 +11,7 @@ // // template -// constexpr R saturate_cast(T x) noexcept; // freestanding +// constexpr R saturating_cast(T x) noexcept; // freestanding #include #include @@ -20,7 +20,7 @@ template concept CanDo = requires(T x) { - { std::saturate_cast(x) } -> std::same_as; + { std::saturating_cast(x) } -> std::same_as; }; template diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_cast.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_cast.pass.cpp new file mode 100644 index 0000000000000..2fcf888e084a1 --- /dev/null +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_cast.pass.cpp @@ -0,0 +1,394 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// constexpr R saturating_cast(T x) noexcept; // freestanding + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// Smaller to larger +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); + +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); + +// Same type +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); + +// Larger to smaller +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); + +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); +static_assert(noexcept(std::saturating_cast(std::numeric_limits::max()))); + +// Tests + +constexpr bool test() { + // clang-format off + +#ifndef TEST_HAS_NO_INT128 + using SIntT = __int128_t; + using UIntT = __uint128_t; +#else + using SIntT = long long int; + using UIntT = unsigned long long int; +#endif + + // Constants the values of which depend on the context (platform) + + constexpr auto sBigMin = std::numeric_limits::min(); + constexpr auto sZero = SIntT{0}; + constexpr auto sBigMax = std::numeric_limits::max(); + + constexpr auto uZero = UIntT{0}; + constexpr auto uBigMax = std::numeric_limits::max(); + + // Constants to avoid casting in place + + constexpr auto O_C = static_cast(0); + constexpr auto O_UC = static_cast(0); + + constexpr auto O_S = static_cast(0); + constexpr auto O_US = static_cast(0); + + // signed char + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == SCHAR_MIN); + assert(std::saturating_cast( O_C) == O_C); + assert(std::saturating_cast(SCHAR_MAX) == SCHAR_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == O_C); + assert(std::saturating_cast(UCHAR_MAX) == SCHAR_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast(sBigMin) == SCHAR_MIN); // saturated + assert(std::saturating_cast( sZero) == O_C); + assert(std::saturating_cast(sBigMax) == SCHAR_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == O_C); + assert(std::saturating_cast(uBigMax) == SCHAR_MAX); // saturated + + // short + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); + assert(std::saturating_cast( O_C) == O_S); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == O_S); + assert(std::saturating_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(SHRT_MAX); + assert(std::saturating_cast( SHRT_MIN) == SHRT_MIN); + assert(std::saturating_cast( O_S) == O_S); + assert(std::saturating_cast( SHRT_MAX) == SHRT_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(USHRT_MAX); + assert(std::saturating_cast( O_US) == O_S); + assert(std::saturating_cast(USHRT_MAX) == SHRT_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == SHRT_MIN); // saturated + assert(std::saturating_cast( sZero) == O_S); + assert(std::saturating_cast( sBigMax) == SHRT_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == O_S); + assert(std::saturating_cast( uBigMax) == SHRT_MAX); // saturated + + // int + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); + assert(std::saturating_cast( O_C) == 0); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == 0); + assert(std::saturating_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(INT_MAX); + assert(std::saturating_cast( INT_MIN) == INT_MIN); + assert(std::saturating_cast( 0) == 0); + assert(std::saturating_cast( INT_MAX) == INT_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(UINT_MAX); + assert(std::saturating_cast( 0) == 0); + assert(std::saturating_cast(UINT_MAX) == INT_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == INT_MIN); // saturated + assert(std::saturating_cast( sZero) == 0); + assert(std::saturating_cast( sBigMax) == INT_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == 0); + assert(std::saturating_cast( uBigMax) == INT_MAX); // saturated + + // long + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); + assert(std::saturating_cast( O_C) == 0L); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == 0L); + assert(std::saturating_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(LONG_MAX); + assert(std::saturating_cast( LONG_MIN) == LONG_MIN); + assert(std::saturating_cast( 0L) == 0L); + assert(std::saturating_cast( LONG_MAX) == LONG_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(ULONG_MAX); + assert(std::saturating_cast( 0UL) == 0L); + assert(std::saturating_cast(ULONG_MAX) == LONG_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == LONG_MIN); // saturated + assert(std::saturating_cast( sZero) == 0L); + assert(std::saturating_cast( sBigMax) == LONG_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == 0L); + assert(std::saturating_cast( uBigMax) == LONG_MAX); // saturated + + // long long + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == static_cast(SCHAR_MIN)); + assert(std::saturating_cast( 0LL) == 0LL); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == 0LL); + assert(std::saturating_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(LLONG_MIN); + assert(std::saturating_cast(LLONG_MIN) == LLONG_MIN); + assert(std::saturating_cast( 0LL) == 0LL); + assert(std::saturating_cast(LLONG_MAX) == LLONG_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(ULLONG_MAX); + assert(std::saturating_cast( 0ULL) == 0LL); + assert(std::saturating_cast(ULLONG_MAX) == LLONG_MAX); // saturated + +#ifndef TEST_HAS_NO_INT128 + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == LLONG_MIN); // (128-bit) saturated + assert(std::saturating_cast( sZero) == 0LL); + assert(std::saturating_cast( sBigMax) == LLONG_MAX); // (128-bit) saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == 0LL); + assert(std::saturating_cast( uBigMax) == LLONG_MAX); // (128-bit) saturated + + std::same_as<__int128_t> decltype(auto) _ = std::saturating_cast<__int128_t>(SCHAR_MAX); + assert(std::saturating_cast<__int128_t>(SCHAR_MIN) == static_cast<__int128_t>(SCHAR_MIN)); + assert(std::saturating_cast<__int128_t>( O_C) == sZero); + assert(std::saturating_cast<__int128_t>(SCHAR_MAX) == static_cast<__int128_t>(SCHAR_MAX)); + + std::same_as<__int128_t> decltype(auto) _ = std::saturating_cast<__int128_t>(UCHAR_MAX); + assert(std::saturating_cast<__int128_t>( O_UC) == sZero); + assert(std::saturating_cast<__int128_t>(UCHAR_MAX) == static_cast<__int128_t>(UCHAR_MAX)); + + std::same_as<__int128_t> decltype(auto) _ = std::saturating_cast<__int128_t>(sBigMax); + assert(std::saturating_cast<__int128_t>( sBigMin) == sBigMin); + assert(std::saturating_cast<__int128_t>( sZero) == sZero); + assert(std::saturating_cast<__int128_t>( sBigMax) == sBigMax); + + std::same_as<__int128_t> decltype(auto) _ = std::saturating_cast<__int128_t>(uBigMax); + assert(std::saturating_cast<__int128_t>( uZero) == sZero); + assert(std::saturating_cast<__int128_t>( uBigMax) == sBigMax); // saturated +#endif + + // unsigned char + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == O_UC); + assert(std::saturating_cast( O_C) == O_UC); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == O_UC); + assert(std::saturating_cast(UCHAR_MAX) == UCHAR_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == O_UC); // saturated + assert(std::saturating_cast( sZero) == O_UC); + assert(std::saturating_cast( sBigMax) == UCHAR_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == O_UC); + assert(std::saturating_cast( uBigMax) == UCHAR_MAX); // saturated + + // unsigned short + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == O_US); + assert(std::saturating_cast( O_C) == O_US); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == O_US); + assert(std::saturating_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MIN); + assert(std::saturating_cast( SHRT_MIN) == O_US); + assert(std::saturating_cast( O_S) == O_US); + assert(std::saturating_cast( SHRT_MAX) == static_cast(SHRT_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_US) == O_US); + assert(std::saturating_cast(USHRT_MAX) == USHRT_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == O_US); // saturated + assert(std::saturating_cast( sZero) == O_US); + assert(std::saturating_cast( sBigMax) == USHRT_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == O_US); + assert(std::saturating_cast( uBigMax) == USHRT_MAX); // saturated + + // unsigned int + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == O_US); + assert(std::saturating_cast( O_UC) == 0U); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == 0U); + assert(std::saturating_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(INT_MAX); + assert(std::saturating_cast( INT_MIN) == 0U); + assert(std::saturating_cast( 0) == 0U); + assert(std::saturating_cast( INT_MAX) == static_cast(INT_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UINT_MAX); + assert(std::saturating_cast( 0U) == 0U); + assert(std::saturating_cast( UINT_MAX) == UINT_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == 0U); // saturated + assert(std::saturating_cast( sZero) == 0U); + assert(std::saturating_cast( sBigMax) == UINT_MAX); // saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == 0U); + assert(std::saturating_cast( uBigMax) == UINT_MAX); // saturated + + // unsigned long + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast(SCHAR_MIN) == 0UL); + assert(std::saturating_cast( O_C) == 0UL); + assert(std::saturating_cast(SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == 0UL); + assert(std::saturating_cast(UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(LONG_MAX); + assert(std::saturating_cast( LONG_MIN) == 0UL); + assert(std::saturating_cast( 0L) == 0UL); + assert(std::saturating_cast( LONG_MAX) == static_cast(LONG_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(ULONG_MAX); + assert(std::saturating_cast( 0UL) == 0UL); + assert(std::saturating_cast(ULONG_MAX) == ULONG_MAX); + + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == 0UL); // saturated + assert(std::saturating_cast( sZero) == 0UL); + assert(std::saturating_cast( sBigMax) == (sizeof(UIntT) > sizeof(unsigned long int) ? ULONG_MAX : LONG_MAX)); // saturated depending on underlying types + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == 0UL); + assert(std::saturating_cast( uBigMax) == ULONG_MAX); // saturated + + // unsigned long long + + std::same_as decltype(auto) _ = std::saturating_cast(SCHAR_MAX); + assert(std::saturating_cast( SCHAR_MIN) == 0ULL); + assert(std::saturating_cast( O_C) == 0ULL); + assert(std::saturating_cast( SCHAR_MAX) == static_cast(SCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(UCHAR_MAX); + assert(std::saturating_cast( O_UC) == 0ULL); + assert(std::saturating_cast( UCHAR_MAX) == static_cast(UCHAR_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(LLONG_MAX); + assert(std::saturating_cast( LLONG_MIN) == 0ULL); + assert(std::saturating_cast( 0LL) == 0ULL); + assert(std::saturating_cast( LLONG_MAX) == static_cast(LLONG_MAX)); + + std::same_as decltype(auto) _ = std::saturating_cast(ULLONG_MAX); + assert(std::saturating_cast( 0ULL) == 0ULL); + assert(std::saturating_cast(ULLONG_MAX) == ULLONG_MAX); + +#ifndef TEST_HAS_NO_INT128 + std::same_as decltype(auto) _ = std::saturating_cast(sBigMax); + assert(std::saturating_cast( sBigMin) == 0ULL); // (128-bit) saturated + assert(std::saturating_cast( sZero) == 0ULL); + assert(std::saturating_cast( sBigMax) == ULLONG_MAX); // (128-bit) saturated + + std::same_as decltype(auto) _ = std::saturating_cast(uBigMax); + assert(std::saturating_cast( uZero) == 0ULL); + assert(std::saturating_cast( uBigMax) == ULLONG_MAX); // (128-bit) saturated + + std::same_as<__uint128_t> decltype(auto) _ = std::saturating_cast<__uint128_t>(SCHAR_MIN); + assert(std::saturating_cast<__uint128_t>(SCHAR_MIN) == uZero); + assert(std::saturating_cast<__uint128_t>( O_C) == uZero); + assert(std::saturating_cast<__uint128_t>(SCHAR_MAX) == static_cast<__uint128_t>(SCHAR_MAX)); + + std::same_as<__uint128_t> decltype(auto) _ = std::saturating_cast<__uint128_t>(UCHAR_MAX); + assert(std::saturating_cast<__uint128_t>( O_UC) == uZero); + assert(std::saturating_cast<__uint128_t>(UCHAR_MAX) == static_cast<__uint128_t>(UCHAR_MAX)); + + std::same_as<__uint128_t> decltype(auto) _ = std::saturating_cast<__uint128_t>(sBigMax); + assert(std::saturating_cast<__uint128_t>( sBigMin) == uZero); // saturated + assert(std::saturating_cast<__uint128_t>( sZero) == uZero); + assert(std::saturating_cast<__uint128_t>( sBigMax) == static_cast<__uint128_t>(sBigMax)); + + std::same_as<__uint128_t> decltype(auto) _ = std::saturating_cast<__uint128_t>(uBigMax); + assert(std::saturating_cast<__uint128_t>( uZero) == uZero); + assert(std::saturating_cast<__uint128_t>( uBigMax) == uBigMax); +#endif + + // clang-format on + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.assert.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.assert.pass.cpp similarity index 87% rename from libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.assert.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.assert.pass.cpp index 50bc29bee4d53..79cbd8124b2de 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.assert.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.assert.pass.cpp @@ -15,7 +15,7 @@ // // template -// constexpr T div_sat(T x, T y) noexcept; // freestanding +// constexpr T saturating_div(T x, T y) noexcept; // freestanding #include #include @@ -25,7 +25,7 @@ template void test_runtime_assertion() { - TEST_LIBCPP_ASSERT_FAILURE((void)std::div_sat(IntegerT{27}, IntegerT{0}), "Division by 0 is undefined"); + TEST_LIBCPP_ASSERT_FAILURE((void)std::saturating_div(IntegerT{27}, IntegerT{0}), "Division by 0 is undefined"); } bool test() { diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.compile.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.compile.pass.cpp similarity index 93% rename from libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.compile.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.compile.pass.cpp index 02ffb17292164..f644b11db05cd 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/div_sat.compile.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.compile.pass.cpp @@ -11,7 +11,7 @@ // // template -// constexpr T div_sat(T x, T y) noexcept; // freestanding +// constexpr T saturating_div(T x, T y) noexcept; // freestanding #include #include @@ -23,7 +23,7 @@ template concept CanDo = requires(T x, U y) { - { std::div_sat(x, y) } -> std::same_as; + { std::saturating_div(x, y) } -> std::same_as; }; template @@ -82,7 +82,7 @@ constexpr void test() { // A function call expression that violates the precondition in the Preconditions: element is not a core constant expression (7.7 [expr.const]). template -using QuotT = std::integral_constant; +using QuotT = std::integral_constant; template QuotT div_by_zero(); diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.pass.cpp new file mode 100644 index 0000000000000..75045e07c3b84 --- /dev/null +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_div.pass.cpp @@ -0,0 +1,155 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// constexpr T saturating_div(T x, T y) noexcept; // freestanding + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr bool test_signed() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_div(minVal, maxVal); + + static_assert(noexcept(std::saturating_div(minVal, maxVal))); + + // clang-format off + + // Limit values (-1, 0, 1, min, max) + + assert(std::saturating_div(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 1}); + assert(std::saturating_div(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-1}); + assert(std::saturating_div(IntegerT{-1}, minVal) == IntegerT{ 0}); + assert(std::saturating_div(IntegerT{-1}, maxVal) == IntegerT{ 0}); + assert(std::saturating_div(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 0}); + assert(std::saturating_div(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 0}); + assert(std::saturating_div(IntegerT{ 0}, minVal) == IntegerT{ 0}); + assert(std::saturating_div(IntegerT{ 0}, maxVal) == IntegerT{ 0}); + assert(std::saturating_div(IntegerT{ 1}, IntegerT{-1}) == IntegerT{-1}); + assert(std::saturating_div(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 1}); + assert(std::saturating_div(IntegerT{ 1}, minVal) == IntegerT{ 0}); + assert(std::saturating_div(IntegerT{ 1}, maxVal) == IntegerT{ 0}); + assert(std::saturating_div( minVal, IntegerT{ 1}) == minVal); + assert(std::saturating_div( minVal, IntegerT{-1}) == maxVal); // saturated + assert(std::saturating_div( minVal, minVal) == IntegerT{ 1}); + assert(std::saturating_div( minVal, maxVal) == (minVal / maxVal)); + assert(std::saturating_div( maxVal, IntegerT{-1}) == -maxVal); + assert(std::saturating_div( maxVal, IntegerT{ 1}) == maxVal); + assert(std::saturating_div( maxVal, minVal) == IntegerT{ 0}); + assert(std::saturating_div( maxVal, maxVal) == IntegerT{ 1}); + + // No saturation (no limit values) + + assert(std::saturating_div(IntegerT{27}, IntegerT{28}) == IntegerT{0}); + assert(std::saturating_div(IntegerT{28}, IntegerT{27}) == IntegerT{1}); + { + constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{-28}; + constexpr IntegerT biggerVal = minVal / IntegerT{2} + IntegerT{-27}; + assert(std::saturating_div(lesserVal, biggerVal) == IntegerT{1}); + assert(std::saturating_div(biggerVal, lesserVal) == IntegerT{0}); + } + { + constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{-27}; + constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_div(lesserVal, biggerVal) == IntegerT{-1}); + assert(std::saturating_div(biggerVal, lesserVal) == IntegerT{-1}); + } + { + constexpr IntegerT lesserVal = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_div(lesserVal, biggerVal) == IntegerT{0}); + assert(std::saturating_div(biggerVal, lesserVal) == IntegerT{1}); + } + + // clang-format on + + return true; +} + +template +constexpr bool test_unsigned() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_div(minVal, maxVal); + static_assert(noexcept(std::saturating_div(minVal, maxVal))); + + // clang-format off + + // No limit values (0, 1, min, max) + + assert(std::saturating_div(IntegerT{0}, IntegerT{1}) == IntegerT{0}); + assert(std::saturating_div(IntegerT{0}, maxVal) == IntegerT{0}); + + assert(std::saturating_div(IntegerT{1}, IntegerT{1}) == IntegerT{1}); + assert(std::saturating_div(IntegerT{1}, maxVal) == IntegerT{0}); + + assert(std::saturating_div( minVal, IntegerT{1}) == minVal); + assert(std::saturating_div( minVal, maxVal) == IntegerT{0}); + + assert(std::saturating_div( maxVal, IntegerT{1}) == maxVal); + assert(std::saturating_div( maxVal, maxVal) == IntegerT{1}); + + // No saturation (no limit values) + + assert(std::saturating_div(IntegerT{27}, IntegerT{28}) == IntegerT{0}); + assert(std::saturating_div(IntegerT{28}, IntegerT{27}) == IntegerT{1}); + { + constexpr IntegerT lesserVal = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_div(lesserVal, biggerVal) == IntegerT{0}); + assert(std::saturating_div(biggerVal, lesserVal) == IntegerT{1}); + } + + // Unsigned integer division never overflows + + // clang-format on + + return true; +} + +constexpr bool test() { + // Signed + test_signed(); + test_signed(); + test_signed(); + test_signed(); + test_signed(); +#ifndef TEST_HAS_NO_INT128 + test_signed<__int128_t>(); +#endif + // Unsigned + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); +#ifndef TEST_HAS_NO_INT128 + test_unsigned<__uint128_t>(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.compile.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_mul.compile.pass.cpp similarity index 94% rename from libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.compile.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_mul.compile.pass.cpp index cd572a73006a8..418c479cd22c6 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/mul_sat.compile.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_mul.compile.pass.cpp @@ -11,7 +11,7 @@ // // template -// constexpr T mul_sat(T x, T y) noexcept; // freestanding +// constexpr T saturating_mul(T x, T y) noexcept; // freestanding #include #include @@ -20,7 +20,7 @@ template concept CanDo = requires(T x, U y) { - { std::mul_sat(x, y) } -> std::same_as; + { std::saturating_mul(x, y) } -> std::same_as; }; template diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_mul.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_mul.pass.cpp new file mode 100644 index 0000000000000..3913b7f632e29 --- /dev/null +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_mul.pass.cpp @@ -0,0 +1,177 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// constexpr T saturating_mul(T x, T y) noexcept; // freestanding + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr bool test_signed() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_mul(minVal, maxVal); + + static_assert(noexcept(std::saturating_mul(minVal, maxVal))); + + // clang-format off + + // Limit values (-1, 0, 1, min, max) + + assert(std::saturating_mul(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 1}); + assert(std::saturating_mul(IntegerT{-1}, IntegerT{ 0}) == IntegerT{ 0}); + assert(std::saturating_mul(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-1}); + assert(std::saturating_mul(IntegerT{-1}, minVal) == maxVal); // saturated + assert(std::saturating_mul(IntegerT{-1}, maxVal) == -maxVal); + + assert(std::saturating_mul(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 0}); + assert(std::saturating_mul(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0}); + assert(std::saturating_mul(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{ 0}); + assert(std::saturating_mul(IntegerT{ 0}, minVal) == IntegerT{ 0}); + assert(std::saturating_mul(IntegerT{ 0}, maxVal) == IntegerT{ 0}); + + assert(std::saturating_mul(IntegerT{ 1}, IntegerT{-1}) == IntegerT{-1}); + assert(std::saturating_mul(IntegerT{ 1}, IntegerT{ 0}) == IntegerT{ 0}); + assert(std::saturating_mul(IntegerT{ 1}, IntegerT{ 1}) == IntegerT{ 1}); + assert(std::saturating_mul(IntegerT{ 1}, minVal) == minVal); + assert(std::saturating_mul(IntegerT{ 1}, maxVal) == maxVal); + + assert(std::saturating_mul( minVal, IntegerT{-1}) == maxVal); // saturated + assert(std::saturating_mul( minVal, IntegerT{ 0}) == IntegerT{ 0}); + assert(std::saturating_mul( minVal, IntegerT{ 1}) == minVal); + assert(std::saturating_mul( minVal, minVal) == maxVal); // saturated + assert(std::saturating_mul( minVal, maxVal) == minVal); // saturated + + assert(std::saturating_mul( maxVal, IntegerT{-1}) == -maxVal); + assert(std::saturating_mul( maxVal, IntegerT{ 0}) == IntegerT{ 0}); + assert(std::saturating_mul( maxVal, IntegerT{ 1}) == maxVal); // saturated + assert(std::saturating_mul( maxVal, minVal) == minVal); // saturated + assert(std::saturating_mul( maxVal, maxVal) == maxVal); // saturated + + // No saturation (no limit values) + + assert(std::saturating_mul(IntegerT{27}, IntegerT{ 2}) == IntegerT{54}); + assert(std::saturating_mul(IntegerT{ 2}, IntegerT{28}) == IntegerT{56}); + + // Saturation (no limit values) + + { + constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_mul(x, y) == maxVal); // saturated + } + { + constexpr IntegerT x = minVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_mul(x, y) == minVal); // saturated + } + { + constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = minVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_mul(x, y) == minVal); // saturated + } + { + constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_mul(x, y) == maxVal); // saturated + } + + // clang-format on + + return true; +} + +template +constexpr bool test_unsigned() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_mul(minVal, maxVal); + + static_assert(noexcept(std::saturating_mul(minVal, maxVal))); + + // clang-format off + + // No saturation (0, 1) + + assert(std::saturating_mul(IntegerT{0}, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_mul(IntegerT{0}, IntegerT{1}) == IntegerT{0}); + assert(std::saturating_mul(IntegerT{0}, minVal) == IntegerT{0}); + assert(std::saturating_mul(IntegerT{0}, maxVal) == IntegerT{0}); + + assert(std::saturating_mul(IntegerT{1}, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_mul(IntegerT{1}, IntegerT{1}) == IntegerT{1}); + assert(std::saturating_mul(IntegerT{1}, minVal) == minVal); + assert(std::saturating_mul(IntegerT{1}, maxVal) == maxVal); + + assert(std::saturating_mul( minVal, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_mul( minVal, IntegerT{1}) == minVal); + assert(std::saturating_mul( minVal, maxVal) == minVal); + assert(std::saturating_mul( minVal, maxVal) == minVal); + + assert(std::saturating_mul( maxVal, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_mul( maxVal, IntegerT{1}) == maxVal); + assert(std::saturating_mul( maxVal, minVal) == IntegerT{0}); + assert(std::saturating_mul( maxVal, maxVal) == maxVal); // saturated + + // No saturation (no limit values) + + assert(std::saturating_mul(IntegerT{28}, IntegerT{2}) == IntegerT{56}); + + // Saturation (no limit values) + + { + constexpr IntegerT x = maxVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT y = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_mul(x, y) == maxVal); // saturated + } + + // clang-format on + + return true; +} + +constexpr bool test() { + // Signed + test_signed(); + test_signed(); + test_signed(); + test_signed(); + test_signed(); +#ifndef TEST_HAS_NO_INT128 + test_signed<__int128_t>(); +#endif + // Unsigned + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); +#ifndef TEST_HAS_NO_INT128 + test_unsigned<__uint128_t>(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.compile.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_sub.compile.pass.cpp similarity index 94% rename from libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.compile.pass.cpp rename to libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_sub.compile.pass.cpp index 453b9b3600f8a..9676d29b2c32c 100644 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.compile.pass.cpp +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_sub.compile.pass.cpp @@ -11,7 +11,7 @@ // // template -// constexpr T sub_sat(T x, T y) noexcept; // freestanding +// constexpr T saturating_sub(T x, T y) noexcept; // freestanding #include #include @@ -20,7 +20,7 @@ template concept CanDo = requires(T x, U y) { - { std::sub_sat(x, y) } -> std::same_as; + { std::saturating_sub(x, y) } -> std::same_as; }; template diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_sub.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_sub.pass.cpp new file mode 100644 index 0000000000000..15659057ae45a --- /dev/null +++ b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/saturating_sub.pass.cpp @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// constexpr T saturating_sub(T x, T y) noexcept; // freestanding + +#include +#include +#include +#include + +#include "test_macros.h" + +template +constexpr bool test_signed() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_sub(minVal, maxVal); + + static_assert(noexcept(std::saturating_sub(minVal, maxVal))); + + // clang-format off + + // Limit values (-1, 0, 1, min, max) + + assert(std::saturating_sub(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 0}); + assert(std::saturating_sub(IntegerT{-1}, IntegerT{ 0}) == IntegerT{-1}); + assert(std::saturating_sub(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-2}); + assert(std::saturating_sub(IntegerT{-1}, minVal) == IntegerT{-1} - minVal); + assert(std::saturating_sub(IntegerT{-1}, maxVal) == IntegerT{-1} - maxVal); + + assert(std::saturating_sub(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 1}); + assert(std::saturating_sub(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0}); + assert(std::saturating_sub(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{-1}); + assert(std::saturating_sub(IntegerT{ 0}, minVal) == maxVal); // saturated + assert(std::saturating_sub(IntegerT{ 0}, maxVal) == -maxVal); + + assert(std::saturating_sub( minVal, IntegerT{-1}) == minVal - IntegerT{-1}); + assert(std::saturating_sub( minVal, IntegerT{ 0}) == minVal); + assert(std::saturating_sub( minVal, IntegerT{ 1}) == minVal); // saturated + assert(std::saturating_sub( minVal, minVal) == IntegerT{0}); + assert(std::saturating_sub( minVal, maxVal) == minVal); // saturated + + assert(std::saturating_sub( maxVal, IntegerT{-1}) == maxVal); // saturated + assert(std::saturating_sub( maxVal, IntegerT{ 0}) == maxVal); + assert(std::saturating_sub( maxVal, IntegerT{ 1}) == maxVal - IntegerT{ 1}); + assert(std::saturating_sub( maxVal, minVal) == maxVal); // saturated + assert(std::saturating_sub( maxVal, maxVal) == IntegerT{0}); + + // No saturation (no limit values) + + assert(std::saturating_sub(IntegerT{ 27}, IntegerT{-28}) == 55); + assert(std::saturating_sub(IntegerT{ 27}, IntegerT{ 28}) == -1); + assert(std::saturating_sub(IntegerT{-27}, IntegerT{ 28}) == -55); + assert(std::saturating_sub(IntegerT{-27}, IntegerT{-28}) == 1); + + // Saturation (no limit values) + + { + constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_sub(lesserVal, biggerVal) == minVal); // saturated + } + { + constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; + constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{27}; + assert(std::saturating_sub(biggerVal, lesserVal) == maxVal); // saturated + } + + // clang-format on + + return true; +} + +template +constexpr bool test_unsigned() { + constexpr auto minVal = std::numeric_limits::min(); + constexpr auto maxVal = std::numeric_limits::max(); + + std::same_as decltype(auto) _ = std::saturating_sub(minVal, maxVal); + + static_assert(noexcept(std::saturating_sub(minVal, maxVal))); + + // clang-format off + + // Limit values (0, 1, min, max) + + assert(std::saturating_sub(IntegerT{0}, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_sub(IntegerT{0}, IntegerT{1}) == minVal); // saturated + assert(std::saturating_sub(IntegerT{0}, minVal) == minVal); + assert(std::saturating_sub(IntegerT{0}, maxVal) == minVal); // saturated + + assert(std::saturating_sub(IntegerT{1}, IntegerT{0}) == IntegerT{1}); + assert(std::saturating_sub(IntegerT{1}, IntegerT{1}) == IntegerT{0}); + assert(std::saturating_sub(IntegerT{1}, minVal) == IntegerT{1}); + assert(std::saturating_sub(IntegerT{1}, maxVal) == minVal); // saturated + + assert(std::saturating_sub( minVal, IntegerT{0}) == IntegerT{0}); + assert(std::saturating_sub( minVal, IntegerT{1}) == minVal); + assert(std::saturating_sub( minVal, maxVal) == minVal); + assert(std::saturating_sub( minVal, maxVal) == minVal); + + assert(std::saturating_sub( maxVal, IntegerT{0}) == maxVal); + assert(std::saturating_sub( maxVal, IntegerT{1}) == maxVal - IntegerT{1}); + assert(std::saturating_sub( maxVal, minVal) == maxVal); + assert(std::saturating_sub( maxVal, maxVal) == IntegerT{0}); + + // Saturation (no limit values) + + { + constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{27}; + constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; + assert(std::saturating_sub(lesserVal, biggerVal) == minVal); // saturated + } + + // clang-format on + + return true; +} + +constexpr bool test() { + // Signed + test_signed(); + test_signed(); + test_signed(); + test_signed(); + test_signed(); +#ifndef TEST_HAS_NO_INT128 + test_signed<__int128_t>(); +#endif + // Unsigned + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); + test_unsigned(); +#ifndef TEST_HAS_NO_INT128 + test_unsigned<__uint128_t>(); +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp b/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp deleted file mode 100644 index c2be8c5a47bdf..0000000000000 --- a/libcxx/test/std/numerics/numeric.ops/numeric.ops.sat/sub_sat.pass.cpp +++ /dev/null @@ -1,159 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// REQUIRES: std-at-least-c++26 - -// - -// template -// constexpr T sub_sat(T x, T y) noexcept; // freestanding - -#include -#include -#include -#include - -#include "test_macros.h" - -template -constexpr bool test_signed() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::sub_sat(minVal, maxVal); - - static_assert(noexcept(std::sub_sat(minVal, maxVal))); - - // clang-format off - - // Limit values (-1, 0, 1, min, max) - - assert(std::sub_sat(IntegerT{-1}, IntegerT{-1}) == IntegerT{ 0}); - assert(std::sub_sat(IntegerT{-1}, IntegerT{ 0}) == IntegerT{-1}); - assert(std::sub_sat(IntegerT{-1}, IntegerT{ 1}) == IntegerT{-2}); - assert(std::sub_sat(IntegerT{-1}, minVal) == IntegerT{-1} - minVal); - assert(std::sub_sat(IntegerT{-1}, maxVal) == IntegerT{-1} - maxVal); - - assert(std::sub_sat(IntegerT{ 0}, IntegerT{-1}) == IntegerT{ 1}); - assert(std::sub_sat(IntegerT{ 0}, IntegerT{ 0}) == IntegerT{ 0}); - assert(std::sub_sat(IntegerT{ 0}, IntegerT{ 1}) == IntegerT{-1}); - assert(std::sub_sat(IntegerT{ 0}, minVal) == maxVal); // saturated - assert(std::sub_sat(IntegerT{ 0}, maxVal) == -maxVal); - - assert(std::sub_sat( minVal, IntegerT{-1}) == minVal - IntegerT{-1}); - assert(std::sub_sat( minVal, IntegerT{ 0}) == minVal); - assert(std::sub_sat( minVal, IntegerT{ 1}) == minVal); // saturated - assert(std::sub_sat( minVal, minVal) == IntegerT{0}); - assert(std::sub_sat( minVal, maxVal) == minVal); // saturated - - assert(std::sub_sat( maxVal, IntegerT{-1}) == maxVal); // saturated - assert(std::sub_sat( maxVal, IntegerT{ 0}) == maxVal); - assert(std::sub_sat( maxVal, IntegerT{ 1}) == maxVal - IntegerT{ 1}); - assert(std::sub_sat( maxVal, minVal) == maxVal); // saturated - assert(std::sub_sat( maxVal, maxVal) == IntegerT{0}); - - // No saturation (no limit values) - - assert(std::sub_sat(IntegerT{ 27}, IntegerT{-28}) == 55); - assert(std::sub_sat(IntegerT{ 27}, IntegerT{ 28}) == -1); - assert(std::sub_sat(IntegerT{-27}, IntegerT{ 28}) == -55); - assert(std::sub_sat(IntegerT{-27}, IntegerT{-28}) == 1); - - // Saturation (no limit values) - - { - constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::sub_sat(lesserVal, biggerVal) == minVal); // saturated - } - { - constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; - constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{27}; - assert(std::sub_sat(biggerVal, lesserVal) == maxVal); // saturated - } - - // clang-format on - - return true; -} - -template -constexpr bool test_unsigned() { - constexpr auto minVal = std::numeric_limits::min(); - constexpr auto maxVal = std::numeric_limits::max(); - - std::same_as decltype(auto) _ = std::sub_sat(minVal, maxVal); - - static_assert(noexcept(std::sub_sat(minVal, maxVal))); - - // clang-format off - - // Limit values (0, 1, min, max) - - assert(std::sub_sat(IntegerT{0}, IntegerT{0}) == IntegerT{0}); - assert(std::sub_sat(IntegerT{0}, IntegerT{1}) == minVal); // saturated - assert(std::sub_sat(IntegerT{0}, minVal) == minVal); - assert(std::sub_sat(IntegerT{0}, maxVal) == minVal); // saturated - - assert(std::sub_sat(IntegerT{1}, IntegerT{0}) == IntegerT{1}); - assert(std::sub_sat(IntegerT{1}, IntegerT{1}) == IntegerT{0}); - assert(std::sub_sat(IntegerT{1}, minVal) == IntegerT{1}); - assert(std::sub_sat(IntegerT{1}, maxVal) == minVal); // saturated - - assert(std::sub_sat( minVal, IntegerT{0}) == IntegerT{0}); - assert(std::sub_sat( minVal, IntegerT{1}) == minVal); - assert(std::sub_sat( minVal, maxVal) == minVal); - assert(std::sub_sat( minVal, maxVal) == minVal); - - assert(std::sub_sat( maxVal, IntegerT{0}) == maxVal); - assert(std::sub_sat( maxVal, IntegerT{1}) == maxVal - IntegerT{1}); - assert(std::sub_sat( maxVal, minVal) == maxVal); - assert(std::sub_sat( maxVal, maxVal) == IntegerT{0}); - - // Saturation (no limit values) - - { - constexpr IntegerT lesserVal = minVal / IntegerT{2} + IntegerT{27}; - constexpr IntegerT biggerVal = maxVal / IntegerT{2} + IntegerT{28}; - assert(std::sub_sat(lesserVal, biggerVal) == minVal); // saturated - } - - // clang-format on - - return true; -} - -constexpr bool test() { - // Signed - test_signed(); - test_signed(); - test_signed(); - test_signed(); - test_signed(); -#ifndef TEST_HAS_NO_INT128 - test_signed<__int128_t>(); -#endif - // Unsigned - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); - test_unsigned(); -#ifndef TEST_HAS_NO_INT128 - test_unsigned<__uint128_t>(); -#endif - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 3dfe8c0768260..56a1d0c39c9fb 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1222,7 +1222,7 @@ def add_version_header(tc): }, { "name": "__cpp_lib_saturation_arithmetic", - "values": {"c++26": 202311}, # P0543R3 Saturation arithmetic + "values": {"c++26": 202603}, # P0543R3 Saturation arithmetic "headers": ["numeric"], }, {