• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
return_valueboost::safe_numerics::validate_detail::exception_possible40         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>
return_valueboost::safe_numerics::validate_detail::exception_not_possible57         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>
return_valueboost::safe_numerics::validate_detail65     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>::
validated_cast(const T & t) const89 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>::
validated_cast(const safe_literal_impl<T,N,P1,E1> &) const96 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>
safe_base(const Stored & rhs,skip_validation)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>
safe_base()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>
safe_base(const T & t,typename std::enable_if<is_safe<T>::value,bool>::type)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>
safe_base(const T & t,typename std::enable_if<std::is_integral<T>::value,bool>::type)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>
safe_base(const std::integral_constant<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>::
operator R() const172 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>::
operator Stored() const194 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>
casting_helper(const T & t,const U & u)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
return_valueboost::safe_numerics::addition_result328     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
return_valueboost::safe_numerics::addition_result340     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 
get_r_type_intervalboost::safe_numerics::addition_result359     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 
exception_possibleboost::safe_numerics::addition_result381     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 
return_valueboost::safe_numerics::addition_result404     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
operator +(const T & t,const U & u)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
operator +=(T & t,const U & u)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
return_valueboost::safe_numerics::subtraction_result447     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
return_valueboost::safe_numerics::subtraction_result459     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 
get_r_type_intervalboost::safe_numerics::subtraction_result477     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 
exception_possibleboost::safe_numerics::subtraction_result501     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 
return_valueboost::safe_numerics::subtraction_result524     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
operator -(const T & t,const U & u)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
operator -=(T & t,const U & u)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
return_valueboost::safe_numerics::multiplication_result567     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
return_valueboost::safe_numerics::multiplication_result579     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 
get_r_type_intervalboost::safe_numerics::multiplication_result598     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 
exception_possibleboost::safe_numerics::multiplication_result623     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 
return_valueboost::safe_numerics::multiplication_result646     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
operator *(const T & t,const U & u)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
operator *=(T & t,const U & u)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
return_valueboost::safe_numerics::division_result691     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
return_valueboost::safe_numerics::division_result712     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 
t_intervalboost::safe_numerics::division_result737     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 
u_intervalboost::safe_numerics::division_result744     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 
get_r_type_intervalboost::safe_numerics::division_result751     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 
exception_possibleboost::safe_numerics::division_result782     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 
return_valueboost::safe_numerics::division_result804     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
operator /(const T & t,const U & u)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
operator /=(T & t,const U & u)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
return_valueboost::safe_numerics::modulus_result846     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
return_valueboost::safe_numerics::modulus_result867     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 
t_intervalboost::safe_numerics::modulus_result893     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 
u_intervalboost::safe_numerics::modulus_result900     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 
get_r_type_intervalboost::safe_numerics::modulus_result907     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 
exception_possibleboost::safe_numerics::modulus_result939     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 
return_valueboost::safe_numerics::modulus_result961     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
operator %(const T & t,const U & u)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
operator %=(T & t,const U & u)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
return_valueboost::safe_numerics::less_than_result1008     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
return_valueboost::safe_numerics::less_than_result1020     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 
interval_openboost::safe_numerics::less_than_result1031     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
return_valueboost::safe_numerics::less_than_result1037     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
operator <(const T & lhs,const U & rhs)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
operator >(const T & lhs,const U & rhs)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
operator >=(const T & lhs,const U & rhs)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
operator <=(const T & lhs,const U & rhs)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
return_valueboost::safe_numerics::equal_result1111     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
return_valueboost::safe_numerics::equal_result1123     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 
interval_openboost::safe_numerics::equal_result1134     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
return_valueboost::safe_numerics::equal_result1140     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
operator ==(const T & lhs,const U & rhs)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
operator !=(const T & lhs,const U & rhs)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
return_valueboost::safe_numerics::left_shift_result1196     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
return_valueboost::safe_numerics::left_shift_result1208     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 
get_r_type_intervalboost::safe_numerics::left_shift_result1227     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 
exception_possibleboost::safe_numerics::left_shift_result1251     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 
return_valueboost::safe_numerics::left_shift_result1274     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
operator <<(const T & t,const U & u)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
operator <<=(T & t,const U & u)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
return_valueboost::safe_numerics::right_shift_result1325     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
return_valueboost::safe_numerics::right_shift_result1337     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 
t_intervalboost::safe_numerics::right_shift_result1356     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 
u_intervalboost::safe_numerics::right_shift_result1363     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     }
get_r_type_intervalboost::safe_numerics::right_shift_result1369     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 
exception_possibleboost::safe_numerics::right_shift_result1384     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 
return_valueboost::safe_numerics::right_shift_result1413     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
operator >>(const T & t,const U & u)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
operator >>=(T & t,const U & u)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 
return_valueboost::safe_numerics::bitwise_or_result1502     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
operator |(const T & t,const U & u)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
operator |=(T & t,const U & u)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 
return_valueboost::safe_numerics::bitwise_and_result1576     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
operator &(const T & t,const U & u)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
operator &=(T & t,const U & u)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 
return_valueboost::safe_numerics::bitwise_xor_result1650     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
operator ^(const T & t,const U & u)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
operator ^=(T & t,const U & u)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 >
output(std::basic_ostream<CharT,Traits> & os) const1692 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 >
input(std::basic_istream<CharT,Traits> & is)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
1746