]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/safe_numerics/safe_base_operations.hpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / boost / safe_numerics / safe_base_operations.hpp
1 #ifndef BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
2 #define BOOST_NUMERIC_SAFE_BASE_OPERATIONS_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_base_of, is_same, is_floating_point, conditional
12 #include <algorithm> // max
13 #include <cassert>
14
15 #include <boost/config.hpp>
16
17 #include <boost/core/enable_if.hpp> // lazy_enable_if
18 #include <boost/integer.hpp>
19 #include <boost/logic/tribool.hpp>
20
21 #include "checked_integer.hpp"
22 #include "checked_result.hpp"
23 #include "safe_base.hpp"
24
25 #include "interval.hpp"
26 #include "utility.hpp"
27
28 namespace boost {
29 namespace safe_numerics {
30
31 /////////////////////////////////////////////////////////////////
32 // validation
33
34 template<typename R, R Min, R Max, typename E>
35 struct validate_detail {
36 using r_type = checked_result<R>;
37
38 struct exception_possible {
39 template<typename T>
40 constexpr static R return_value(
41 const T & t
42 ){
43 // INT08-C
44 const r_type rx = heterogeneous_checked_operation<
45 R,
46 Min,
47 Max,
48 typename base_type<T>::type,
49 dispatch_and_return<E, R>
50 >::cast(t);
51
52 return rx;
53 }
54 };
55 struct exception_not_possible {
56 template<typename T>
57 constexpr static R return_value(
58 const T & t
59 ){
60 return static_cast<R>(base_value(t));
61 }
62 };
63
64 template<typename T>
65 constexpr static R return_value(const T & t){
66
67 constexpr const interval<r_type> t_interval{
68 checked::cast<R>(base_value(std::numeric_limits<T>::min())),
69 checked::cast<R>(base_value(std::numeric_limits<T>::max()))
70 };
71 constexpr const interval<r_type> r_interval{r_type(Min), r_type(Max)};
72
73 static_assert(
74 true != static_cast<bool>(r_interval.excludes(t_interval)),
75 "can't cast from ranges that don't overlap"
76 );
77
78 return std::conditional<
79 static_cast<bool>(r_interval.includes(t_interval)),
80 exception_not_possible,
81 exception_possible
82 >::type::return_value(t);
83 }
84 };
85
86 template<class Stored, Stored Min, Stored Max, class P, class E>
87 template<class T>
88 constexpr Stored safe_base<Stored, Min, Max, P, E>::
89 validated_cast(const T & t) const {
90 return validate_detail<Stored,Min,Max,E>::return_value(t);
91 }
92
93 template<class Stored, Stored Min, Stored Max, class P, class E>
94 template<typename T, T N, class P1, class E1>
95 constexpr Stored safe_base<Stored, Min, Max, P, E>::
96 validated_cast(const safe_literal_impl<T, N, P1, E1> &) const {
97 constexpr const interval<Stored> this_interval{};
98 // if static values don't overlap, the program can never function
99 static_assert(
100 this_interval.includes(N),
101 "safe type cannot be constructed from this value"
102 );
103 return static_cast<Stored>(N);
104 }
105
106 /////////////////////////////////////////////////////////////////
107 // constructors
108
109 template<class Stored, Stored Min, Stored Max, class P, class E>
110 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
111 const Stored & rhs,
112 skip_validation
113 ) :
114 m_t(rhs)
115 {}
116
117 template<class Stored, Stored Min, Stored Max, class P, class E>
118 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(){
119 dispatch<E, safe_numerics_error::uninitialized_value>(
120 "safe values must be initialized"
121 );
122 }
123
124 // construct an instance of a safe type
125 // from an instance of a convertible underlying type.
126 template<class Stored, Stored Min, Stored Max, class P, class E>
127 template<class T>
128 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
129 const T & t,
130 typename std::enable_if<
131 is_safe<T>::value,
132 bool
133 >::type
134 ) :
135 m_t(validated_cast(t))
136 {}
137
138 template<class Stored, Stored Min, Stored Max, class P, class E>
139 template<class T>
140 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
141 const T & t,
142 typename std::enable_if<
143 std::is_integral<T>::value,
144 bool
145 >::type
146 ) :
147 m_t(validated_cast(t))
148 {}
149
150 template<class Stored, Stored Min, Stored Max, class P, class E>
151 template<class T, T value>
152 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
153
154 const std::integral_constant<T, value> &
155 ) :
156 m_t(validated_cast(value))
157 {}
158
159 /////////////////////////////////////////////////////////////////
160 // casting operators
161
162 // cast to a builtin type from a safe type
163 template< class Stored, Stored Min, Stored Max, class P, class E>
164 template<
165 class R,
166 typename std::enable_if<
167 ! boost::safe_numerics::is_safe<R>::value,
168 int
169 >::type
170 >
171 constexpr safe_base<Stored, Min, Max, P, E>::
172 operator R () const {
173 // if static values don't overlap, the program can never function
174 #if 1
175 constexpr const interval<R> r_interval;
176 constexpr const interval<Stored> this_interval(Min, Max);
177 static_assert(
178 ! r_interval.excludes(this_interval),
179 "safe type cannot be constructed with this type"
180 );
181 #endif
182
183 return validate_detail<
184 R,
185 std::numeric_limits<R>::min(),
186 std::numeric_limits<R>::max(),
187 E
188 >::return_value(*this);
189 }
190
191 // cast to the underlying builtin type from a safe type
192 template<class Stored, Stored Min, Stored Max, class P, class E>
193 constexpr safe_base<Stored, Min, Max, P, E>::
194 operator Stored () const {
195 return m_t;
196 }
197
198 /////////////////////////////////////////////////////////////////
199 // binary operators
200
201 template<class T, class U>
202 struct common_exception_policy {
203 static_assert(is_safe<T>::value || is_safe<U>::value,
204 "at least one type must be a safe type"
205 );
206
207 using t_exception_policy = typename get_exception_policy<T>::type;
208 using u_exception_policy = typename get_exception_policy<U>::type;
209
210 static_assert(
211 std::is_same<t_exception_policy, u_exception_policy>::value
212 || std::is_same<t_exception_policy, void>::value
213 || std::is_same<void, u_exception_policy>::value,
214 "if the exception policies are different, one must be void!"
215 );
216
217 static_assert(
218 ! (std::is_same<t_exception_policy, void>::value
219 && std::is_same<void, u_exception_policy>::value),
220 "at least one exception policy must not be void"
221 );
222
223 using type =
224 typename std::conditional<
225 !std::is_same<void, u_exception_policy>::value,
226 u_exception_policy,
227 typename std::conditional<
228 !std::is_same<void, t_exception_policy>::value,
229 t_exception_policy,
230 //
231 void
232 >::type >::type;
233
234 static_assert(
235 !std::is_same<void, type>::value,
236 "exception_policy is void"
237 );
238 };
239
240 template<class T, class U>
241 struct common_promotion_policy {
242 static_assert(is_safe<T>::value || is_safe<U>::value,
243 "at least one type must be a safe type"
244 );
245 using t_promotion_policy = typename get_promotion_policy<T>::type;
246 using u_promotion_policy = typename get_promotion_policy<U>::type;
247 static_assert(
248 std::is_same<t_promotion_policy, u_promotion_policy>::value
249 ||std::is_same<t_promotion_policy, void>::value
250 ||std::is_same<void, u_promotion_policy>::value,
251 "if the promotion policies are different, one must be void!"
252 );
253 static_assert(
254 ! (std::is_same<t_promotion_policy, void>::value
255 && std::is_same<void, u_promotion_policy>::value),
256 "at least one promotion policy must not be void"
257 );
258
259 using type =
260 typename std::conditional<
261 ! std::is_same<void, u_promotion_policy>::value,
262 u_promotion_policy,
263 typename std::conditional<
264 ! std::is_same<void, t_promotion_policy>::value,
265 t_promotion_policy,
266 //
267 void
268 >::type >::type;
269
270 static_assert(
271 ! std::is_same<void, type>::value,
272 "promotion_policy is void"
273 );
274
275 };
276
277 // give the resultant base type, figure out what the final result
278 // type will be. Note we currently need this because we support
279 // return of only safe integer types. Someday ..., we'll support
280 // all other safe types including float and user defined ones.
281
282 // helper - cast arguments to binary operators to a specified
283 // result type
284
285 template<class EP, class R, class T, class U>
286 std::pair<R, R>
287 constexpr static casting_helper(const T & t, const U & u){
288 using r_type = checked_result<R>;
289 const r_type tx = heterogeneous_checked_operation<
290 R,
291 std::numeric_limits<R>::min(),
292 std::numeric_limits<R>::max(),
293 typename base_type<T>::type,
294 dispatch_and_return<EP, R>
295 >::cast(base_value(t));
296 const R tr = tx.exception()
297 ? static_cast<R>(t)
298 : tx.m_r;
299
300 const r_type ux = heterogeneous_checked_operation<
301 R,
302 std::numeric_limits<R>::min(),
303 std::numeric_limits<R>::max(),
304 typename base_type<U>::type,
305 dispatch_and_return<EP, R>
306 >::cast(base_value(u));
307 const R ur = ux.exception()
308 ? static_cast<R>(u)
309 : ux.m_r;
310 return std::pair<R, R>(tr, ur);
311 }
312
313 // Note: the following global operators will be found via
314 // argument dependent lookup.
315
316 /////////////////////////////////////////////////////////////////
317 // addition
318
319 template<class T, class U>
320 struct addition_result {
321 private:
322 using promotion_policy = typename common_promotion_policy<T, U>::type;
323 using result_base_type =
324 typename promotion_policy::template addition_result<T,U>::type;
325
326 // if exception not possible
327 constexpr static result_base_type
328 return_value(const T & t, const U & u, std::false_type){
329 return
330 static_cast<result_base_type>(base_value(t))
331 + static_cast<result_base_type>(base_value(u));
332 }
333
334 // if exception possible
335 using exception_policy = typename common_exception_policy<T, U>::type;
336
337 using r_type = checked_result<result_base_type>;
338
339 constexpr static result_base_type
340 return_value(const T & t, const U & u, std::true_type){
341 const std::pair<result_base_type, result_base_type> r = casting_helper<
342 exception_policy,
343 result_base_type
344 >(t, u);
345
346 const r_type rx = checked_operation<
347 result_base_type,
348 dispatch_and_return<exception_policy, result_base_type>
349 >::add(r.first, r.second);
350
351 return
352 rx.exception()
353 ? r.first + r.second
354 : rx.m_r;
355 }
356
357 using r_type_interval_t = interval<r_type>;
358
359 constexpr static const r_type_interval_t get_r_type_interval(){
360 constexpr const r_type_interval_t t_interval{
361 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
362 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
363 };
364 constexpr const r_type_interval_t u_interval{
365 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
366 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
367 };
368 return t_interval + u_interval;
369 }
370 constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
371
372 constexpr static const interval<result_base_type> return_interval{
373 r_type_interval.l.exception()
374 ? std::numeric_limits<result_base_type>::min()
375 : static_cast<result_base_type>(r_type_interval.l),
376 r_type_interval.u.exception()
377 ? std::numeric_limits<result_base_type>::max()
378 : static_cast<result_base_type>(r_type_interval.u)
379 };
380
381 constexpr static bool exception_possible(){
382 if(r_type_interval.l.exception())
383 return true;
384 if(r_type_interval.u.exception())
385 return true;
386 if(! return_interval.includes(r_type_interval))
387 return true;
388 return false;
389 }
390
391 constexpr static auto rl = return_interval.l;
392 constexpr static auto ru = return_interval.u;
393
394 public:
395 using type =
396 safe_base<
397 result_base_type,
398 rl,
399 ru,
400 promotion_policy,
401 exception_policy
402 >;
403
404 constexpr static type return_value(const T & t, const U & u){
405 return type(
406 return_value(
407 t,
408 u,
409 std::integral_constant<bool, exception_possible()>()
410 ),
411 typename type::skip_validation()
412 );
413 }
414 };
415
416 template<class T, class U>
417 typename boost::lazy_enable_if_c<
418 is_safe<T>::value || is_safe<U>::value,
419 addition_result<T, U>
420 >::type
421 constexpr operator+(const T & t, const U & u){
422 return addition_result<T, U>::return_value(t, u);
423 }
424
425 template<class T, class U>
426 typename std::enable_if<
427 is_safe<T>::value || is_safe<U>::value,
428 T
429 >::type
430 constexpr operator+=(T & t, const U & u){
431 t = static_cast<T>(t + u);
432 return t;
433 }
434
435 /////////////////////////////////////////////////////////////////
436 // subtraction
437
438 template<class T, class U>
439 struct subtraction_result {
440 private:
441 using promotion_policy = typename common_promotion_policy<T, U>::type;
442 using result_base_type =
443 typename promotion_policy::template subtraction_result<T, U>::type;
444
445 // if exception not possible
446 constexpr static result_base_type
447 return_value(const T & t, const U & u, std::false_type){
448 return
449 static_cast<result_base_type>(base_value(t))
450 - static_cast<result_base_type>(base_value(u));
451 }
452
453 // if exception possible
454 using exception_policy = typename common_exception_policy<T, U>::type;
455
456 using r_type = checked_result<result_base_type>;
457
458 constexpr static result_base_type
459 return_value(const T & t, const U & u, std::true_type){
460 const std::pair<result_base_type, result_base_type> r = casting_helper<
461 exception_policy,
462 result_base_type
463 >(t, u);
464
465 const r_type rx = checked_operation<
466 result_base_type,
467 dispatch_and_return<exception_policy, result_base_type>
468 >::subtract(r.first, r.second);
469
470 return
471 rx.exception()
472 ? r.first + r.second
473 : rx.m_r;
474 }
475 using r_type_interval_t = interval<r_type>;
476
477 constexpr static const r_type_interval_t get_r_type_interval(){
478 constexpr const r_type_interval_t t_interval{
479 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
480 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
481 };
482
483 constexpr const r_type_interval_t u_interval{
484 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
485 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
486 };
487
488 return t_interval - u_interval;
489 }
490 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
491
492 constexpr static const interval<result_base_type> return_interval{
493 r_type_interval.l.exception()
494 ? std::numeric_limits<result_base_type>::min()
495 : static_cast<result_base_type>(r_type_interval.l),
496 r_type_interval.u.exception()
497 ? std::numeric_limits<result_base_type>::max()
498 : static_cast<result_base_type>(r_type_interval.u)
499 };
500
501 constexpr static bool exception_possible(){
502 if(r_type_interval.l.exception())
503 return true;
504 if(r_type_interval.u.exception())
505 return true;
506 if(! return_interval.includes(r_type_interval))
507 return true;
508 return false;
509 }
510
511 public:
512 constexpr static auto rl = return_interval.l;
513 constexpr static auto ru = return_interval.u;
514
515 using type =
516 safe_base<
517 result_base_type,
518 rl,
519 ru,
520 promotion_policy,
521 exception_policy
522 >;
523
524 constexpr static type return_value(const T & t, const U & u){
525 return type(
526 return_value(
527 t,
528 u,
529 std::integral_constant<bool, exception_possible()>()
530 ),
531 typename type::skip_validation()
532 );
533 }
534 };
535
536 template<class T, class U>
537 typename boost::lazy_enable_if_c<
538 is_safe<T>::value || is_safe<U>::value,
539 subtraction_result<T, U>
540 >::type
541 constexpr operator-(const T & t, const U & u){
542 return subtraction_result<T, U>::return_value(t, u);
543 }
544
545 template<class T, class U>
546 typename std::enable_if<
547 is_safe<T>::value || is_safe<U>::value,
548 T
549 >::type
550 constexpr operator-=(T & t, const U & u){
551 t = static_cast<T>(t - u);
552 return t;
553 }
554
555 /////////////////////////////////////////////////////////////////
556 // multiplication
557
558 template<class T, class U>
559 struct multiplication_result {
560 private:
561 using promotion_policy = typename common_promotion_policy<T, U>::type;
562 using result_base_type =
563 typename promotion_policy::template multiplication_result<T, U>::type;
564
565 // if exception not possible
566 constexpr static result_base_type
567 return_value(const T & t, const U & u, std::false_type){
568 return
569 static_cast<result_base_type>(base_value(t))
570 * static_cast<result_base_type>(base_value(u));
571 }
572
573 // if exception possible
574 using exception_policy = typename common_exception_policy<T, U>::type;
575
576 using r_type = checked_result<result_base_type>;
577
578 constexpr static result_base_type
579 return_value(const T & t, const U & u, std::true_type){
580 const std::pair<result_base_type, result_base_type> r = casting_helper<
581 exception_policy,
582 result_base_type
583 >(t, u);
584
585 const r_type rx = checked_operation<
586 result_base_type,
587 dispatch_and_return<exception_policy, result_base_type>
588 >::multiply(r.first, r.second);
589
590 return
591 rx.exception()
592 ? r.first * r.second
593 : rx.m_r;
594 }
595
596 using r_type_interval_t = interval<r_type>;
597
598 constexpr static r_type_interval_t get_r_type_interval(){
599 constexpr const r_type_interval_t t_interval{
600 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
601 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
602 };
603
604 constexpr const r_type_interval_t u_interval{
605 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
606 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
607 };
608
609 return t_interval * u_interval;
610 }
611
612 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
613
614 constexpr static const interval<result_base_type> return_interval{
615 r_type_interval.l.exception()
616 ? std::numeric_limits<result_base_type>::min()
617 : static_cast<result_base_type>(r_type_interval.l),
618 r_type_interval.u.exception()
619 ? std::numeric_limits<result_base_type>::max()
620 : static_cast<result_base_type>(r_type_interval.u)
621 };
622
623 constexpr static bool exception_possible(){
624 if(r_type_interval.l.exception())
625 return true;
626 if(r_type_interval.u.exception())
627 return true;
628 if(! return_interval.includes(r_type_interval))
629 return true;
630 return false;
631 }
632
633 constexpr static auto rl = return_interval.l;
634 constexpr static auto ru = return_interval.u;
635
636 public:
637 using type =
638 safe_base<
639 result_base_type,
640 rl,
641 ru,
642 promotion_policy,
643 exception_policy
644 >;
645
646 constexpr static type return_value(const T & t, const U & u){
647 return type(
648 return_value(
649 t,
650 u,
651 std::integral_constant<bool, exception_possible()>()
652 ),
653 typename type::skip_validation()
654 );
655 }
656 };
657
658 template<class T, class U>
659 typename boost::lazy_enable_if_c<
660 is_safe<T>::value || is_safe<U>::value,
661 multiplication_result<T, U>
662 >::type
663 constexpr operator*(const T & t, const U & u){
664 // argument dependent lookup should guarentee that we only get here
665 return multiplication_result<T, U>::return_value(t, u);
666 }
667
668 template<class T, class U>
669 typename std::enable_if<
670 is_safe<T>::value || is_safe<U>::value,
671 T
672 >::type
673 constexpr operator*=(T & t, const U & u){
674 t = static_cast<T>(t * u);
675 return t;
676 }
677
678 /////////////////////////////////////////////////////////////////
679 // division
680
681 // key idea here - result will never be larger than T
682 template<class T, class U>
683 struct division_result {
684 private:
685 using promotion_policy = typename common_promotion_policy<T, U>::type;
686 using result_base_type =
687 typename promotion_policy::template division_result<T, U>::type;
688
689 // if exception not possible
690 constexpr static result_base_type
691 return_value(const T & t, const U & u, std::false_type){
692 return
693 static_cast<result_base_type>(base_value(t))
694 / static_cast<result_base_type>(base_value(u));
695 }
696
697 // if exception possible
698 using exception_policy = typename common_exception_policy<T, U>::type;
699
700 constexpr static int bits = std::min(
701 std::numeric_limits<std::uintmax_t>::digits,
702 std::max(std::initializer_list<int>{
703 std::numeric_limits<result_base_type>::digits,
704 std::numeric_limits<typename base_type<T>::type>::digits,
705 std::numeric_limits<typename base_type<U>::type>::digits
706 }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
707 );
708
709 using r_type = checked_result<result_base_type>;
710
711 constexpr static result_base_type
712 return_value(const T & t, const U & u, std::true_type){
713 using temp_base = typename std::conditional<
714 std::numeric_limits<result_base_type>::is_signed,
715 typename boost::int_t<bits>::least,
716 typename boost::uint_t<bits>::least
717 >::type;
718 using t_type = checked_result<temp_base>;
719
720 const std::pair<t_type, t_type> r = casting_helper<
721 exception_policy,
722 temp_base
723 >(t, u);
724
725 const t_type rx = checked_operation<
726 temp_base,
727 dispatch_and_return<exception_policy, temp_base>
728 >::divide(r.first, r.second);
729
730 return
731 rx.exception()
732 ? r.first / r.second
733 : rx;
734 }
735 using r_type_interval_t = interval<r_type>;
736
737 constexpr static r_type_interval_t t_interval(){
738 return r_type_interval_t{
739 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
740 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
741 };
742 };
743
744 constexpr static r_type_interval_t u_interval(){
745 return r_type_interval_t{
746 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
747 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
748 };
749 };
750
751 constexpr static r_type_interval_t get_r_type_interval(){
752 constexpr const r_type_interval_t t = t_interval();
753 constexpr const r_type_interval_t u = u_interval();
754
755 if(u.u < r_type(0) || u.l > r_type(0))
756 return t / u;
757 return utility::minmax(
758 std::initializer_list<r_type> {
759 t.l / u.l,
760 t.l / r_type(-1),
761 t.l / r_type(1),
762 t.l / u.u,
763 t.u / u.l,
764 t.u / r_type(-1),
765 t.u / r_type(1),
766 t.u / u.u,
767 }
768 );
769 }
770
771 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
772
773 constexpr static const interval<result_base_type> return_interval{
774 r_type_interval.l.exception()
775 ? std::numeric_limits<result_base_type>::min()
776 : static_cast<result_base_type>(r_type_interval.l),
777 r_type_interval.u.exception()
778 ? std::numeric_limits<result_base_type>::max()
779 : static_cast<result_base_type>(r_type_interval.u)
780 };
781
782 constexpr static bool exception_possible(){
783 constexpr const r_type_interval_t ri = get_r_type_interval();
784 constexpr const r_type_interval_t ui = u_interval();
785 return
786 static_cast<bool>(ui.includes(r_type(0)))
787 || ri.l.exception()
788 || ri.u.exception();
789 }
790
791 constexpr static auto rl = return_interval.l;
792 constexpr static auto ru = return_interval.u;
793
794 public:
795 using type =
796 safe_base<
797 result_base_type,
798 rl,
799 ru,
800 promotion_policy,
801 exception_policy
802 >;
803
804 constexpr static type return_value(const T & t, const U & u){
805 return type(
806 return_value(
807 t,
808 u,
809 std::integral_constant<bool, exception_possible()>()
810 ),
811 typename type::skip_validation()
812 );
813 }
814 };
815
816 template<class T, class U>
817 typename boost::lazy_enable_if_c<
818 is_safe<T>::value || is_safe<U>::value,
819 division_result<T, U>
820 >::type
821 constexpr operator/(const T & t, const U & u){
822 return division_result<T, U>::return_value(t, u);
823 }
824
825 template<class T, class U>
826 typename std::enable_if<
827 is_safe<T>::value || is_safe<U>::value,
828 T
829 >::type
830 constexpr operator/=(T & t, const U & u){
831 t = static_cast<T>(t / u);
832 return t;
833 }
834
835 /////////////////////////////////////////////////////////////////
836 // modulus
837
838 template<class T, class U>
839 struct modulus_result {
840 private:
841 using promotion_policy = typename common_promotion_policy<T, U>::type;
842 using result_base_type = typename promotion_policy::template modulus_result<T, U>::type;
843
844 // if exception not possible
845 constexpr static result_base_type
846 return_value(const T & t, const U & u, std::false_type){
847 return
848 static_cast<result_base_type>(base_value(t))
849 % static_cast<result_base_type>(base_value(u));
850 }
851
852 // if exception possible
853 using exception_policy = typename common_exception_policy<T, U>::type;
854
855 constexpr static int bits = std::min(
856 std::numeric_limits<std::uintmax_t>::digits,
857 std::max(std::initializer_list<int>{
858 std::numeric_limits<result_base_type>::digits,
859 std::numeric_limits<typename base_type<T>::type>::digits,
860 std::numeric_limits<typename base_type<U>::type>::digits
861 }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
862 );
863
864 using r_type = checked_result<result_base_type>;
865
866 constexpr static result_base_type
867 return_value(const T & t, const U & u, std::true_type){
868 using temp_base = typename std::conditional<
869 std::numeric_limits<result_base_type>::is_signed,
870 typename boost::int_t<bits>::least,
871 typename boost::uint_t<bits>::least
872 >::type;
873 using t_type = checked_result<temp_base>;
874
875 const std::pair<t_type, t_type> r = casting_helper<
876 exception_policy,
877 temp_base
878 >(t, u);
879
880 const t_type rx = checked_operation<
881 temp_base,
882 dispatch_and_return<exception_policy, temp_base>
883 >::modulus(r.first, r.second);
884
885 return
886 rx.exception()
887 ? r.first % r.second
888 : rx;
889 }
890
891 using r_type_interval_t = interval<r_type>;
892
893 constexpr static const r_type_interval_t t_interval(){
894 return r_type_interval_t{
895 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
896 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
897 };
898 };
899
900 constexpr static const r_type_interval_t u_interval(){
901 return r_type_interval_t{
902 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
903 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
904 };
905 };
906
907 constexpr static const r_type_interval_t get_r_type_interval(){
908 constexpr const r_type_interval_t t = t_interval();
909 constexpr const r_type_interval_t u = u_interval();
910
911 if(u.u < r_type(0)
912 || u.l > r_type(0))
913 return t % u;
914 return utility::minmax(
915 std::initializer_list<r_type> {
916 t.l % u.l,
917 t.l % r_type(-1),
918 t.l % r_type(1),
919 t.l % u.u,
920 t.u % u.l,
921 t.u % r_type(-1),
922 t.u % r_type(1),
923 t.u % u.u,
924 }
925 );
926 }
927
928 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
929
930 constexpr static const interval<result_base_type> return_interval{
931 r_type_interval.l.exception()
932 ? std::numeric_limits<result_base_type>::min()
933 : static_cast<result_base_type>(r_type_interval.l),
934 r_type_interval.u.exception()
935 ? std::numeric_limits<result_base_type>::max()
936 : static_cast<result_base_type>(r_type_interval.u)
937 };
938
939 constexpr static bool exception_possible(){
940 constexpr const r_type_interval_t ri = get_r_type_interval();
941 constexpr const r_type_interval_t ui = u_interval();
942 return
943 static_cast<bool>(ui.includes(r_type(0)))
944 || ri.l.exception()
945 || ri.u.exception();
946 }
947
948 constexpr static auto rl = return_interval.l;
949 constexpr static auto ru = return_interval.u;
950
951 public:
952 using type =
953 safe_base<
954 result_base_type,
955 rl,
956 ru,
957 promotion_policy,
958 exception_policy
959 >;
960
961 constexpr static type return_value(const T & t, const U & u){
962 return type(
963 return_value(
964 t,
965 u,
966 std::integral_constant<bool, exception_possible()>()
967 ),
968 typename type::skip_validation()
969 );
970 }
971 };
972
973 template<class T, class U>
974 typename boost::lazy_enable_if_c<
975 is_safe<T>::value || is_safe<U>::value,
976 modulus_result<T, U>
977 >::type
978 constexpr operator%(const T & t, const U & u){
979 // see https://en.wikipedia.org/wiki/Modulo_operation
980 return modulus_result<T, U>::return_value(t, u);
981 }
982
983 template<class T, class U>
984 typename std::enable_if<
985 is_safe<T>::value || is_safe<U>::value,
986 T
987 >::type
988 constexpr operator%=(T & t, const U & u){
989 t = static_cast<T>(t % u);
990 return t;
991 }
992
993 /////////////////////////////////////////////////////////////////
994 // comparison
995
996 // less than
997
998 template<class T, class U>
999 struct less_than_result {
1000 private:
1001 using promotion_policy = typename common_promotion_policy<T, U>::type;
1002
1003 using result_base_type =
1004 typename promotion_policy::template comparison_result<T, U>::type;
1005
1006 // if exception not possible
1007 constexpr static bool
1008 return_value(const T & t, const U & u, std::false_type){
1009 return
1010 static_cast<result_base_type>(base_value(t))
1011 < static_cast<result_base_type>(base_value(u));
1012 }
1013
1014 using exception_policy = typename common_exception_policy<T, U>::type;
1015
1016 using r_type = checked_result<result_base_type>;
1017
1018 // if exception possible
1019 constexpr static bool
1020 return_value(const T & t, const U & u, std::true_type){
1021 const std::pair<result_base_type, result_base_type> r = casting_helper<
1022 exception_policy,
1023 result_base_type
1024 >(t, u);
1025
1026 return safe_compare::less_than(r.first, r.second);
1027 }
1028
1029 using r_type_interval_t = interval<r_type>;
1030
1031 constexpr static bool interval_open(const r_type_interval_t & t){
1032 return t.l.exception() || t.u.exception();
1033 }
1034
1035 public:
1036 constexpr static bool
1037 return_value(const T & t, const U & u){
1038 constexpr const r_type_interval_t t_interval{
1039 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1040 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1041 };
1042 constexpr const r_type_interval_t u_interval{
1043 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1044 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1045 };
1046
1047 if(t_interval < u_interval)
1048 return true;
1049 if(t_interval > u_interval)
1050 return false;
1051
1052 constexpr bool exception_possible
1053 = interval_open(t_interval) || interval_open(u_interval);
1054
1055 return return_value(
1056 t,
1057 u,
1058 std::integral_constant<bool, exception_possible>()
1059 );
1060 }
1061 };
1062
1063 template<class T, class U>
1064 typename std::enable_if<
1065 is_safe<T>::value || is_safe<U>::value,
1066 bool
1067 >::type
1068 constexpr operator<(const T & lhs, const U & rhs) {
1069 return less_than_result<T, U>::return_value(lhs, rhs);
1070 }
1071
1072 template<class T, class U>
1073 typename std::enable_if<
1074 is_safe<T>::value || is_safe<U>::value,
1075 bool
1076 >::type
1077 constexpr operator>(const T & lhs, const U & rhs) {
1078 return rhs < lhs;
1079 }
1080
1081 template<class T, class U>
1082 typename std::enable_if<
1083 is_safe<T>::value || is_safe<U>::value,
1084 bool
1085 >::type
1086 constexpr operator>=(const T & lhs, const U & rhs) {
1087 return ! ( lhs < rhs );
1088 }
1089
1090 template<class T, class U>
1091 typename std::enable_if<
1092 is_safe<T>::value || is_safe<U>::value,
1093 bool
1094 >::type
1095 constexpr operator<=(const T & lhs, const U & rhs) {
1096 return ! ( lhs > rhs );
1097 }
1098
1099 // equal
1100
1101 template<class T, class U>
1102 struct equal_result {
1103 private:
1104 using promotion_policy = typename common_promotion_policy<T, U>::type;
1105
1106 using result_base_type =
1107 typename promotion_policy::template comparison_result<T, U>::type;
1108
1109 // if exception not possible
1110 constexpr static bool
1111 return_value(const T & t, const U & u, std::false_type){
1112 return
1113 static_cast<result_base_type>(base_value(t))
1114 == static_cast<result_base_type>(base_value(u));
1115 }
1116
1117 using exception_policy = typename common_exception_policy<T, U>::type;
1118
1119 using r_type = checked_result<result_base_type>;
1120
1121 // exception possible
1122 constexpr static bool
1123 return_value(const T & t, const U & u, std::true_type){
1124 const std::pair<result_base_type, result_base_type> r = casting_helper<
1125 exception_policy,
1126 result_base_type
1127 >(t, u);
1128
1129 return safe_compare::equal(r.first, r.second);
1130 }
1131
1132 using r_type_interval = interval<r_type>;
1133
1134 constexpr static bool interval_open(const r_type_interval & t){
1135 return t.l.exception() || t.u.exception();
1136 }
1137
1138 public:
1139 constexpr static bool
1140 return_value(const T & t, const U & u){
1141 constexpr const r_type_interval t_interval{
1142 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1143 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1144 };
1145
1146 constexpr const r_type_interval u_interval{
1147 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1148 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1149 };
1150
1151 if(! intersect(t_interval, u_interval))
1152 return false;
1153
1154 constexpr bool exception_possible
1155 = interval_open(t_interval) || interval_open(u_interval);
1156
1157 return return_value(
1158 t,
1159 u,
1160 std::integral_constant<bool, exception_possible>()
1161 );
1162 }
1163 };
1164
1165 template<class T, class U>
1166 typename std::enable_if<
1167 is_safe<T>::value || is_safe<U>::value,
1168 bool
1169 >::type
1170 constexpr operator==(const T & lhs, const U & rhs) {
1171 return equal_result<T, U>::return_value(lhs, rhs);
1172 }
1173
1174 template<class T, class U>
1175 typename std::enable_if<
1176 is_safe<T>::value || is_safe<U>::value,
1177 bool
1178 >::type
1179 constexpr operator!=(const T & lhs, const U & rhs) {
1180 return ! (lhs == rhs);
1181 }
1182
1183 /////////////////////////////////////////////////////////////////
1184 // shift operators
1185
1186 // left shift
1187 template<class T, class U>
1188 struct left_shift_result {
1189 private:
1190 using promotion_policy = typename common_promotion_policy<T, U>::type;
1191 using result_base_type =
1192 typename promotion_policy::template left_shift_result<T, U>::type;
1193
1194 // if exception not possible
1195 constexpr static result_base_type
1196 return_value(const T & t, const U & u, std::false_type){
1197 return
1198 static_cast<result_base_type>(base_value(t))
1199 << static_cast<result_base_type>(base_value(u));
1200 }
1201
1202 // exception possible
1203 using exception_policy = typename common_exception_policy<T, U>::type;
1204
1205 using r_type = checked_result<result_base_type>;
1206
1207 constexpr static result_base_type
1208 return_value(const T & t, const U & u, std::true_type){
1209 const std::pair<result_base_type, result_base_type> r = casting_helper<
1210 exception_policy,
1211 result_base_type
1212 >(t, u);
1213
1214 const r_type rx = checked_operation<
1215 result_base_type,
1216 dispatch_and_return<exception_policy, result_base_type>
1217 >::left_shift(r.first, r.second);
1218
1219 return
1220 rx.exception()
1221 ? r.first << r.second
1222 : rx.m_r;
1223 }
1224
1225 using r_type_interval_t = interval<r_type>;
1226
1227 constexpr static r_type_interval_t get_r_type_interval(){
1228 constexpr const r_type_interval_t t_interval{
1229 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1230 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1231 };
1232
1233 constexpr const r_type_interval_t u_interval{
1234 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1235 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1236 };
1237 return (t_interval << u_interval);
1238 }
1239
1240 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
1241
1242 constexpr static const interval<result_base_type> return_interval{
1243 r_type_interval.l.exception()
1244 ? std::numeric_limits<result_base_type>::min()
1245 : static_cast<result_base_type>(r_type_interval.l),
1246 r_type_interval.u.exception()
1247 ? std::numeric_limits<result_base_type>::max()
1248 : static_cast<result_base_type>(r_type_interval.u)
1249 };
1250
1251 constexpr static bool exception_possible(){
1252 if(r_type_interval.l.exception())
1253 return true;
1254 if(r_type_interval.u.exception())
1255 return true;
1256 if(! return_interval.includes(r_type_interval))
1257 return true;
1258 return false;
1259 }
1260
1261 constexpr static auto rl = return_interval.l;
1262 constexpr static auto ru = return_interval.u;
1263
1264 public:
1265 using type =
1266 safe_base<
1267 result_base_type,
1268 rl,
1269 ru,
1270 promotion_policy,
1271 exception_policy
1272 >;
1273
1274 constexpr static type return_value(const T & t, const U & u){
1275 return type(
1276 return_value(
1277 t,
1278 u,
1279 std::integral_constant<bool, exception_possible()>()
1280 ),
1281 typename type::skip_validation()
1282 );
1283 }
1284 };
1285
1286 template<class T, class U>
1287 typename boost::lazy_enable_if_c<
1288 // handle safe<T> << int, int << safe<U>, safe<T> << safe<U>
1289 // exclude std::ostream << ...
1290 (! std::is_base_of<std::ios_base, T>::value)
1291 && (is_safe<T>::value || is_safe<U>::value),
1292 left_shift_result<T, U>
1293 >::type
1294 constexpr operator<<(const T & t, const U & u){
1295 // INT13-CPP
1296 // C++ standards document N4618 & 5.8.2
1297 static_assert(
1298 std::numeric_limits<T>::is_integer, "shifted value must be an integer"
1299 );
1300 static_assert(
1301 std::numeric_limits<U>::is_integer, "shift amount must be an integer"
1302 );
1303 return left_shift_result<T, U>::return_value(t, u);
1304 }
1305
1306 template<class T, class U>
1307 typename std::enable_if<
1308 is_safe<T>::value || is_safe<U>::value,
1309 T
1310 >::type
1311 constexpr operator<<=(T & t, const U & u){
1312 t = static_cast<T>(t << u);
1313 return t;
1314 }
1315
1316 // right shift
1317 template<class T, class U>
1318 struct right_shift_result {
1319 using promotion_policy = typename common_promotion_policy<T, U>::type;
1320 using result_base_type =
1321 typename promotion_policy::template right_shift_result<T, U>::type;
1322
1323 // if exception not possible
1324 constexpr static result_base_type
1325 return_value(const T & t, const U & u, std::false_type){
1326 return
1327 static_cast<result_base_type>(base_value(t))
1328 >> static_cast<result_base_type>(base_value(u));
1329 }
1330
1331 // exception possible
1332 using exception_policy = typename common_exception_policy<T, U>::type;
1333
1334 using r_type = checked_result<result_base_type>;
1335
1336 constexpr static result_base_type
1337 return_value(const T & t, const U & u, std::true_type){
1338 const std::pair<result_base_type, result_base_type> r = casting_helper<
1339 exception_policy,
1340 result_base_type
1341 >(t, u);
1342
1343 const r_type rx = checked_operation<
1344 result_base_type,
1345 dispatch_and_return<exception_policy, result_base_type>
1346 >::right_shift(r.first, r.second);
1347
1348 return
1349 rx.exception()
1350 ? r.first >> r.second
1351 : rx.m_r;
1352 }
1353
1354 using r_type_interval_t = interval<r_type>;
1355
1356 constexpr static r_type_interval_t t_interval(){
1357 return r_type_interval_t(
1358 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1359 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1360 );
1361 };
1362
1363 constexpr static r_type_interval_t u_interval(){
1364 return r_type_interval_t(
1365 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1366 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1367 );
1368 }
1369 constexpr static r_type_interval_t get_r_type_interval(){;
1370 return (t_interval() >> u_interval());
1371 }
1372
1373 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
1374
1375 constexpr static const interval<result_base_type> return_interval{
1376 r_type_interval.l.exception()
1377 ? std::numeric_limits<result_base_type>::min()
1378 : static_cast<result_base_type>(r_type_interval.l),
1379 r_type_interval.u.exception()
1380 ? std::numeric_limits<result_base_type>::max()
1381 : static_cast<result_base_type>(r_type_interval.u)
1382 };
1383
1384 constexpr static bool exception_possible(){
1385 constexpr const r_type_interval_t ri = r_type_interval;
1386 constexpr const r_type_interval_t ti = t_interval();
1387 constexpr const r_type_interval_t ui = u_interval();
1388 return static_cast<bool>(
1389 // note undesirable coupling with checked::shift right here !
1390 ui.u > checked_result<result_base_type>(
1391 std::numeric_limits<result_base_type>::digits
1392 )
1393 || ti.l < checked_result<result_base_type>(0)
1394 || ui.l < checked_result<result_base_type>(0)
1395 || ri.l.exception()
1396 || ri.u.exception()
1397 );
1398 }
1399
1400 constexpr static auto rl = return_interval.l;
1401 constexpr static auto ru = return_interval.u;
1402
1403 public:
1404 using type =
1405 safe_base<
1406 result_base_type,
1407 rl,
1408 ru,
1409 promotion_policy,
1410 exception_policy
1411 >;
1412
1413 constexpr static type return_value(const T & t, const U & u){
1414 return type(
1415 return_value(
1416 t,
1417 u,
1418 std::integral_constant<bool, exception_possible()>()
1419 ),
1420 typename type::skip_validation()
1421 );
1422 }
1423 };
1424
1425 template<class T, class U>
1426 typename boost::lazy_enable_if_c<
1427 (! std::is_base_of<std::ios_base, T>::value)
1428 && (is_safe<T>::value || is_safe<U>::value),
1429 right_shift_result<T, U>
1430 >::type
1431 constexpr operator>>(const T & t, const U & u){
1432 // INT13-CPP
1433 static_assert(
1434 std::numeric_limits<T>::is_integer, "shifted value must be an integer"
1435 );
1436 static_assert(
1437 std::numeric_limits<U>::is_integer, "shift amount must be an integer"
1438 );
1439 return right_shift_result<T, U>::return_value(t, u);
1440 }
1441
1442 template<class T, class U>
1443 typename std::enable_if<
1444 is_safe<T>::value || is_safe<U>::value,
1445 T
1446 >::type
1447 constexpr operator>>=(T & t, const U & u){
1448 t = static_cast<T>(t >> u);
1449 return t;
1450 }
1451
1452 /////////////////////////////////////////////////////////////////
1453 // bitwise operators
1454
1455 // operator |
1456 template<class T, class U>
1457 struct bitwise_or_result {
1458 private:
1459 using promotion_policy = typename common_promotion_policy<T, U>::type;
1460 using result_base_type =
1461 typename promotion_policy::template bitwise_or_result<T, U>::type;
1462
1463 // according to the C++ standard, the bitwise operators are executed as if
1464 // the operands are consider a logical array of bits. That is, there is no
1465 // sense that these are signed numbers.
1466
1467 using r_type = typename std::make_unsigned<result_base_type>::type;
1468 using r_type_interval_t = interval<r_type>;
1469
1470 #if 0
1471 // breaks compilation for earlier versions of clant
1472 constexpr static const r_type_interval_t r_interval{
1473 r_type(0),
1474 utility::round_out(
1475 std::max(
1476 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1477 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1478 )
1479 )
1480 };
1481 #endif
1482
1483 using exception_policy = typename common_exception_policy<T, U>::type;
1484
1485 public:
1486 // lazy_enable_if_c depends on this
1487 using type = safe_base<
1488 result_base_type,
1489 //r_interval.l,
1490 r_type(0),
1491 //r_interval.u,
1492 utility::round_out(
1493 std::max(
1494 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1495 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1496 )
1497 ),
1498 promotion_policy,
1499 exception_policy
1500 >;
1501
1502 constexpr static type return_value(const T & t, const U & u){
1503 return type(
1504 static_cast<result_base_type>(base_value(t))
1505 | static_cast<result_base_type>(base_value(u)),
1506 typename type::skip_validation()
1507 );
1508 }
1509 };
1510
1511 template<class T, class U>
1512 typename boost::lazy_enable_if_c<
1513 is_safe<T>::value || is_safe<U>::value,
1514 bitwise_or_result<T, U>
1515 >::type
1516 constexpr operator|(const T & t, const U & u){
1517 return bitwise_or_result<T, U>::return_value(t, u);
1518 }
1519
1520 template<class T, class U>
1521 typename std::enable_if<
1522 is_safe<T>::value || is_safe<U>::value,
1523 T
1524 >::type
1525 constexpr operator|=(T & t, const U & u){
1526 t = static_cast<T>(t | u);
1527 return t;
1528 }
1529
1530 // operator &
1531 template<class T, class U>
1532 struct bitwise_and_result {
1533 private:
1534 using promotion_policy = typename common_promotion_policy<T, U>::type;
1535 using result_base_type =
1536 typename promotion_policy::template bitwise_and_result<T, U>::type;
1537
1538 // according to the C++ standard, the bitwise operators are executed as if
1539 // the operands are consider a logical array of bits. That is, there is no
1540 // sense that these are signed numbers.
1541
1542 using r_type = typename std::make_unsigned<result_base_type>::type;
1543 using r_type_interval_t = interval<r_type>;
1544
1545 #if 0
1546 // breaks compilation for earlier versions of clant
1547 constexpr static const r_type_interval_t r_interval{
1548 r_type(0),
1549 utility::round_out(
1550 std::min(
1551 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1552 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1553 )
1554 )
1555 };
1556 #endif
1557 using exception_policy = typename common_exception_policy<T, U>::type;
1558
1559 public:
1560 // lazy_enable_if_c depends on this
1561 using type = safe_base<
1562 result_base_type,
1563 //r_interval.l,
1564 r_type(0),
1565 //r_interval.u,
1566 utility::round_out(
1567 std::min(
1568 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1569 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1570 )
1571 ),
1572 promotion_policy,
1573 exception_policy
1574 >;
1575
1576 constexpr static type return_value(const T & t, const U & u){
1577 return type(
1578 static_cast<result_base_type>(base_value(t))
1579 & static_cast<result_base_type>(base_value(u)),
1580 typename type::skip_validation()
1581 );
1582 }
1583 };
1584
1585 template<class T, class U>
1586 typename boost::lazy_enable_if_c<
1587 is_safe<T>::value || is_safe<U>::value,
1588 bitwise_and_result<T, U>
1589 >::type
1590 constexpr operator&(const T & t, const U & u){
1591 return bitwise_and_result<T, U>::return_value(t, u);
1592 }
1593
1594 template<class T, class U>
1595 typename std::enable_if<
1596 is_safe<T>::value || is_safe<U>::value,
1597 T
1598 >::type
1599 constexpr operator&=(T & t, const U & u){
1600 t = static_cast<T>(t & u);
1601 return t;
1602 }
1603
1604 // operator ^
1605 template<class T, class U>
1606 struct bitwise_xor_result {
1607 using promotion_policy = typename common_promotion_policy<T, U>::type;
1608 using result_base_type =
1609 typename promotion_policy::template bitwise_xor_result<T, U>::type;
1610
1611 // according to the C++ standard, the bitwise operators are executed as if
1612 // the operands are consider a logical array of bits. That is, there is no
1613 // sense that these are signed numbers.
1614
1615 using r_type = typename std::make_unsigned<result_base_type>::type;
1616 using r_type_interval_t = interval<r_type>;
1617
1618 #if 0
1619 // breaks compilation for earlier versions of clant
1620 constexpr static const r_type_interval_t r_interval{
1621 r_type(0),
1622 utility::round_out(
1623 std::max(
1624 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1625 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1626 )
1627 )
1628 };
1629 #endif
1630
1631 using exception_policy = typename common_exception_policy<T, U>::type;
1632
1633 public:
1634 // lazy_enable_if_c depends on this
1635 using type = safe_base<
1636 result_base_type,
1637 //r_interval.l,
1638 r_type(0),
1639 //r_interval.u,
1640 utility::round_out(
1641 std::max(
1642 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1643 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1644 )
1645 ),
1646 promotion_policy,
1647 exception_policy
1648 >;
1649
1650 constexpr static type return_value(const T & t, const U & u){
1651 return type(
1652 static_cast<result_base_type>(base_value(t))
1653 ^ static_cast<result_base_type>(base_value(u)),
1654 typename type::skip_validation()
1655 );
1656 }
1657 };
1658
1659 template<class T, class U>
1660 typename boost::lazy_enable_if_c<
1661 is_safe<T>::value || is_safe<U>::value,
1662 bitwise_xor_result<T, U>
1663 >::type
1664 constexpr operator^(const T & t, const U & u){
1665 return bitwise_xor_result<T, U>::return_value(t, u);
1666 }
1667
1668 template<class T, class U>
1669 typename std::enable_if<
1670 is_safe<T>::value || is_safe<U>::value,
1671 T
1672 >::type
1673 constexpr operator^=(T & t, const U & u){
1674 t = static_cast<T>(t ^ u);
1675 return t;
1676 }
1677
1678 /////////////////////////////////////////////////////////////////
1679 // stream helpers
1680
1681 template<
1682 class T,
1683 T Min,
1684 T Max,
1685 class P, // promotion polic
1686 class E // exception policy
1687 >
1688 template<
1689 class CharT,
1690 class Traits
1691 >
1692 void safe_base<T, Min, Max, P, E>::output(
1693 std::basic_ostream<CharT, Traits> & os
1694 ) const {
1695 os << (
1696 (std::is_same<T, signed char>::value
1697 || std::is_same<T, unsigned char>::value
1698 || std::is_same<T, wchar_t>::value
1699 ) ?
1700 static_cast<int>(m_t)
1701 :
1702 m_t
1703 );
1704 }
1705
1706 template<
1707 class T,
1708 T Min,
1709 T Max,
1710 class P, // promotion polic
1711 class E // exception policy
1712 >
1713 template<
1714 class CharT,
1715 class Traits
1716 >
1717 void safe_base<T, Min, Max, P, E>::input(
1718 std::basic_istream<CharT, Traits> & is
1719 ){
1720 if(std::is_same<T, signed char>::value
1721 || std::is_same<T, unsigned char>::value
1722 || std::is_same<T, wchar_t>::value
1723 ){
1724 int x;
1725 is >> x;
1726 m_t = validated_cast(x);
1727 }
1728 else{
1729 is >> m_t;
1730 validated_cast(m_t);
1731 }
1732 if(is.fail()){
1733 boost::safe_numerics::dispatch<
1734 E,
1735 boost::safe_numerics::safe_numerics_error::domain_error
1736 >(
1737 "error in file input"
1738 );
1739 }
1740 }
1741
1742 } // safe_numerics
1743 } // boost
1744
1745 #endif // BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP