• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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