1 #ifndef BOOST_NUMERIC_CHECKED_DEFAULT_HPP
2 #define BOOST_NUMERIC_CHECKED_DEFAULT_HPP
3
4 // Copyright (c) 2017 Robert Ramey
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9
10 // contains operation implementation of arithmetic operators
11 // on built-in types. The default implementation is to just
12 // invoke the operation with no checking. These are overloaded
13 // for specific types such as integer, etc.
14
15 // implement the equivant of template partial specialization for functions
16
17 // what we need is
18 // a) a default implementation of add, subtract, etc which just
19 // implements the standard operations and returns the result
20 // b) specific implementations to be called from safe implementation
21 // such as safe<int> ... and someday maybe money<T, D> ...
22 //
23 // What we need is partial function specialization - but this doesn't
24 // exist in C++ (yet?). But particial specialization of structures DOES
25 // exist. So put our functions into a class which can then be
26 // partially specialized. Finally. add a function interface to so that
27 // data types can be deduced from the function call. We now have
28 // the equivalent of partial function template specialization.
29
30 // usage example: checked<int>::add(t, u) ...
31
32 #include <boost/logic/tribool.hpp>
33 #include "checked_result.hpp"
34
35 namespace boost {
36 namespace safe_numerics {
37
38 // main function object which contains functions which handle
39 // primitives which haven't been overriden. For now, these
40 // implement the default operation. But I see this as an indicator
41 // that there is more work to be done. For example float * int should
42 // never be called because promotions on operands should occur before
43 // the operation is invoked. So rather than returning the default operation
44 // it should trap with a static_assert. This occurs at compile time while
45 // calculating result interval. This needs more investigation.
46
47 template<
48 typename R,
49 R Min,
50 R Max,
51 typename T,
52 class F = make_checked_result<R>,
53 class Default = void
54 >
55 struct heterogeneous_checked_operation {
56 constexpr static checked_result<R>
castboost::safe_numerics::heterogeneous_checked_operation57 cast(const T & t) /* noexcept */ {
58 return static_cast<R>(t);
59 }
60 };
61
62 template<
63 typename R,
64 class F = make_checked_result<R>,
65 class Default = void
66 >
67 struct checked_operation{
68 constexpr static checked_result<R>
minusboost::safe_numerics::checked_operation69 minus(const R & t) noexcept {
70 return - t;
71 }
72 constexpr static checked_result<R>
addboost::safe_numerics::checked_operation73 add(const R & t, const R & u) noexcept {
74 return t + u;
75 }
76 constexpr static checked_result<R>
subtractboost::safe_numerics::checked_operation77 subtract(const R & t, const R & u) noexcept {
78 return t - u;
79 }
80 constexpr static checked_result<R>
multiplyboost::safe_numerics::checked_operation81 multiply(const R & t, const R & u) noexcept {
82 return t * u;
83 }
84 constexpr static checked_result<R>
divideboost::safe_numerics::checked_operation85 divide(const R & t, const R & u) noexcept {
86 return t / u;
87 }
88 constexpr static checked_result<R>
modulusboost::safe_numerics::checked_operation89 modulus(const R & t, const R & u) noexcept {
90 return t % u;
91 }
92 constexpr static boost::logic::tribool
less_thanboost::safe_numerics::checked_operation93 less_than(const R & t, const R & u) noexcept {
94 return t < u;
95 }
96 constexpr static boost::logic::tribool
greater_thanboost::safe_numerics::checked_operation97 greater_than(const R & t, const R & u) noexcept {
98 return t > u;
99 }
100 constexpr static boost::logic::tribool
equalboost::safe_numerics::checked_operation101 equal(const R & t, const R & u) noexcept {
102 return t < u;
103 }
104 constexpr static checked_result<R>
left_shiftboost::safe_numerics::checked_operation105 left_shift(const R & t, const R & u) noexcept {
106 return t << u;
107 }
108 constexpr static checked_result<R>
right_shiftboost::safe_numerics::checked_operation109 right_shift(const R & t, const R & u) noexcept {
110 return t >> u;
111 }
112 constexpr static checked_result<R>
bitwise_orboost::safe_numerics::checked_operation113 bitwise_or(const R & t, const R & u) noexcept {
114 return t | u;
115 }
116 constexpr static checked_result<R>
bitwise_xorboost::safe_numerics::checked_operation117 bitwise_xor(const R & t, const R & u) noexcept {
118 return t ^ u;
119 }
120 constexpr static checked_result<R>
bitwise_andboost::safe_numerics::checked_operation121 bitwise_and(const R & t, const R & u) noexcept {
122 return t & u;
123 }
124 constexpr static checked_result<R>
bitwise_notboost::safe_numerics::checked_operation125 bitwise_not(const R & t) noexcept {
126 return ~t;
127 }
128 };
129
130 namespace checked {
131
132 // implement function call interface so that types other than
133 // the result type R can be deduced from the function parameters.
134
135 template<typename R, typename T>
cast(const T & t)136 constexpr checked_result<R> cast(const T & t) /* noexcept */ {
137 return heterogeneous_checked_operation<
138 R,
139 std::numeric_limits<R>::min(),
140 std::numeric_limits<R>::max(),
141 T
142 >::cast(t);
143 }
144 template<typename R>
minus(const R & t)145 constexpr checked_result<R> minus(const R & t) noexcept {
146 return checked_operation<R>::minus(t);
147 }
148 template<typename R>
add(const R & t,const R & u)149 constexpr checked_result<R> add(const R & t, const R & u) noexcept {
150 return checked_operation<R>::add(t, u);
151 }
152 template<typename R>
subtract(const R & t,const R & u)153 constexpr checked_result<R> subtract(const R & t, const R & u) noexcept {
154 return checked_operation<R>::subtract(t, u);
155 }
156 template<typename R>
multiply(const R & t,const R & u)157 constexpr checked_result<R> multiply(const R & t, const R & u) noexcept {
158 return checked_operation<R>::multiply(t, u);
159 }
160 template<typename R>
divide(const R & t,const R & u)161 constexpr checked_result<R> divide(const R & t, const R & u) noexcept {
162 return checked_operation<R>::divide(t, u);
163 }
164 template<typename R>
modulus(const R & t,const R & u)165 constexpr checked_result<R> modulus(const R & t, const R & u) noexcept {
166 return checked_operation<R>::modulus(t, u);
167 }
168 template<typename R>
less_than(const R & t,const R & u)169 constexpr checked_result<bool> less_than(const R & t, const R & u) noexcept {
170 return checked_operation<R>::less_than(t, u);
171 }
172 template<typename R>
greater_than_equal(const R & t,const R & u)173 constexpr checked_result<bool> greater_than_equal(const R & t, const R & u) noexcept {
174 return ! checked_operation<R>::less_than(t, u);
175 }
176 template<typename R>
greater_than(const R & t,const R & u)177 constexpr checked_result<bool> greater_than(const R & t, const R & u) noexcept {
178 return checked_operation<R>::greater_than(t, u);
179 }
180 template<typename R>
less_than_equal(const R & t,const R & u)181 constexpr checked_result<bool> less_than_equal(const R & t, const R & u) noexcept {
182 return ! checked_operation<R>::greater_than(t, u);
183 }
184 template<typename R>
equal(const R & t,const R & u)185 constexpr checked_result<bool> equal(const R & t, const R & u) noexcept {
186 return checked_operation<R>::equal(t, u);
187 }
188 template<typename R>
left_shift(const R & t,const R & u)189 constexpr checked_result<R> left_shift(const R & t, const R & u) noexcept {
190 return checked_operation<R>::left_shift(t, u);
191 }
192 template<typename R>
right_shift(const R & t,const R & u)193 constexpr checked_result<R> right_shift(const R & t, const R & u) noexcept {
194 return checked_operation<R>::right_shift(t, u);
195 }
196 template<typename R>
bitwise_or(const R & t,const R & u)197 constexpr checked_result<R> bitwise_or(const R & t, const R & u) noexcept {
198 return checked_operation<R>::bitwise_or(t, u);
199 }
200 template<typename R>
bitwise_xor(const R & t,const R & u)201 constexpr checked_result<R> bitwise_xor(const R & t, const R & u) noexcept {
202 return checked_operation<R>::bitwise_xor(t, u);
203 }
204 template<typename R>
bitwise_and(const R & t,const R & u)205 constexpr checked_result<R> bitwise_and(const R & t, const R & u) noexcept {
206 return checked_operation<R>::bitwise_and(t, u);
207 }
208 template<typename R>
bitwise_not(const R & t)209 constexpr checked_result<R> bitwise_not(const R & t) noexcept {
210 return checked_operation<R>::bitwise_not(t);
211 }
212
213 } // checked
214 } // safe_numerics
215 } // boost
216
217 #endif // BOOST_NUMERIC_CHECKED_DEFAULT_HPP
218