17a6dacacSDimitry Andric // -*- C++ -*- 27a6dacacSDimitry Andric //===----------------------------------------------------------------------===// 37a6dacacSDimitry Andric // 47a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 57a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 67a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 77a6dacacSDimitry Andric // 87a6dacacSDimitry Andric //===----------------------------------------------------------------------===// 97a6dacacSDimitry Andric 107a6dacacSDimitry Andric #ifndef _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H 117a6dacacSDimitry Andric #define _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H 127a6dacacSDimitry Andric 13*0fca6ea1SDimitry Andric #include <__assert> 147a6dacacSDimitry Andric #include <__concepts/arithmetic.h> 157a6dacacSDimitry Andric #include <__config> 167a6dacacSDimitry Andric #include <__utility/cmp.h> 177a6dacacSDimitry Andric #include <limits> 187a6dacacSDimitry Andric 197a6dacacSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 207a6dacacSDimitry Andric # pragma GCC system_header 217a6dacacSDimitry Andric #endif 227a6dacacSDimitry Andric 23b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS 24b3edf446SDimitry Andric #include <__undef_macros> 25b3edf446SDimitry Andric 267a6dacacSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 277a6dacacSDimitry Andric 28*0fca6ea1SDimitry Andric #if _LIBCPP_STD_VER >= 20 297a6dacacSDimitry Andric 307a6dacacSDimitry Andric template <__libcpp_integer _Tp> 31*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { 327a6dacacSDimitry Andric if (_Tp __sum; !__builtin_add_overflow(__x, __y, &__sum)) 337a6dacacSDimitry Andric return __sum; 347a6dacacSDimitry Andric // Handle overflow 357a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 367a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 377a6dacacSDimitry Andric } else { 387a6dacacSDimitry Andric // Signed addition overflow 397a6dacacSDimitry Andric if (__x > 0) 407a6dacacSDimitry Andric // Overflows if (x > 0 && y > 0) 417a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 427a6dacacSDimitry Andric else 437a6dacacSDimitry Andric // Overflows if (x < 0 && y < 0) 447a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 457a6dacacSDimitry Andric } 467a6dacacSDimitry Andric } 477a6dacacSDimitry Andric 487a6dacacSDimitry Andric template <__libcpp_integer _Tp> 49*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { 507a6dacacSDimitry Andric if (_Tp __sub; !__builtin_sub_overflow(__x, __y, &__sub)) 517a6dacacSDimitry Andric return __sub; 527a6dacacSDimitry Andric // Handle overflow 537a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 547a6dacacSDimitry Andric // Overflows if (x < y) 557a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 567a6dacacSDimitry Andric } else { 577a6dacacSDimitry Andric // Signed subtration overflow 587a6dacacSDimitry Andric if (__x >= 0) 597a6dacacSDimitry Andric // Overflows if (x >= 0 && y < 0) 607a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 617a6dacacSDimitry Andric else 627a6dacacSDimitry Andric // Overflows if (x < 0 && y > 0) 637a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 647a6dacacSDimitry Andric } 657a6dacacSDimitry Andric } 667a6dacacSDimitry Andric 677a6dacacSDimitry Andric template <__libcpp_integer _Tp> 68*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp __mul_sat(_Tp __x, _Tp __y) noexcept { 697a6dacacSDimitry Andric if (_Tp __mul; !__builtin_mul_overflow(__x, __y, &__mul)) 707a6dacacSDimitry Andric return __mul; 717a6dacacSDimitry Andric // Handle overflow 727a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 737a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 747a6dacacSDimitry Andric } else { 757a6dacacSDimitry Andric // Signed multiplication overflow 767a6dacacSDimitry Andric if ((__x > 0 && __y > 0) || (__x < 0 && __y < 0)) 777a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 787a6dacacSDimitry Andric // Overflows if (x < 0 && y > 0) || (x > 0 && y < 0) 797a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 807a6dacacSDimitry Andric } 817a6dacacSDimitry Andric } 827a6dacacSDimitry Andric 837a6dacacSDimitry Andric template <__libcpp_integer _Tp> 84*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp __div_sat(_Tp __x, _Tp __y) noexcept { 857a6dacacSDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined"); 867a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 877a6dacacSDimitry Andric return __x / __y; 887a6dacacSDimitry Andric } else { 897a6dacacSDimitry Andric // Handle signed division overflow 907a6dacacSDimitry Andric if (__x == std::numeric_limits<_Tp>::min() && __y == _Tp{-1}) 917a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 927a6dacacSDimitry Andric return __x / __y; 937a6dacacSDimitry Andric } 947a6dacacSDimitry Andric } 957a6dacacSDimitry Andric 967a6dacacSDimitry Andric template <__libcpp_integer _Rp, __libcpp_integer _Tp> 97*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept { 987a6dacacSDimitry Andric // Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be 997a6dacacSDimitry Andric // optimized out by the compiler. 1007a6dacacSDimitry Andric 1017a6dacacSDimitry Andric // Handle overflow 1027a6dacacSDimitry Andric if (std::cmp_less(__x, std::numeric_limits<_Rp>::min())) 1037a6dacacSDimitry Andric return std::numeric_limits<_Rp>::min(); 1047a6dacacSDimitry Andric if (std::cmp_greater(__x, std::numeric_limits<_Rp>::max())) 1057a6dacacSDimitry Andric return std::numeric_limits<_Rp>::max(); 1067a6dacacSDimitry Andric // No overflow 1077a6dacacSDimitry Andric return static_cast<_Rp>(__x); 1087a6dacacSDimitry Andric } 1097a6dacacSDimitry Andric 110*0fca6ea1SDimitry Andric #endif // _LIBCPP_STD_VER >= 20 111*0fca6ea1SDimitry Andric 112*0fca6ea1SDimitry Andric #if _LIBCPP_STD_VER >= 26 113*0fca6ea1SDimitry Andric 114*0fca6ea1SDimitry Andric template <__libcpp_integer _Tp> 115*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { 116*0fca6ea1SDimitry Andric return std::__add_sat(__x, __y); 117*0fca6ea1SDimitry Andric } 118*0fca6ea1SDimitry Andric 119*0fca6ea1SDimitry Andric template <__libcpp_integer _Tp> 120*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { 121*0fca6ea1SDimitry Andric return std::__sub_sat(__x, __y); 122*0fca6ea1SDimitry Andric } 123*0fca6ea1SDimitry Andric 124*0fca6ea1SDimitry Andric template <__libcpp_integer _Tp> 125*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { 126*0fca6ea1SDimitry Andric return std::__mul_sat(__x, __y); 127*0fca6ea1SDimitry Andric } 128*0fca6ea1SDimitry Andric 129*0fca6ea1SDimitry Andric template <__libcpp_integer _Tp> 130*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { 131*0fca6ea1SDimitry Andric return std::__div_sat(__x, __y); 132*0fca6ea1SDimitry Andric } 133*0fca6ea1SDimitry Andric 134*0fca6ea1SDimitry Andric template <__libcpp_integer _Rp, __libcpp_integer _Tp> 135*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept { 136*0fca6ea1SDimitry Andric return std::__saturate_cast<_Rp>(__x); 137*0fca6ea1SDimitry Andric } 138*0fca6ea1SDimitry Andric 1397a6dacacSDimitry Andric #endif // _LIBCPP_STD_VER >= 26 1407a6dacacSDimitry Andric 1417a6dacacSDimitry Andric _LIBCPP_END_NAMESPACE_STD 1427a6dacacSDimitry Andric 143b3edf446SDimitry Andric _LIBCPP_POP_MACROS 144b3edf446SDimitry Andric 1457a6dacacSDimitry Andric #endif // _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H 146