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