1e78f53d1SNikolas Klauser // -*- C++ -*- 2e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===// 3e78f53d1SNikolas Klauser // 4e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information. 6e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7e78f53d1SNikolas Klauser // 8e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===// 9e78f53d1SNikolas Klauser 10*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___NUMERIC_SATURATION_ARITHMETIC_H 11*ce777190SNikolas Klauser #define _LIBCPP___CXX03___NUMERIC_SATURATION_ARITHMETIC_H 12e78f53d1SNikolas Klauser 1373fbae83SNikolas Klauser #include <__cxx03/__assert> 1473fbae83SNikolas Klauser #include <__cxx03/__concepts/arithmetic.h> 1573fbae83SNikolas Klauser #include <__cxx03/__config> 1673fbae83SNikolas Klauser #include <__cxx03/__utility/cmp.h> 1773fbae83SNikolas Klauser #include <__cxx03/limits> 18e78f53d1SNikolas Klauser 19e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 20e78f53d1SNikolas Klauser # pragma GCC system_header 21e78f53d1SNikolas Klauser #endif 22e78f53d1SNikolas Klauser 23e78f53d1SNikolas Klauser _LIBCPP_PUSH_MACROS 2473fbae83SNikolas Klauser #include <__cxx03/__undef_macros> 25e78f53d1SNikolas Klauser 26e78f53d1SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD 27e78f53d1SNikolas Klauser 28e78f53d1SNikolas Klauser #if _LIBCPP_STD_VER >= 20 29e78f53d1SNikolas Klauser 30e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 31e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { 32e78f53d1SNikolas Klauser if (_Tp __sum; !__builtin_add_overflow(__x, __y, &__sum)) 33e78f53d1SNikolas Klauser return __sum; 34e78f53d1SNikolas Klauser // Handle overflow 35e78f53d1SNikolas Klauser if constexpr (__libcpp_unsigned_integer<_Tp>) { 36e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::max(); 37e78f53d1SNikolas Klauser } else { 38e78f53d1SNikolas Klauser // Signed addition overflow 39e78f53d1SNikolas Klauser if (__x > 0) 40e78f53d1SNikolas Klauser // Overflows if (x > 0 && y > 0) 41e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::max(); 42e78f53d1SNikolas Klauser else 43e78f53d1SNikolas Klauser // Overflows if (x < 0 && y < 0) 44e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::min(); 45e78f53d1SNikolas Klauser } 46e78f53d1SNikolas Klauser } 47e78f53d1SNikolas Klauser 48e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 49e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { 50e78f53d1SNikolas Klauser if (_Tp __sub; !__builtin_sub_overflow(__x, __y, &__sub)) 51e78f53d1SNikolas Klauser return __sub; 52e78f53d1SNikolas Klauser // Handle overflow 53e78f53d1SNikolas Klauser if constexpr (__libcpp_unsigned_integer<_Tp>) { 54e78f53d1SNikolas Klauser // Overflows if (x < y) 55e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::min(); 56e78f53d1SNikolas Klauser } else { 57e78f53d1SNikolas Klauser // Signed subtration overflow 58e78f53d1SNikolas Klauser if (__x >= 0) 59e78f53d1SNikolas Klauser // Overflows if (x >= 0 && y < 0) 60e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::max(); 61e78f53d1SNikolas Klauser else 62e78f53d1SNikolas Klauser // Overflows if (x < 0 && y > 0) 63e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::min(); 64e78f53d1SNikolas Klauser } 65e78f53d1SNikolas Klauser } 66e78f53d1SNikolas Klauser 67e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 68e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept { 69e78f53d1SNikolas Klauser if (_Tp __mul; !__builtin_mul_overflow(__x, __y, &__mul)) 70e78f53d1SNikolas Klauser return __mul; 71e78f53d1SNikolas Klauser // Handle overflow 72e78f53d1SNikolas Klauser if constexpr (__libcpp_unsigned_integer<_Tp>) { 73e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::max(); 74e78f53d1SNikolas Klauser } else { 75e78f53d1SNikolas Klauser // Signed multiplication overflow 76e78f53d1SNikolas Klauser if ((__x > 0 && __y > 0) || (__x < 0 && __y < 0)) 77e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::max(); 78e78f53d1SNikolas Klauser // Overflows if (x < 0 && y > 0) || (x > 0 && y < 0) 79e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::min(); 80e78f53d1SNikolas Klauser } 81e78f53d1SNikolas Klauser } 82e78f53d1SNikolas Klauser 83e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 84e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept { 85e78f53d1SNikolas Klauser _LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined"); 86e78f53d1SNikolas Klauser if constexpr (__libcpp_unsigned_integer<_Tp>) { 87e78f53d1SNikolas Klauser return __x / __y; 88e78f53d1SNikolas Klauser } else { 89e78f53d1SNikolas Klauser // Handle signed division overflow 90e78f53d1SNikolas Klauser if (__x == std::numeric_limits<_Tp>::min() && __y == _Tp{-1}) 91e78f53d1SNikolas Klauser return std::numeric_limits<_Tp>::max(); 92e78f53d1SNikolas Klauser return __x / __y; 93e78f53d1SNikolas Klauser } 94e78f53d1SNikolas Klauser } 95e78f53d1SNikolas Klauser 96e78f53d1SNikolas Klauser template <__libcpp_integer _Rp, __libcpp_integer _Tp> 97e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept { 98e78f53d1SNikolas Klauser // Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be 99e78f53d1SNikolas Klauser // optimized out by the compiler. 100e78f53d1SNikolas Klauser 101e78f53d1SNikolas Klauser // Handle overflow 102e78f53d1SNikolas Klauser if (std::cmp_less(__x, std::numeric_limits<_Rp>::min())) 103e78f53d1SNikolas Klauser return std::numeric_limits<_Rp>::min(); 104e78f53d1SNikolas Klauser if (std::cmp_greater(__x, std::numeric_limits<_Rp>::max())) 105e78f53d1SNikolas Klauser return std::numeric_limits<_Rp>::max(); 106e78f53d1SNikolas Klauser // No overflow 107e78f53d1SNikolas Klauser return static_cast<_Rp>(__x); 108e78f53d1SNikolas Klauser } 109e78f53d1SNikolas Klauser 110e78f53d1SNikolas Klauser #endif // _LIBCPP_STD_VER >= 20 111e78f53d1SNikolas Klauser 112e78f53d1SNikolas Klauser #if _LIBCPP_STD_VER >= 26 113e78f53d1SNikolas Klauser 114e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 115e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { 116e78f53d1SNikolas Klauser return std::__add_sat(__x, __y); 117e78f53d1SNikolas Klauser } 118e78f53d1SNikolas Klauser 119e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 120e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { 121e78f53d1SNikolas Klauser return std::__sub_sat(__x, __y); 122e78f53d1SNikolas Klauser } 123e78f53d1SNikolas Klauser 124e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 125e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { 126e78f53d1SNikolas Klauser return std::__mul_sat(__x, __y); 127e78f53d1SNikolas Klauser } 128e78f53d1SNikolas Klauser 129e78f53d1SNikolas Klauser template <__libcpp_integer _Tp> 130e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { 131e78f53d1SNikolas Klauser return std::__div_sat(__x, __y); 132e78f53d1SNikolas Klauser } 133e78f53d1SNikolas Klauser 134e78f53d1SNikolas Klauser template <__libcpp_integer _Rp, __libcpp_integer _Tp> 135e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept { 136e78f53d1SNikolas Klauser return std::__saturate_cast<_Rp>(__x); 137e78f53d1SNikolas Klauser } 138e78f53d1SNikolas Klauser 139e78f53d1SNikolas Klauser #endif // _LIBCPP_STD_VER >= 26 140e78f53d1SNikolas Klauser 141e78f53d1SNikolas Klauser _LIBCPP_END_NAMESPACE_STD 142e78f53d1SNikolas Klauser 143e78f53d1SNikolas Klauser _LIBCPP_POP_MACROS 144e78f53d1SNikolas Klauser 145*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___NUMERIC_SATURATION_ARITHMETIC_H 146