]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/safe_numerics/checked_result_operations.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / safe_numerics / checked_result_operations.hpp
1 #ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
2 #define BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
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 // Implemenation of arithmetic on "extended" integers.
11 // Extended integers are defined in terms of C++ primitive integers as
12 // a) an interger range
13 // b) extra elements +inf, -inf, indeterminate
14 //
15 // Integer operations are closed on the set of extended integers
16 // but operations are not necessarily associative when they result in the
17 // extensions +inf, -inf, and indeterminate
18 //
19 // in this code, the type "checked_result<T>" where T is some
20 // integer type is an "extended" integer.
21
22 #include <cassert>
23
24 #include <boost/logic/tribool.hpp>
25
26 #include "checked_result.hpp"
27 #include "checked_integer.hpp"
28
29 //////////////////////////////////////////////////////////////////////////
30 // the following idea of "value_type" is used by several of the operations
31 // defined by checked_result arithmetic.
32
33 namespace boost {
34 namespace safe_numerics {
35
36 template<typename T>
37 constexpr inline void display(const boost::safe_numerics::checked_result<T> & c){
38 switch(c.m_e){
39 case safe_numerics_error::success:
40 std::terminate();
41 case safe_numerics_error::positive_overflow_error: // result is above representational maximum
42 std::terminate();
43 case safe_numerics_error::negative_overflow_error: // result is below representational minimum
44 std::terminate();
45 case safe_numerics_error::domain_error: // one operand is out of valid range
46 std::terminate();
47 case safe_numerics_error::range_error: // result cannot be produced for this operation
48 std::terminate();
49 case safe_numerics_error::precision_overflow_error: // result lost precision
50 std::terminate();
51 case safe_numerics_error::underflow_error: // result is too small to be represented
52 std::terminate();
53 case safe_numerics_error::negative_value_shift: // negative value in shift operator
54 std::terminate();
55 case safe_numerics_error::negative_shift: // shift a negative value
56 std::terminate();
57 case safe_numerics_error::shift_too_large: // l/r shift exceeds variable size
58 std::terminate();
59 case safe_numerics_error::uninitialized_value: // creating of uninitialized value
60 std::terminate();
61 }
62 }
63
64 //////////////////////////////////////////////////////////////////////////
65 // implement C++ operators for check_result<T>
66
67 struct sum_value_type {
68 // characterization of various values
69 const enum flag {
70 known_value = 0,
71 less_than_min,
72 greater_than_max,
73 indeterminate,
74 count
75 } m_flag;
76 template<class T>
77 constexpr flag to_flag(const checked_result<T> & t) const {
78 switch(static_cast<safe_numerics_error>(t)){
79 case safe_numerics_error::success:
80 return known_value;
81 case safe_numerics_error::negative_overflow_error:
82 // result is below representational minimum
83 return less_than_min;
84 case safe_numerics_error::positive_overflow_error:
85 // result is above representational maximum
86 return greater_than_max;
87 default:
88 return indeterminate;
89 }
90 }
91 template<class T>
92 constexpr sum_value_type(const checked_result<T> & t) :
93 m_flag(to_flag(t))
94 {}
95 constexpr operator std::uint8_t () const {
96 return static_cast<std::uint8_t>(m_flag);
97 }
98 };
99
100 // integers addition
101 template<class T>
102 typename std::enable_if<
103 std::is_integral<T>::value,
104 checked_result<T>
105 >::type
106 constexpr inline operator+(
107 const checked_result<T> & t,
108 const checked_result<T> & u
109 ){
110 using value_type = sum_value_type;
111 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
112
113 // note major pain. Clang constexpr multi-dimensional array is fine.
114 // but gcc doesn't permit a multi-dimensional array to be be constexpr.
115 // so we need to some ugly gymnastics to make our system work for all
116 // all systems.
117 const enum safe_numerics_error result[order * order] = {
118 // t == known_value
119 //{
120 // u == ...
121 safe_numerics_error::success, // known_value,
122 safe_numerics_error::negative_overflow_error, // less_than_min,
123 safe_numerics_error::positive_overflow_error, // greater_than_max,
124 safe_numerics_error::range_error, // indeterminate,
125 //},
126 // t == less_than_min,
127 //{
128 // u == ...
129 safe_numerics_error::negative_overflow_error, // known_value,
130 safe_numerics_error::negative_overflow_error, // less_than_min,
131 safe_numerics_error::range_error, // greater_than_max,
132 safe_numerics_error::range_error, // indeterminate,
133 //},
134 // t == greater_than_max,
135 //{
136 // u == ...
137 safe_numerics_error::positive_overflow_error, // known_value,
138 safe_numerics_error::range_error, // less_than_min,
139 safe_numerics_error::positive_overflow_error, // greater_than_max,
140 safe_numerics_error::range_error, // indeterminate,
141 //},
142 // t == indeterminate,
143 //{
144 // u == ...
145 safe_numerics_error::range_error, // known_value,
146 safe_numerics_error::range_error, // less_than_min,
147 safe_numerics_error::range_error, // greater_than_max,
148 safe_numerics_error::range_error, // indeterminate,
149 //},
150 };
151
152 const value_type tx(t);
153 const value_type ux(u);
154
155 const safe_numerics_error e = result[tx * order + ux];
156 if(safe_numerics_error::success == e)
157 return checked::add<T>(t, u);
158 return checked_result<T>(e, "addition result");
159 }
160
161 // unary +
162 template<class T>
163 typename std::enable_if<
164 std::is_integral<T>::value,
165 checked_result<T>
166 >::type
167 constexpr inline operator+(
168 const checked_result<T> & t
169 ){
170 return t;
171 }
172
173 // integers subtraction
174 template<class T>
175 typename std::enable_if<
176 std::is_integral<T>::value,
177 checked_result<T>
178 >::type
179 constexpr inline operator-(
180 const checked_result<T> & t,
181 const checked_result<T> & u
182 ){
183 using value_type = sum_value_type;
184 constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
185
186 constexpr const enum safe_numerics_error result[order * order] = {
187 // t == known_value
188 //{
189 // u == ...
190 safe_numerics_error::success, // known_value,
191 safe_numerics_error::positive_overflow_error, // less_than_min,
192 safe_numerics_error::negative_overflow_error, // greater_than_max,
193 safe_numerics_error::range_error, // indeterminate,
194 //},
195 // t == less_than_min,
196 //{
197 // u == ...
198 safe_numerics_error::negative_overflow_error, // known_value,
199 safe_numerics_error::range_error, // less_than_min,
200 safe_numerics_error::negative_overflow_error, // greater_than_max,
201 safe_numerics_error::range_error, // indeterminate,
202 //},
203 // t == greater_than_max,
204 //{
205 // u == ...
206 safe_numerics_error::positive_overflow_error, // known_value,
207 safe_numerics_error::positive_overflow_error, // less_than_min,
208 safe_numerics_error::range_error, // greater_than_max,
209 safe_numerics_error::range_error, // indeterminate,
210 //},
211 // t == indeterminate,
212 //{
213 // u == ...
214 safe_numerics_error::range_error, // known_value,
215 safe_numerics_error::range_error, // less_than_min,
216 safe_numerics_error::range_error, // greater_than_max,
217 safe_numerics_error::range_error, // indeterminate,
218 //},
219 };
220
221 const value_type tx(t);
222 const value_type ux(u);
223
224 const safe_numerics_error e = result[tx * order + ux];
225 if(safe_numerics_error::success == e)
226 return checked::subtract<T>(t, u);
227 return checked_result<T>(e, "subtraction result");
228 }
229
230 // unary -
231 template<class T>
232 typename std::enable_if<
233 std::is_integral<T>::value,
234 checked_result<T>
235 >::type
236 constexpr inline operator-(
237 const checked_result<T> & t
238 ){
239 // assert(false);
240 return checked_result<T>(0) - t;
241 }
242
243 struct product_value_type {
244 // characterization of various values
245 const enum flag {
246 less_than_min = 0,
247 less_than_zero,
248 zero,
249 greater_than_zero,
250 greater_than_max,
251 indeterminate,
252 // count of number of cases for values
253 count,
254 // temporary values for special cases
255 t_value,
256 u_value,
257 z_value
258 } m_flag;
259 template<class T>
260 constexpr flag to_flag(const checked_result<T> & t) const {
261 switch(static_cast<safe_numerics_error>(t)){
262 case safe_numerics_error::success:
263 return (t < checked_result<T>(0))
264 ? less_than_zero
265 : (t > checked_result<T>(0))
266 ? greater_than_zero
267 : zero;
268 case safe_numerics_error::negative_overflow_error:
269 // result is below representational minimum
270 return less_than_min;
271 case safe_numerics_error::positive_overflow_error:
272 // result is above representational maximum
273 return greater_than_max;
274 default:
275 return indeterminate;
276 }
277 }
278 template<class T>
279 constexpr product_value_type(const checked_result<T> & t) :
280 m_flag(to_flag(t))
281 {}
282 constexpr operator std::uint8_t () const {
283 return static_cast<std::uint8_t>(m_flag);
284 }
285 };
286
287 // integers multiplication
288 template<class T>
289 typename std::enable_if<
290 std::is_integral<T>::value,
291 checked_result<T>
292 >::type
293 constexpr inline operator*(
294 const checked_result<T> & t,
295 const checked_result<T> & u
296 ){
297 using value_type = product_value_type;
298 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
299
300 constexpr const enum value_type::flag result[order * order] = {
301 // t == less_than_min
302 //{
303 // u == ...
304 value_type::greater_than_max, // less_than_min,
305 value_type::greater_than_max, // less_than_zero,
306 value_type::zero, // zero,
307 value_type::less_than_min, // greater_than_zero,
308 value_type::less_than_min, // greater than max,
309 value_type::indeterminate, // indeterminate,
310 //},
311 // t == less_than_zero,
312 //{
313 // u == ...
314 value_type::greater_than_max, // less_than_min,
315 value_type::greater_than_zero, // less_than_zero,
316 value_type::zero, // zero,
317 value_type::less_than_zero, // greater_than_zero,
318 value_type::less_than_min, // greater than max,
319 value_type::indeterminate, // indeterminate,
320 //},
321 // t == zero,
322 //{
323 // u == ...
324 value_type::zero, // less_than_min,
325 value_type::zero, // less_than_zero,
326 value_type::zero, // zero,
327 value_type::zero, // greater_than_zero,
328 value_type::zero, // greater than max,
329 value_type::indeterminate, // indeterminate,
330 //},
331 // t == greater_than_zero,
332 //{
333 // u == ...
334 value_type::less_than_min, // less_than_min,
335 value_type::less_than_zero, // less_than_zero,
336 value_type::zero, // zero,
337 value_type::greater_than_zero, // greater_than_zero,
338 value_type::greater_than_max, // greater than max,
339 value_type::indeterminate, // indeterminate,
340 //},
341 // t == greater_than_max
342 //{
343 value_type::less_than_min, // less_than_min,
344 value_type::less_than_min, // less_than_zero,
345 value_type::zero, // zero,
346 value_type::greater_than_max, // greater_than_zero,
347 value_type::greater_than_max, // greater than max,
348 value_type::indeterminate, // indeterminate,
349 //},
350 // t == indeterminate
351 //{
352 value_type::indeterminate, // less_than_min,
353 value_type::indeterminate, // less_than_zero,
354 value_type::indeterminate, // zero,
355 value_type::indeterminate, // greater_than_zero,
356 value_type::indeterminate, // greater than max,
357 value_type::indeterminate, // indeterminate,
358 //}
359 };
360
361 const value_type tx(t);
362 const value_type ux(u);
363
364 switch(result[tx * order + ux]){
365 case value_type::less_than_min:
366 return safe_numerics_error::negative_overflow_error;
367 case value_type::zero:
368 return T(0);
369 case value_type::greater_than_max:
370 return safe_numerics_error::positive_overflow_error;
371 case value_type::less_than_zero:
372 case value_type::greater_than_zero:
373 return checked::multiply<T>(t, u);
374 case value_type::indeterminate:
375 return safe_numerics_error::range_error;
376 default:
377 assert(false);
378 }
379 return checked_result<T>(0); // to suppress msvc warning
380 }
381
382 // integers division
383 template<class T>
384 typename std::enable_if<
385 std::is_integral<T>::value,
386 checked_result<T>
387 >::type
388 constexpr inline operator/(
389 const checked_result<T> & t,
390 const checked_result<T> & u
391 ){
392 using value_type = product_value_type;
393 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
394
395 constexpr const enum value_type::flag result[order * order] = {
396 // t == less_than_min
397 //{
398 // u == ...
399 value_type::indeterminate, // less_than_min,
400 value_type::greater_than_max, // less_than_zero,
401 value_type::less_than_min, // zero,
402 value_type::less_than_min, // greater_than_zero,
403 value_type::less_than_min, // greater than max,
404 value_type::indeterminate, // indeterminate,
405 //},
406 // t == less_than_zero,
407 //{
408 // u == ...
409 value_type::zero, // less_than_min,
410 value_type::greater_than_zero, // less_than_zero,
411 value_type::less_than_min, // zero,
412 value_type::less_than_zero, // greater_than_zero,
413 value_type::zero, // greater than max,
414 value_type::indeterminate, // indeterminate,
415 //},
416 // t == zero,
417 //{
418 // u == ...
419 value_type::zero, // less_than_min,
420 value_type::zero, // less_than_zero,
421 value_type::indeterminate, // zero,
422 value_type::zero, // greater_than_zero,
423 value_type::zero, // greater than max,
424 value_type::indeterminate, // indeterminate,
425 //},
426 // t == greater_than_zero,
427 //{
428 // u == ...
429 value_type::zero, // less_than_min,
430 value_type::less_than_zero, // less_than_zero,
431 value_type::greater_than_max, // zero,
432 value_type::greater_than_zero, // greater_than_zero,
433 value_type::zero, // greater than max,
434 value_type::indeterminate, // indeterminate,
435 //},
436 // t == greater_than_max
437 //{
438 value_type::less_than_min, // less_than_min,
439 value_type::less_than_min, // less_than_zero,
440 value_type::greater_than_max, // zero,
441 value_type::greater_than_max, // greater_than_zero,
442 value_type::indeterminate, // greater than max,
443 value_type::indeterminate, // indeterminate,
444 //},
445 // t == indeterminate
446 //{
447 value_type::indeterminate, // less_than_min,
448 value_type::indeterminate, // less_than_zero,
449 value_type::indeterminate, // zero,
450 value_type::indeterminate, // greater_than_zero,
451 value_type::indeterminate, // greater than max,
452 value_type::indeterminate, // indeterminate,
453 //}
454 };
455
456 const value_type tx(t);
457 const value_type ux(u);
458
459 switch(result[tx * order + ux]){
460 case value_type::less_than_min:
461 return safe_numerics_error::negative_overflow_error;
462 case value_type::zero:
463 return 0;
464 case value_type::greater_than_max:
465 return safe_numerics_error::positive_overflow_error;
466 case value_type::less_than_zero:
467 case value_type::greater_than_zero:
468 return checked::divide<T>(t, u);
469 case value_type::indeterminate:
470 return safe_numerics_error::range_error;
471 default:
472 assert(false);
473 }
474 return checked_result<T>(0); // to suppress msvc warning
475 }
476
477 // integers modulus
478 template<class T>
479 typename std::enable_if<
480 std::is_integral<T>::value,
481 checked_result<T>
482 >::type
483 constexpr inline operator%(
484 const checked_result<T> & t,
485 const checked_result<T> & u
486 ){
487 using value_type = product_value_type;
488 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
489
490 constexpr const enum value_type::flag result[order * order] = {
491 // t == less_than_min
492 //{
493 // u == ...
494 value_type::indeterminate, // less_than_min,
495 value_type::z_value, // less_than_zero,
496 value_type::indeterminate, // zero,
497 value_type::z_value, // greater_than_zero,
498 value_type::indeterminate, // greater than max,
499 value_type::indeterminate, // indeterminate,
500 //},
501 // t == less_than_zero,
502 //{
503 // u == ...
504 value_type::t_value, // less_than_min,
505 value_type::greater_than_zero, // less_than_zero,
506 value_type::indeterminate, // zero,
507 value_type::less_than_zero, // greater_than_zero,
508 value_type::t_value, // greater than max,
509 value_type::indeterminate, // indeterminate,
510 //},
511 // t == zero,
512 //{
513 // u == ...
514 value_type::zero, // less_than_min,
515 value_type::zero, // less_than_zero,
516 value_type::indeterminate, // zero,
517 value_type::zero, // greater_than_zero,
518 value_type::zero, // greater than max,
519 value_type::indeterminate, // indeterminate,
520 //},
521 // t == greater_than_zero,
522 //{
523 // u == ...
524 value_type::t_value, // less_than_min,
525 value_type::less_than_zero, // less_than_zero,
526 value_type::indeterminate, // zero,
527 value_type::greater_than_zero, // greater_than_zero,
528 value_type::t_value, // greater than max,
529 value_type::indeterminate, // indeterminate,
530 //},
531 // t == greater_than_max
532 //{
533 value_type::indeterminate, // less_than_min,
534 value_type::u_value, // less_than_zero,
535 value_type::indeterminate, // zero,
536 value_type::u_value, // greater_than_zero,
537 value_type::indeterminate, // greater than max,
538 value_type::indeterminate, // indeterminate,
539 //},
540 // t == indeterminate
541 //{
542 value_type::indeterminate, // less_than_min,
543 value_type::indeterminate, // less_than_zero,
544 value_type::indeterminate, // zero,
545 value_type::indeterminate, // greater_than_zero,
546 value_type::indeterminate, // greater than max,
547 value_type::indeterminate, // indeterminate,
548 //}
549 };
550
551 const value_type tx(t);
552 const value_type ux(u);
553
554 switch(result[tx * order + ux]){
555 case value_type::zero:
556 return 0;
557 case value_type::less_than_zero:
558 case value_type::greater_than_zero:
559 return checked::modulus<T>(t, u);
560 case value_type::indeterminate:
561 return safe_numerics_error::range_error;
562 case value_type::t_value:
563 return t;
564 case value_type::u_value:
565 return checked::subtract<T>(u, 1);
566 case value_type::z_value:
567 return checked::subtract<T>(1, u);
568 case value_type::greater_than_max:
569 case value_type::less_than_min:
570 default:
571 assert(false);
572 }
573 // suppress msvc warning
574 return checked_result<T>(0);
575 }
576
577 // comparison operators
578
579 template<class T>
580 constexpr boost::logic::tribool operator<(
581 const checked_result<T> & t,
582 const checked_result<T> & u
583 ){
584 using value_type = sum_value_type;
585 constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
586
587 // the question arises about how to order values of type greater_than_min.
588 // that is: what should greater_than_min < greater_than_min return.
589 //
590 // a) return indeterminate because we're talking about the "true" values for
591 // which greater_than_min is a placholder.
592 //
593 // b) return false because the two values are "equal"
594 //
595 // for our purposes, a) seems the better interpretation.
596
597 enum class result_type : std::uint8_t {
598 runtime,
599 false_value,
600 true_value,
601 indeterminate,
602 };
603 constexpr const result_type resultx[order * order]{
604 // t == known_value
605 //{
606 // u == ...
607 result_type::runtime, // known_value,
608 result_type::false_value, // less_than_min,
609 result_type::true_value, // greater_than_max,
610 result_type::indeterminate, // indeterminate,
611 //},
612 // t == less_than_min
613 //{
614 // u == ...
615 result_type::true_value, // known_value,
616 result_type::indeterminate, // less_than_min, see above argument
617 result_type::true_value, // greater_than_max,
618 result_type::indeterminate, // indeterminate,
619 //},
620 // t == greater_than_max
621 //{
622 // u == ...
623 result_type::false_value, // known_value,
624 result_type::false_value, // less_than_min,
625 result_type::indeterminate, // greater_than_max, see above argument
626 result_type::indeterminate, // indeterminate,
627 //},
628 // t == indeterminate
629 //{
630 // u == ...
631 result_type::indeterminate, // known_value,
632 result_type::indeterminate, // less_than_min,
633 result_type::indeterminate, // greater_than_max,
634 result_type::indeterminate, // indeterminate,
635 //},
636 };
637
638 const value_type tx(t);
639 const value_type ux(u);
640
641 switch(resultx[tx * order + ux]){
642 case result_type::runtime:
643 return static_cast<const T &>(t) < static_cast<const T &>(u);
644 case result_type::false_value:
645 return false;
646 case result_type::true_value:
647 return true;
648 case result_type::indeterminate:
649 return boost::logic::indeterminate;
650 default:
651 assert(false);
652 }
653 return true;
654 }
655
656 template<class T>
657 constexpr boost::logic::tribool
658 operator>=(
659 const checked_result<T> & t,
660 const checked_result<T> & u
661 ){
662 return !(t < u);
663 }
664
665 template<class T>
666 constexpr boost::logic::tribool
667 operator>(
668 const checked_result<T> & t,
669 const checked_result<T> & u
670 ){
671 return u < t;
672 }
673
674 template<class T>
675 constexpr boost::logic::tribool
676 operator<=(
677 const checked_result<T> & t,
678 const checked_result<T> & u
679 ){
680 return !(u < t);
681 }
682
683 template<class T>
684 constexpr boost::logic::tribool
685 operator==(
686 const checked_result<T> & t,
687 const checked_result<T> & u
688 ){
689 using value_type = sum_value_type;
690 constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
691
692 enum class result_type : std::uint8_t {
693 runtime,
694 false_value,
695 true_value,
696 indeterminate,
697 };
698
699 constexpr const result_type result[order * order]{
700 // t == known_value
701 //{
702 // u == ...
703 result_type::runtime, // known_value,
704 result_type::false_value, // less_than_min,
705 result_type::false_value, // greater_than_max,
706 result_type::indeterminate, // indeterminate,
707 //},
708 // t == less_than_min
709 //{
710 // u == ...
711 result_type::false_value, // known_value,
712 result_type::indeterminate, // less_than_min,
713 result_type::false_value, // greater_than_max,
714 result_type::indeterminate, // indeterminate,
715 //},
716 // t == greater_than_max
717 //{
718 // u == ...
719 result_type::false_value, // known_value,
720 result_type::false_value, // less_than_min,
721 result_type::indeterminate, // greater_than_max,
722 result_type::indeterminate, // indeterminate,
723 //},
724 // t == indeterminate
725 //{
726 // u == ...
727 result_type::indeterminate, // known_value,
728 result_type::indeterminate, // less_than_min,
729 result_type::indeterminate, // greater_than_max,
730 result_type::indeterminate, // indeterminate,
731 //},
732 };
733
734 const value_type tx(t);
735 const value_type ux(u);
736
737 switch(result[tx * order + ux]){
738 case result_type::runtime:
739 return static_cast<const T &>(t) == static_cast<const T &>(u);
740 case result_type::false_value:
741 return false;
742 case result_type::true_value:
743 return true;
744 case result_type::indeterminate:
745 return boost::logic::indeterminate;
746 default:
747 assert(false);
748 }
749 // suppress msvc warning - not all control paths return a value
750 return false;
751 }
752
753 template<class T>
754 constexpr boost::logic::tribool
755 operator!=(
756 const checked_result<T> & t,
757 const checked_result<T> & u
758 ){
759 return ! (t == u);
760 }
761
762 template<class T>
763 typename std::enable_if<
764 std::is_integral<T>::value,
765 checked_result<T>
766 >::type
767 constexpr inline operator>>(
768 const checked_result<T> & t,
769 const checked_result<T> & u
770 );
771
772 template<class T>
773 typename std::enable_if<
774 std::is_integral<T>::value,
775 checked_result<T>
776 >::type
777 constexpr inline operator~(
778 const checked_result<T> & t
779 ){
780 // assert(false);
781 return ~t.m_r;
782 }
783
784 template<class T>
785 typename std::enable_if<
786 std::is_integral<T>::value,
787 checked_result<T>
788 >::type
789 constexpr inline operator<<(
790 const checked_result<T> & t,
791 const checked_result<T> & u
792 ){
793 using value_type = product_value_type;
794 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
795
796 constexpr const std::uint8_t result[order * order] = {
797 // t == less_than_min
798 //{
799 // u == ...
800 1, // -1, // less_than_min,
801 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
802 2, // safe_numerics_error::negative_overflow_error, // zero,
803 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
804 2, // safe_numerics_error::negative_overflow_error, // greater than max,
805 1, // safe_numerics_error::range_error, // indeterminate,
806 //},
807 // t == less_than_zero,
808 //{
809 // u == ...
810 3, // -1, // less_than_min,
811 4, // - (-t >> -u), // less_than_zero,
812 5, // safe_numerics_error::negative_overflow_error, // zero,
813 6, // - (-t << u), // greater_than_zero,
814 2, // safe_numerics_error::negative_overflow_error, // greater than max,
815 1, // safe_numerics_error::range_error, // indeterminate,
816 //},
817 // t == zero,
818 //{
819 // u == ...
820 3, // 0 // less_than_min,
821 3, // 0 // less_than_zero,
822 3, // 0, // zero,
823 3, // 0, // greater_than_zero,
824 3, // 0, // greater than max,
825 3, // safe_numerics_error::range_error, // indeterminate,
826 //},
827 // t == greater_than_zero,
828 //{
829 // u == ...
830 3, // 0, // less_than_min,
831 7, // t << -u, // less_than_zero,
832 5, // t, // zero,
833 8, // t << u // greater_than_zero,
834 9, // safe_numerics_error::positive_overflow_error, // greater than max,
835 1, // safe_numerics_error::range_error, // indeterminate,
836 //},
837 // t == greater_than_max
838 //{
839 // u == ...
840 1, // safe_numerics_error::range_error, // less_than_min,
841 9, // safe_numerics_error::positive_overflow_error), // less_than_zero,
842 9, // safe_numerics_error::positive_overflow_error, // zero,
843 9, // safe_numerics_error::positive_overflow_error), // greater_than_zero,
844 9, // safe_numerics_error::positive_overflow_error, // greater than max,
845 1, // safe_numerics_error::range_error, // indeterminate,
846 //},
847 // t == indeterminate
848 //{
849 1, // safe_numerics_error::range_error, // indeterminate,
850 1, // safe_numerics_error::range_error, // indeterminate,
851 1, // safe_numerics_error::range_error, // indeterminate,
852 1, // safe_numerics_error::range_error, // indeterminate,
853 1, // safe_numerics_error::range_error, // indeterminate,
854 1, // safe_numerics_error::range_error, // indeterminate,
855 //}
856 };
857
858 const value_type tx(t);
859 const value_type ux(u);
860 assert(tx * order + ux < order * order);
861
862 // I had a switch(i) statment here - but it results in an ICE
863 // on multiple versions of gcc. So make the equivalent in
864 // nested if statments - should be the same (more or less)
865 // performancewise.
866 const unsigned int i = result[tx * order + ux];
867 assert(i <= 9);
868 if(1 == i){
869 return safe_numerics_error::range_error;
870 }
871 else
872 if(2 == i){
873 return safe_numerics_error::negative_overflow_error;
874 }
875 else
876 if(3 == i){
877 return checked_result<T>(0);
878 // the following gymnastics are to handle the case where
879 // a value is changed from a negative to a positive number.
880 // For example, and 8 bit number t == -128. Then -t also
881 // equals -128 since 128 cannot be held in an 8 bit signed
882 // integer.
883 }
884 else
885 if(4 == i){ // - (-t >> -u)
886 assert(static_cast<bool>(t < checked_result<T>(0)));
887 assert(static_cast<bool>(u < checked_result<T>(0)));
888 return t >> -u;
889 }
890 else
891 if(5 == i){
892 return t;
893 }
894 else
895 if(6 == i){ // - (-t << u)
896 assert(static_cast<bool>(t < checked_result<T>(0)));
897 assert(static_cast<bool>(u > checked_result<T>(0)));
898 const checked_result<T> temp_t = t * checked_result<T>(2);
899 const checked_result<T> temp_u = u - checked_result<T>(1);
900 return - (-temp_t << temp_u);
901 }
902 else
903 if(7 == i){ // t >> -u
904 assert(static_cast<bool>(t > checked_result<T>(0)));
905 assert(static_cast<bool>(u < checked_result<T>(0)));
906 return t >> -u;
907 }
908 else
909 if(8 == i){ // t << u
910 assert(static_cast<bool>(t > checked_result<T>(0)));
911 assert(static_cast<bool>(u > checked_result<T>(0)));
912 checked_result<T> r = checked::left_shift<T>(t, u);
913 return (r.m_e == safe_numerics_error::shift_too_large)
914 ? checked_result<T>(safe_numerics_error::positive_overflow_error)
915 : r;
916 }
917 else
918 if(9 == i){
919 return safe_numerics_error::positive_overflow_error;
920 }
921 else{
922 assert(false);
923 };
924 return checked_result<T>(0); // to suppress msvc warning
925 }
926
927 template<class T>
928 typename std::enable_if<
929 std::is_integral<T>::value,
930 checked_result<T>
931 >::type
932 constexpr inline operator>>(
933 const checked_result<T> & t,
934 const checked_result<T> & u
935 ){
936 using value_type = product_value_type;
937 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
938
939 const std::uint8_t result[order * order] = {
940 // t == less_than_min
941 //{
942 // u == ...
943 2, // safe_numerics_error::negative_overflow_error, // less_than_min,
944 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
945 2, // safe_numerics_error::negative_overflow_error, // zero,
946 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
947 1, // safe_numerics_error::range_error, // greater than max,
948 1, // safe_numerics_error::range_error, // indeterminate,
949 //},
950 // t == less_than_zero,
951 //{
952 // u == ...
953 2, // safe_numerics_error::negative_overflow_error // less_than_min,
954 4, // - (-t << -u), // less_than_zero,
955 5, // safe_numerics_error::negative_overflow_error. // zero,
956 6, // - (-t >> u), // greater_than_zero,
957 3, // 0, ? or -1 // greater than max,
958 1, // safe_numerics_error::range_error, // indeterminate,
959 //},
960 // t == zero,
961 //{
962 // u == ...
963 3, // 0 // less_than_min,
964 3, // 0 // less_than_zero,
965 3, // 0, // zero,
966 3, // 0, // greater_than_zero,
967 3, // 0, // greater than max,
968 3, // safe_numerics_error::range_error, // indeterminate,
969 //},
970 // t == greater_than_zero,
971 //{
972 // u == ...
973 9, // safe_numerics_error::positive_overflow_error // less_than_min,
974 7, // t << -u, // less_than_zero,
975 5, // t, // zero,
976 8, // t >> u // greater_than_zero,
977 3, // 0, // greater than max,
978 1, // safe_numerics_error::range_error, // indeterminate,
979 //},
980 // t == greater_than_max
981 //{
982 // u == ...
983 9, // safe_numerics_error::positive_overflow_error, // less_than_min,
984 9, // safe_numerics_error::positive_overflow_error, // less_than_zero,
985 9, // safe_numerics_error::positive_overflow_error, // zero,
986 9, // safe_numerics_error::positive_overflow_error, // greater_than_zero,
987 1, // safe_numerics_error::range_error, // greater than max,
988 1, // safe_numerics_error::range_error, // indeterminate,
989 //},
990 // t == indeterminate
991 //{
992 1, // safe_numerics_error::range_error, // indeterminate,
993 1, // safe_numerics_error::range_error, // indeterminate,
994 1, // safe_numerics_error::range_error, // indeterminate,
995 1, // safe_numerics_error::range_error, // indeterminate,
996 1, // safe_numerics_error::range_error, // indeterminate,
997 1, // safe_numerics_error::range_error, // indeterminate,
998 //}
999 };
1000
1001 const value_type tx(t);
1002 const value_type ux(u);
1003 assert(tx * order + ux < order * order);
1004
1005 // I had a switch(i) statment here - but it results in an ICE
1006 // on multiple versions of gcc. So make the equivalent in
1007 // nested if statments - should be the same (more or less)
1008 // performancewise.
1009 const unsigned int i = result[tx * order + ux];
1010 assert(i <= 9);
1011 if(1 == i){
1012 return safe_numerics_error::range_error;
1013 }
1014 else
1015 if(2 == i){
1016 return safe_numerics_error::negative_overflow_error;
1017 }
1018 else
1019 if(3 == i){
1020 return checked_result<T>(0);
1021 }
1022 else
1023 if(4 == i){ // - (-t << -u)
1024 assert(static_cast<bool>(t < checked_result<T>(0)));
1025 assert(static_cast<bool>(u < checked_result<T>(0)));
1026 return t << -u;
1027 }
1028 else
1029 if(5 == i){
1030 return t;
1031 }
1032 else
1033 if(6 == i){ // - (-t >> u)
1034 assert(static_cast<bool>(t < checked_result<T>(0)));
1035 assert(static_cast<bool>(u > checked_result<T>(0)));
1036 const checked_result<T> temp_t = t / checked_result<T>(2);
1037 const checked_result<T> temp_u = u - checked_result<T>(1);
1038 return - (-temp_t >> temp_u);
1039 }
1040 else
1041 if(7 == i){ // t << -u,
1042 assert(static_cast<bool>(t > checked_result<T>(0)));
1043 assert(static_cast<bool>(u < checked_result<T>(0)));
1044 return t << -u;
1045 }
1046 else
1047 if(8 == i){ // t >> u
1048 assert(static_cast<bool>(t > checked_result<T>(0)));
1049 assert(static_cast<bool>(u > checked_result<T>(0)));
1050 checked_result<T> r = checked::right_shift<T>(t, u);
1051 return (r.m_e == safe_numerics_error::shift_too_large)
1052 ? checked_result<T>(0)
1053 : r;
1054 }
1055 else
1056 if(9 == i){
1057 return safe_numerics_error::positive_overflow_error;
1058 }
1059 else{
1060 assert(false);
1061 };
1062 return checked_result<T>(0); // to suppress msvc warning
1063 }
1064
1065 template<class T>
1066 typename std::enable_if<
1067 std::is_integral<T>::value,
1068 checked_result<T>
1069 >::type
1070 constexpr inline operator|(
1071 const checked_result<T> & t,
1072 const checked_result<T> & u
1073 ){
1074 return
1075 t.exception() || u.exception()
1076 ? checked_result<T>(safe_numerics_error::range_error)
1077 : checked::bitwise_or<T>(
1078 static_cast<T>(t),
1079 static_cast<T>(u)
1080 );
1081 }
1082 template<class T>
1083 typename std::enable_if<
1084 std::is_integral<T>::value,
1085 checked_result<T>
1086 >::type
1087 constexpr inline operator^(
1088 const checked_result<T> & t,
1089 const checked_result<T> & u
1090 ){
1091 return
1092 t.exception() || u.exception()
1093 ? checked_result<T>(safe_numerics_error::range_error)
1094 : checked::bitwise_xor<T>(
1095 static_cast<T>(t),
1096 static_cast<T>(u)
1097 );
1098 }
1099
1100 template<class T>
1101 typename std::enable_if<
1102 std::is_integral<T>::value,
1103 checked_result<T>
1104 >::type
1105 constexpr inline operator&(
1106 const checked_result<T> & t,
1107 const checked_result<T> & u
1108 ){
1109 return
1110 t.exception() || u.exception()
1111 ? checked_result<T>(safe_numerics_error::range_error)
1112 : checked::bitwise_and<T>(
1113 static_cast<T>(t),
1114 static_cast<T>(u)
1115 );
1116 }
1117
1118 } // safe_numerics
1119 } // boost
1120
1121 #include <iosfwd>
1122
1123 namespace std {
1124
1125 template<typename CharT, typename Traits, typename R>
1126 inline std::basic_ostream<CharT, Traits> & operator<<(
1127 std::basic_ostream<CharT, Traits> & os,
1128 const boost::safe_numerics::checked_result<R> & r
1129 ){
1130 bool e = r.exception();
1131 os << e;
1132 if(!e)
1133 os << static_cast<R>(r);
1134 else
1135 os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
1136 return os;
1137 }
1138
1139 template<typename CharT, typename Traits>
1140 inline std::basic_ostream<CharT, Traits> & operator<<(
1141 std::basic_ostream<CharT, Traits> & os,
1142 const boost::safe_numerics::checked_result<signed char> & r
1143 ){
1144 bool e = r.exception();
1145 os << e;
1146 if(! e)
1147 os << static_cast<std::int16_t>(r);
1148 else
1149 os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
1150 return os;
1151 }
1152
1153 template<typename CharT, typename Traits, typename R>
1154 inline std::basic_istream<CharT, Traits> & operator>>(
1155 std::basic_istream<CharT, Traits> & is,
1156 boost::safe_numerics::checked_result<R> & r
1157 ){
1158 bool e;
1159 is >> e;
1160 if(!e)
1161 is >> static_cast<R>(r);
1162 else
1163 is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
1164 return is;
1165 }
1166
1167 template<typename CharT, typename Traits>
1168 inline std::basic_istream<CharT, Traits> & operator>>(
1169 std::basic_istream<CharT, Traits> & is,
1170 boost::safe_numerics::checked_result<signed char> & r
1171 ){
1172 bool e;
1173 is >> e;
1174 if(!e){
1175 std::int16_t i;
1176 is >> i;
1177 r.m_contents.m_r = static_cast<signed char>(i);
1178 }
1179 else
1180 is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
1181 return is;
1182 }
1183
1184 } // std
1185
1186 /////////////////////////////////////////////////////////////////
1187 // numeric limits for checked<R>
1188
1189 #include <limits>
1190
1191 namespace std {
1192
1193 template<class R>
1194 class numeric_limits<boost::safe_numerics::checked_result<R> >
1195 : public std::numeric_limits<R>
1196 {
1197 using this_type = boost::safe_numerics::checked_result<R>;
1198 public:
1199 constexpr static this_type min() noexcept {
1200 return this_type(std::numeric_limits<R>::min());
1201 }
1202 constexpr static this_type max() noexcept {
1203 return this_type(std::numeric_limits<R>::max());
1204 }
1205 };
1206
1207 } // std
1208
1209 #endif // BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS