1#ifndef BOOST_NUMERIC_SAFE_BASE_HPP
2#define BOOST_NUMERIC_SAFE_BASE_HPP
3
4// Copyright (c) 2012 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#include <limits>
11#include <type_traits> // is_integral, enable_if, conditional is_convertible
12#include <boost/config.hpp> // BOOST_CLANG
13#include "concept/exception_policy.hpp"
14#include "concept/promotion_policy.hpp"
15
16#include "safe_common.hpp"
17#include "exception_policies.hpp"
18
19#include "boost/concept/assert.hpp"
20
21namespace boost {
22namespace safe_numerics {
23
24/////////////////////////////////////////////////////////////////
25// forward declarations to support friend function declarations
26// in safe_base
27
28template<
29 class Stored,
30 Stored Min,
31 Stored Max,
32 class P, // promotion polic
33 class E // exception policy
34>
35class safe_base;
36
37template<
38 class T,
39 T Min,
40 T Max,
41 class P,
42 class E
43>
44struct is_safe<safe_base<T, Min, Max, P, E> > : public std::true_type
45{};
46
47template<
48 class T,
49 T Min,
50 T Max,
51 class P,
52 class E
53>
54struct get_promotion_policy<safe_base<T, Min, Max, P, E> > {
55 using type = P;
56};
57
58template<
59 class T,
60 T Min,
61 T Max,
62 class P,
63 class E
64>
65struct get_exception_policy<safe_base<T, Min, Max, P, E> > {
66 using type = E;
67};
68
69template<
70 class T,
71 T Min,
72 T Max,
73 class P,
74 class E
75>
76struct base_type<safe_base<T, Min, Max, P, E> > {
77 using type = T;
78};
79
80template<
81 class T,
82 T Min,
83 T Max,
84 class P,
85 class E
86>
87constexpr T base_value(
88 const safe_base<T, Min, Max, P, E> & st
89) {
90 return static_cast<T>(st);
91}
92
93template<
94 typename T,
95 T N,
96 class P, // promotion policy
97 class E // exception policy
98>
99class safe_literal_impl;
100
101// works for both GCC and clang
102#if BOOST_CLANG==1
103#pragma GCC diagnostic push
104#pragma GCC diagnostic ignored "-Wmismatched-tags"
105#endif
106
107/////////////////////////////////////////////////////////////////
108// Main implementation
109
110// note in the current version of the library, it is a requirement than type
111// type "Stored" be a scalar type. Problem is when violates this rule, the error message (on clang)
112// is "A non-type template parameter cannot have type ... " where ... is some non-scalar type
113// The example which triggered this investigation is safe<safe<int>> . It was difficult to make
114// the trip from the error message to the source of the problem, hence we're including this
115// comment here.
116template<
117 class Stored,
118 Stored Min,
119 Stored Max,
120 class P, // promotion polic
121 class E // exception policy
122>
123class safe_base {
124private:
125 BOOST_CONCEPT_ASSERT((PromotionPolicy<P>));
126 BOOST_CONCEPT_ASSERT((ExceptionPolicy<E>));
127 Stored m_t;
128
129 template<class T>
130 constexpr Stored validated_cast(const T & t) const;
131
132 // stream support
133
134 template<class CharT, class Traits>
135 void output(std::basic_ostream<CharT, Traits> & os) const;
136
137 // note usage of friend declaration to mark function as
138 // a global function rather than a member function. If
139 // this is not done, the compiler will confuse this with
140 // a member operator overload on the << operator. Weird
141 // I know. But it's documented here
142 // http://en.cppreference.com/w/cpp/language/friend
143 // under the heading "Template friend operators"
144 template<class CharT, class Traits>
145 friend std::basic_ostream<CharT, Traits> &
146 operator<<(
147 std::basic_ostream<CharT, Traits> & os,
148 const safe_base & t
149 ){
150 t.output(os);
151 return os;
152 }
153
154 template<class CharT, class Traits>
155 void input(std::basic_istream<CharT, Traits> & is);
156
157 // see above
158 template<class CharT, class Traits>
159 friend inline std::basic_istream<CharT, Traits> &
160 operator>>(
161 std::basic_istream<CharT, Traits> & is,
162 safe_base & t
163 ){
164 t.input(is);
165 return is;
166 }
167
168public:
169 ////////////////////////////////////////////////////////////
170 // constructors
171
172 constexpr safe_base();
173
174 struct skip_validation{};
175
176 constexpr explicit safe_base(const Stored & rhs, skip_validation);
177
178 // construct an instance of a safe type from an instance of a convertible underlying type.
179 template<
180 class T,
181 typename std::enable_if<
182 std::is_convertible<T, Stored>::value,
183 bool
184 >::type = 0
185 >
186 constexpr /*explicit*/ safe_base(const T & t);
187
188 // construct an instance of a safe type from a literal value
189 template<typename T, T N, class Px, class Ex>
190 constexpr /*explicit*/ safe_base(const safe_literal_impl<T, N, Px, Ex> & t);
191
192 // note: Rule of Five. Supply all or none of the following
193 // a) user-defined destructor
194 ~safe_base() = default;
195 // b) copy-constructor
196 constexpr safe_base(const safe_base &) = default;
197 // c) copy-assignment
198 constexpr safe_base & operator=(const safe_base &) = default;
199 // d) move constructor
200 constexpr safe_base(safe_base &&) = default;
201 // e) move assignment operator
202 constexpr safe_base & operator=(safe_base &&) = default;
203
204 /////////////////////////////////////////////////////////////////
205 // casting operators for intrinsic integers
206 // convert to any type which is not safe. safe types need to be
207 // excluded to prevent ambiguous function selection which
208 // would otherwise occur. validity of safe types is checked in
209 // the constructor of safe types
210 template<
211 class R,
212 typename std::enable_if<
213 ! boost::safe_numerics::is_safe<R>::value,
214 int
215 >::type = 0
216 >
217 constexpr /*explicit*/ operator R () const;
218
219 /////////////////////////////////////////////////////////////////
220 // modification binary operators
221 template<class T>
222 constexpr safe_base &
223 operator=(const T & rhs){
224 m_t = validated_cast(rhs);
225 return *this;
226 }
227
228 // mutating unary operators
229 constexpr safe_base & operator++(){ // pre increment
230 return *this = *this + 1;
231 }
232 constexpr safe_base & operator--(){ // pre decrement
233 return *this = *this - 1;
234 }
235 constexpr safe_base operator++(int){ // post increment
236 safe_base old_t = *this;
237 ++(*this);
238 return old_t;
239 }
240 constexpr safe_base operator--(int){ // post decrement
241 safe_base old_t = *this;
242 --(*this);
243 return old_t;
244 }
245 // non mutating unary operators
246 constexpr auto operator+() const { // unary plus
247 return *this;
248 }
249 // after much consideration, I've permited the resulting value of a unary
250 // - to change the type. The C++ standard does invoke integral promotions
251 // so it's changing the type as well.
252
253 /* section 5.3.1 &8 of the C++ standard
254 The operand of the unary - operator shall have arithmetic or unscoped
255 enumeration type and the result is the negation of its operand. Integral
256 promotion is performed on integral or enumeration operands. The negative
257 of an unsigned quantity is computed by subtracting its value from 2n,
258 where n is the number of bits in the promoted operand. The type of the
259 result is the type of the promoted operand.
260 */
261 constexpr auto operator-() const { // unary minus
262 // if this is a unsigned type and the promotion policy is native
263 // the result will be unsigned. But then the operation will fail
264 // according to the requirements of arithmetic correctness.
265 // if this is an unsigned type and the promotion policy is automatic.
266 // the result will be signed.
267 return 0 - *this;
268 }
269 /* section 5.3.1 &10 of the C++ standard
270 The operand of ~ shall have integral or unscoped enumeration type;
271 the result is the ones’ complement of its operand. Integral promotions
272 are performed. The type of the result is the type of the promoted operand.
273 */
274 constexpr auto operator~() const { // complement
275 return ~Stored(0u) ^ *this;
276 }
277};
278
279} // safe_numerics
280} // boost
281
282/////////////////////////////////////////////////////////////////
283// numeric limits for safe<int> etc.
284
285#include <limits>
286
287namespace std {
288
289template<
290 class T,
291 T Min,
292 T Max,
293 class P,
294 class E
295>
296class numeric_limits<boost::safe_numerics::safe_base<T, Min, Max, P, E> >
297 : public std::numeric_limits<T>
298{
299 using SB = boost::safe_numerics::safe_base<T, Min, Max, P, E>;
300public:
301 constexpr static SB lowest() noexcept {
302 return SB(Min, typename SB::skip_validation());
303 }
304 constexpr static SB min() noexcept {
305 return SB(Min, typename SB::skip_validation());
306 }
307 constexpr static SB max() noexcept {
308 return SB(Max, typename SB::skip_validation());
309 }
310};
311
312} // std
313
314#if BOOST_CLANG==1
315#pragma GCC diagnostic pop
316#endif
317
318#endif // BOOST_NUMERIC_SAFE_BASE_HPP
319

source code of boost/libs/safe_numerics/include/boost/safe_numerics/safe_base.hpp