1
2// Copyright 2012 John Maddock. Distributed under the Boost
3// Software License, Version 1.0. (See accompanying file
4// LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
5
6#ifndef BOOST_MP_CPP_INT_CHECKED_HPP
7#define BOOST_MP_CPP_INT_CHECKED_HPP
8
9#include <climits>
10#include <limits>
11#include <type_traits>
12#include <stdexcept>
13#include <string>
14#include <boost/multiprecision/detail/standalone_config.hpp>
15#include <boost/multiprecision/detail/no_exceptions_support.hpp>
16
17namespace boost { namespace multiprecision { namespace backends { namespace detail {
18
19//
20// Simple routines for performing checked arithmetic with a builtin arithmetic type.
21// Note that this is not a complete header, it must be included as part of boost/multiprecision/cpp_int.hpp.
22//
23
24template <typename T>
25inline constexpr T type_max() noexcept
26{
27 return
28 #ifdef BOOST_HAS_INT128
29 std::is_same<T, boost::multiprecision::int128_type>::value ? INT128_MAX :
30 std::is_same<T, boost::multiprecision::uint128_type>::value ? UINT128_MAX :
31 #endif
32 (std::numeric_limits<T>::max)();
33}
34
35template <typename T>
36inline constexpr T type_min() noexcept
37{
38 return
39 #ifdef BOOST_HAS_INT128
40 std::is_same<T, boost::multiprecision::int128_type>::value ? INT128_MIN :
41 std::is_same<T, boost::multiprecision::uint128_type>::value ? T(0) :
42 #endif
43 (std::numeric_limits<T>::min)();
44}
45
46inline void raise_overflow(std::string op)
47{
48 BOOST_MP_THROW_EXCEPTION(std::overflow_error("overflow in " + op));
49}
50inline void raise_add_overflow()
51{
52 raise_overflow(op: "addition");
53}
54inline void raise_subtract_overflow()
55{
56 BOOST_MP_THROW_EXCEPTION(std::range_error("Subtraction resulted in a negative value, but the type is unsigned"));
57}
58inline void raise_mul_overflow()
59{
60 raise_overflow(op: "multiplication");
61}
62inline void raise_div_overflow()
63{
64 raise_overflow(op: "division");
65}
66
67template <class A>
68inline BOOST_MP_CXX14_CONSTEXPR A checked_add_imp(A a, A b, const std::integral_constant<bool, true>&)
69{
70 if (a > 0)
71 {
72 if ((b > 0) && ((type_max<A>() - b) < a))
73 raise_add_overflow();
74 }
75 else
76 {
77 if ((b < 0) && ((type_min<A>() - b) > a))
78 raise_add_overflow();
79 }
80 return a + b;
81}
82template <class A>
83inline BOOST_MP_CXX14_CONSTEXPR A checked_add_imp(A a, A b, const std::integral_constant<bool, false>&)
84{
85 if ((type_max<A>() - b) < a)
86 raise_add_overflow();
87 return a + b;
88}
89template <class A>
90inline BOOST_MP_CXX14_CONSTEXPR A checked_add(A a, A b, const std::integral_constant<int, checked>&)
91{
92 return checked_add_imp(a, b, std::integral_constant<bool, boost::multiprecision::detail::is_signed<A>::value && boost::multiprecision::detail::is_integral<A>::value > ());
93}
94template <class A>
95inline BOOST_MP_CXX14_CONSTEXPR A checked_add(A a, A b, const std::integral_constant<int, unchecked>&)
96{
97 return a + b;
98}
99
100template <class A>
101inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract_imp(A a, A b, const std::integral_constant<bool, true>&)
102{
103 if (a > 0)
104 {
105 if ((b < 0) && ((type_max<A>() + b) < a))
106 raise_subtract_overflow();
107 }
108 else
109 {
110 if ((b > 0) && ((type_min<A>() + b) > a))
111 raise_subtract_overflow();
112 }
113 return a - b;
114}
115template <class A>
116inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract_imp(A a, A b, const std::integral_constant<bool, false>&)
117{
118 if (a < b)
119 raise_subtract_overflow();
120 return a - b;
121}
122template <class A>
123inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract(A a, A b, const std::integral_constant<int, checked>&)
124{
125 return checked_subtract_imp(a, b, std::integral_constant<bool, boost::multiprecision::detail::is_signed<A>::value && boost::multiprecision::detail::is_integral<A>::value>());
126}
127template <class A>
128inline BOOST_MP_CXX14_CONSTEXPR A checked_subtract(A a, A b, const std::integral_constant<int, unchecked>&)
129{
130 return a - b;
131}
132
133template <class A>
134inline BOOST_MP_CXX14_CONSTEXPR A checked_multiply(A a, A b, const std::integral_constant<int, checked>&)
135{
136 BOOST_MP_USING_ABS
137 if (a && (type_max<A>() / abs(a) < abs(b)))
138 raise_mul_overflow();
139 return a * b;
140}
141template <class A>
142inline BOOST_MP_CXX14_CONSTEXPR A checked_multiply(A a, A b, const std::integral_constant<int, unchecked>&)
143{
144 return a * b;
145}
146
147template <class A>
148inline BOOST_MP_CXX14_CONSTEXPR A checked_divide(A a, A b, const std::integral_constant<int, checked>&)
149{
150 if (b == 0)
151 raise_div_overflow();
152 return a / b;
153}
154template <class A>
155inline BOOST_MP_CXX14_CONSTEXPR A checked_divide(A a, A b, const std::integral_constant<int, unchecked>&)
156{
157 return a / b;
158}
159
160template <class A>
161inline BOOST_MP_CXX14_CONSTEXPR A checked_left_shift(A a, unsigned long long shift, const std::integral_constant<int, checked>&)
162{
163 if (a && shift)
164 {
165 if ((shift > sizeof(A) * CHAR_BIT) || (a >> (sizeof(A) * CHAR_BIT - shift)))
166 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Shift out of range"));
167 }
168 return a << shift;
169}
170template <class A>
171inline BOOST_MP_CXX14_CONSTEXPR A checked_left_shift(A a, unsigned long long shift, const std::integral_constant<int, unchecked>&)
172{
173 return (shift >= sizeof(A) * CHAR_BIT) ? 0 : a << shift;
174}
175
176}}}} // namespace boost::multiprecision::backends::detail
177
178#endif
179

source code of boost/libs/multiprecision/include/boost/multiprecision/cpp_int/checked.hpp