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