xref: /freebsd-src/contrib/llvm-project/libcxx/include/__numeric/saturation_arithmetic.h (revision b3edf4467982447620505a28fc82e38a414c07dc)
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