summaryrefslogtreecommitdiff
path: root/boost/safe_numerics/checked_default.hpp
blob: 07699c4fcac575d3819e6ffe1afb118371a2dcc7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#ifndef BOOST_NUMERIC_CHECKED_DEFAULT_HPP
#define BOOST_NUMERIC_CHECKED_DEFAULT_HPP

//  Copyright (c) 2017 Robert Ramey
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// contains operation implementation of arithmetic operators
// on built-in types.  The default implementation is to just
// invoke the operation with no checking.  These are overloaded
// for specific types such as integer, etc.

// implement the equivant of template partial specialization for functions

// what we need is
// a) a default implementation of add, subtract, etc which just
// implements the standard operations and returns the result
// b) specific implementations to be called from safe implementation
// such as safe<int> ... and someday maybe money<T, D> ...
//
// What we need is partial function specialization - but this doesn't
// exist in C++ (yet?).  But particial specialization of structures DOES
// exist.  So put our functions into a class which can then be
// partially specialized.  Finally. add a function interface to so that
// data types can be deduced from the function call.  We now have
// the equivalent of partial function template specialization.

// usage example: checked<int>::add(t, u) ...

#include <boost/logic/tribool.hpp>
#include "checked_result.hpp"

namespace boost {
namespace safe_numerics {

// main function object which contains functions which handle
// primitives which haven't been overriden.  For now, these
// implement the default operation.  But I see this as an indicator
// that there is more work to be done.  For example float * int should
// never be called because promotions on operands should occur before
// the operation is invoked. So rather than returning the default operation
// it should trap with a static_assert. This occurs at compile time while
// calculating result interval.  This needs more investigation.

template<
    typename R,
    typename T,
    class F = make_checked_result<R>,
    class Default = void
>
struct heterogeneous_checked_operation {
    constexpr static checked_result<R>
    cast(const T & t) /* noexcept */ {
        return static_cast<R>(t);
    }
};

template<
    typename R,
    class F = make_checked_result<R>,
    class Default = void
>
struct checked_operation{
    constexpr static checked_result<R>
    minus(const R & t) noexcept {
        return - t;
    }
    constexpr static checked_result<R>
    add(const R & t, const R & u) noexcept {
        return t + u;
    }
    constexpr static checked_result<R>
    subtract(const R & t, const R & u) noexcept {
        return t - u;
    }
    constexpr static checked_result<R>
    multiply(const R & t, const R & u) noexcept {
        return t * u;
    }
    constexpr static checked_result<R>
    divide(const R & t, const R & u) noexcept {
        return t / u;
    }
    constexpr static checked_result<R>
    modulus(const R & t, const R & u) noexcept {
        return t % u;
    }
    constexpr static boost::logic::tribool
    less_than(const R & t, const R & u) noexcept {
        return t < u;
    }
    constexpr static boost::logic::tribool
    greater_than(const R & t, const R & u) noexcept {
        return t > u;
    }
    constexpr static boost::logic::tribool
    equal(const R & t, const R & u) noexcept {
        return t < u;
    }
    constexpr static checked_result<R>
    left_shift(const R & t, const R & u) noexcept {
        return t << u;
    }
    constexpr static checked_result<R>
    right_shift(const R & t, const R & u) noexcept {
        return t >> u;
    }
    constexpr static checked_result<R>
    bitwise_or(const R & t, const R & u) noexcept {
        return t | u;
    }
    constexpr static checked_result<R>
    bitwise_xor(const R & t, const R & u) noexcept {
        return t ^ u;
    }
    constexpr static checked_result<R>
    bitwise_and(const R & t, const R & u) noexcept {
        return t & u;
    }
    constexpr static checked_result<R>
    bitwise_not(const R & t) noexcept {
        return ~t;
    }
};

namespace checked {

// implement function call interface so that types other than
// the result type R can be deduced from the function parameters.

template<typename R, typename T>
constexpr checked_result<R> cast(const T & t) /* noexcept */ {
    return heterogeneous_checked_operation<R, T>::cast(t);
}
template<typename R>
constexpr checked_result<R> minus(const R & t) noexcept {
    return checked_operation<R>::minus(t);
}
template<typename R>
constexpr checked_result<R> add(const R & t, const R & u) noexcept {
    return checked_operation<R>::add(t, u);
}
template<typename R>
constexpr checked_result<R> subtract(const R & t, const R & u) noexcept {
    return checked_operation<R>::subtract(t, u);
}
template<typename R>
constexpr checked_result<R> multiply(const R & t, const R & u) noexcept {
    return checked_operation<R>::multiply(t, u);
}
template<typename R>
constexpr checked_result<R> divide(const R & t, const R & u) noexcept {
    return checked_operation<R>::divide(t, u);
}
template<typename R>
constexpr checked_result<R> modulus(const R & t, const R & u) noexcept {
    return checked_operation<R>::modulus(t, u);
}
template<typename R>
constexpr checked_result<bool> less_than(const R & t, const R & u) noexcept {
    return checked_operation<R>::less_than(t, u);
}
template<typename R>
constexpr checked_result<bool> greater_than_equal(const R & t, const R & u) noexcept {
    return ! checked_operation<R>::less_than(t, u);
}
template<typename R>
constexpr checked_result<bool> greater_than(const R & t, const R & u) noexcept {
    return checked_operation<R>::greater_than(t, u);
}
template<typename R>
constexpr checked_result<bool> less_than_equal(const R & t, const R & u) noexcept {
    return ! checked_operation<R>::greater_than(t, u);
}
template<typename R>
constexpr checked_result<bool> equal(const R & t, const R & u) noexcept {
    return checked_operation<R>::equal(t, u);
}
template<typename R>
constexpr checked_result<R> left_shift(const R & t, const R & u) noexcept {
    return checked_operation<R>::left_shift(t, u);
}
template<typename R>
constexpr checked_result<R> right_shift(const R & t, const R & u) noexcept {
    return checked_operation<R>::right_shift(t, u);
}
template<typename R>
constexpr checked_result<R> bitwise_or(const R & t, const R & u) noexcept {
    return checked_operation<R>::bitwise_or(t, u);
}
template<typename R>
constexpr checked_result<R> bitwise_xor(const R & t, const R & u) noexcept {
    return checked_operation<R>::bitwise_xor(t, u);
}
template<typename R>
constexpr checked_result<R> bitwise_and(const R & t, const R & u) noexcept {
    return checked_operation<R>::bitwise_and(t, u);
}
template<typename R>
constexpr checked_result<R> bitwise_not(const R & t) noexcept {
    return checked_operation<R>::bitwise_not(t);
}

} // checked
} // safe_numerics
} // boost

#endif // BOOST_NUMERIC_CHECKED_DEFAULT_HPP