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 137a6dacacSDimitry Andric #include <__concepts/arithmetic.h> 147a6dacacSDimitry Andric #include <__config> 157a6dacacSDimitry Andric #include <__utility/cmp.h> 167a6dacacSDimitry Andric #include <limits> 177a6dacacSDimitry Andric 187a6dacacSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 197a6dacacSDimitry Andric # pragma GCC system_header 207a6dacacSDimitry Andric #endif 217a6dacacSDimitry Andric 22*b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS 23*b3edf446SDimitry Andric #include <__undef_macros> 24*b3edf446SDimitry Andric 257a6dacacSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 267a6dacacSDimitry Andric 277a6dacacSDimitry Andric #if _LIBCPP_STD_VER >= 26 287a6dacacSDimitry Andric 297a6dacacSDimitry Andric template <__libcpp_integer _Tp> 307a6dacacSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { 317a6dacacSDimitry Andric if (_Tp __sum; !__builtin_add_overflow(__x, __y, &__sum)) 327a6dacacSDimitry Andric return __sum; 337a6dacacSDimitry Andric // Handle overflow 347a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 357a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 367a6dacacSDimitry Andric } else { 377a6dacacSDimitry Andric // Signed addition overflow 387a6dacacSDimitry Andric if (__x > 0) 397a6dacacSDimitry Andric // Overflows if (x > 0 && y > 0) 407a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 417a6dacacSDimitry Andric else 427a6dacacSDimitry Andric // Overflows if (x < 0 && y < 0) 437a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 447a6dacacSDimitry Andric } 457a6dacacSDimitry Andric } 467a6dacacSDimitry Andric 477a6dacacSDimitry Andric template <__libcpp_integer _Tp> 487a6dacacSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { 497a6dacacSDimitry Andric if (_Tp __sub; !__builtin_sub_overflow(__x, __y, &__sub)) 507a6dacacSDimitry Andric return __sub; 517a6dacacSDimitry Andric // Handle overflow 527a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 537a6dacacSDimitry Andric // Overflows if (x < y) 547a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 557a6dacacSDimitry Andric } else { 567a6dacacSDimitry Andric // Signed subtration overflow 577a6dacacSDimitry Andric if (__x >= 0) 587a6dacacSDimitry Andric // Overflows if (x >= 0 && y < 0) 597a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 607a6dacacSDimitry Andric else 617a6dacacSDimitry Andric // Overflows if (x < 0 && y > 0) 627a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 637a6dacacSDimitry Andric } 647a6dacacSDimitry Andric } 657a6dacacSDimitry Andric 667a6dacacSDimitry Andric template <__libcpp_integer _Tp> 677a6dacacSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { 687a6dacacSDimitry Andric if (_Tp __mul; !__builtin_mul_overflow(__x, __y, &__mul)) 697a6dacacSDimitry Andric return __mul; 707a6dacacSDimitry Andric // Handle overflow 717a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 727a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 737a6dacacSDimitry Andric } else { 747a6dacacSDimitry Andric // Signed multiplication overflow 757a6dacacSDimitry Andric if ((__x > 0 && __y > 0) || (__x < 0 && __y < 0)) 767a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 777a6dacacSDimitry Andric // Overflows if (x < 0 && y > 0) || (x > 0 && y < 0) 787a6dacacSDimitry Andric return std::numeric_limits<_Tp>::min(); 797a6dacacSDimitry Andric } 807a6dacacSDimitry Andric } 817a6dacacSDimitry Andric 827a6dacacSDimitry Andric template <__libcpp_integer _Tp> 837a6dacacSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { 847a6dacacSDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__y != 0, "Division by 0 is undefined"); 857a6dacacSDimitry Andric if constexpr (__libcpp_unsigned_integer<_Tp>) { 867a6dacacSDimitry Andric return __x / __y; 877a6dacacSDimitry Andric } else { 887a6dacacSDimitry Andric // Handle signed division overflow 897a6dacacSDimitry Andric if (__x == std::numeric_limits<_Tp>::min() && __y == _Tp{-1}) 907a6dacacSDimitry Andric return std::numeric_limits<_Tp>::max(); 917a6dacacSDimitry Andric return __x / __y; 927a6dacacSDimitry Andric } 937a6dacacSDimitry Andric } 947a6dacacSDimitry Andric 957a6dacacSDimitry Andric template <__libcpp_integer _Rp, __libcpp_integer _Tp> 967a6dacacSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept { 977a6dacacSDimitry Andric // Saturation is impossible edge case when ((min _Rp) < (min _Tp) && (max _Rp) > (max _Tp)) and it is expected to be 987a6dacacSDimitry Andric // optimized out by the compiler. 997a6dacacSDimitry Andric 1007a6dacacSDimitry Andric // Handle overflow 1017a6dacacSDimitry Andric if (std::cmp_less(__x, std::numeric_limits<_Rp>::min())) 1027a6dacacSDimitry Andric return std::numeric_limits<_Rp>::min(); 1037a6dacacSDimitry Andric if (std::cmp_greater(__x, std::numeric_limits<_Rp>::max())) 1047a6dacacSDimitry Andric return std::numeric_limits<_Rp>::max(); 1057a6dacacSDimitry Andric // No overflow 1067a6dacacSDimitry Andric return static_cast<_Rp>(__x); 1077a6dacacSDimitry Andric } 1087a6dacacSDimitry Andric 1097a6dacacSDimitry Andric #endif // _LIBCPP_STD_VER >= 26 1107a6dacacSDimitry Andric 1117a6dacacSDimitry Andric _LIBCPP_END_NAMESPACE_STD 1127a6dacacSDimitry Andric 113*b3edf446SDimitry Andric _LIBCPP_POP_MACROS 114*b3edf446SDimitry Andric 1157a6dacacSDimitry Andric #endif // _LIBCPP___NUMERIC_SATURATION_ARITHMETIC_H 116