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