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