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