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