libstdc++
sat_arith.h
Go to the documentation of this file.
1// Saturation arithmetic -*- C++ -*-
2
3// Copyright The GNU Toolchain Authors.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file include/bits/sat_arith.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{numeric}
28 */
29
30#ifndef _GLIBCXX_SAT_ARITH_H
31#define _GLIBCXX_SAT_ARITH_H 1
32
33#ifdef _GLIBCXX_SYSHDR
34#pragma GCC system_header
35#endif
36
37#include <bits/version.h>
38
39#ifdef __glibcxx_saturation_arithmetic // C++ >= 26
40
41#include <concepts>
42#include <ext/numeric_traits.h>
43
44namespace std _GLIBCXX_VISIBILITY(default)
45{
46_GLIBCXX_BEGIN_NAMESPACE_VERSION
47
48 /// Add two integers, with saturation in case of overflow.
49 template<typename _Tp> requires __is_standard_integer<_Tp>::value
50 constexpr _Tp
51 add_sat(_Tp __x, _Tp __y) noexcept
52 {
53 _Tp __z;
54 if (!__builtin_add_overflow(__x, __y, &__z))
55 return __z;
56 if constexpr (is_unsigned_v<_Tp>)
57 return __gnu_cxx::__int_traits<_Tp>::__max;
58 else if (__x < 0)
59 return __gnu_cxx::__int_traits<_Tp>::__min;
60 else
61 return __gnu_cxx::__int_traits<_Tp>::__max;
62 }
63
64 /// Subtract one integer from another, with saturation in case of overflow.
65 template<typename _Tp> requires __is_standard_integer<_Tp>::value
66 constexpr _Tp
67 sub_sat(_Tp __x, _Tp __y) noexcept
68 {
69 _Tp __z;
70 if (!__builtin_sub_overflow(__x, __y, &__z))
71 return __z;
72 if constexpr (is_unsigned_v<_Tp>)
73 return __gnu_cxx::__int_traits<_Tp>::__min;
74 else if (__x < 0)
75 return __gnu_cxx::__int_traits<_Tp>::__min;
76 else
77 return __gnu_cxx::__int_traits<_Tp>::__max;
78 }
79
80 /// Multiply two integers, with saturation in case of overflow.
81 template<typename _Tp> requires __is_standard_integer<_Tp>::value
82 constexpr _Tp
83 mul_sat(_Tp __x, _Tp __y) noexcept
84 {
85 _Tp __z;
86 if (!__builtin_mul_overflow(__x, __y, &__z))
87 return __z;
88 if constexpr (is_unsigned_v<_Tp>)
89 return __gnu_cxx::__int_traits<_Tp>::__max;
90 else if (__x < 0 != __y < 0)
91 return __gnu_cxx::__int_traits<_Tp>::__min;
92 else
93 return __gnu_cxx::__int_traits<_Tp>::__max;
94 }
95
96 /// Divide one integer by another, with saturation in case of overflow.
97 template<typename _Tp> requires __is_standard_integer<_Tp>::value
98 constexpr _Tp
99 div_sat(_Tp __x, _Tp __y) noexcept
100 {
101 __glibcxx_assert(__y != 0);
102 if constexpr (is_signed_v<_Tp>)
103 if (__x == __gnu_cxx::__int_traits<_Tp>::__min && __y == _Tp(-1))
104 return __gnu_cxx::__int_traits<_Tp>::__max;
105 return __x / __y;
106 }
107
108 /// Divide one integer by another, with saturation in case of overflow.
109 template<typename _Res, typename _Tp>
110 requires __is_standard_integer<_Res>::value
111 && __is_standard_integer<_Tp>::value
112 constexpr _Res
113 saturate_cast(_Tp __x) noexcept
114 {
115 constexpr int __digits_R = __gnu_cxx::__int_traits<_Res>::__digits;
116 constexpr int __digits_T = __gnu_cxx::__int_traits<_Tp>::__digits;
117 constexpr _Res __max_Res = __gnu_cxx::__int_traits<_Res>::__max;
118
119 if constexpr (is_signed_v<_Res> == is_signed_v<_Tp>)
120 {
121 if constexpr (__digits_R < __digits_T)
122 {
123 constexpr _Res __min_Res = __gnu_cxx::__int_traits<_Res>::__min;
124
125 if (__x < static_cast<_Tp>(__min_Res))
126 return __min_Res;
127 else if (__x > static_cast<_Tp>(__max_Res))
128 return __max_Res;
129 }
130 }
131 else if constexpr (is_signed_v<_Tp>) // Res is unsigned
132 {
133 if (__x < 0)
134 return 0;
135 else if (make_unsigned_t<_Tp>(__x) > __max_Res)
136 return __gnu_cxx::__int_traits<_Res>::__max;
137 }
138 else // Tp is unsigned, Res is signed
139 {
140 if (__x > make_unsigned_t<_Res>(__max_Res))
141 return __max_Res;
142 }
143 return static_cast<_Res>(__x);
144 }
145
146_GLIBCXX_END_NAMESPACE_VERSION
147} // namespace
148
149#endif // __glibcxx_saturation_arithmetic
150#endif /* _GLIBCXX_SAT_ARITH_H */
typename make_unsigned< _Tp >::type make_unsigned_t
Alias template for make_unsigned.
Definition type_traits:2202
ISO C++ entities toplevel namespace is std.