xref: /freebsd/contrib/llvm-project/libcxx/include/__numeric/saturation_arithmetic.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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>
__add_sat(_Tp __x,_Tp __y)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>
__sub_sat(_Tp __x,_Tp __y)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>
__mul_sat(_Tp __x,_Tp __y)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>
__div_sat(_Tp __x,_Tp __y)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>
__saturate_cast(_Tp __x)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>
add_sat(_Tp __x,_Tp __y)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>
sub_sat(_Tp __x,_Tp __y)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>
mul_sat(_Tp __x,_Tp __y)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>
div_sat(_Tp __x,_Tp __y)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>
saturate_cast(_Tp __x)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