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