• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
display(const boost::safe_numerics::checked_result<T> & c)37 constexpr 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>
to_flagboost::safe_numerics::sum_value_type77     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>
sum_value_typeboost::safe_numerics::sum_value_type92     constexpr sum_value_type(const checked_result<T> & t) :
93         m_flag(to_flag(t))
94     {}
operator std::uint8_tboost::safe_numerics::sum_value_type95     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
operator +(const checked_result<T> & t,const checked_result<T> & u)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
operator +(const checked_result<T> & t)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
operator -(const checked_result<T> & t,const checked_result<T> & u)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
operator -(const checked_result<T> & t)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>
to_flagboost::safe_numerics::product_value_type260     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>
product_value_typeboost::safe_numerics::product_value_type279     constexpr product_value_type(const checked_result<T> & t) :
280         m_flag(to_flag(t))
281     {}
operator std::uint8_tboost::safe_numerics::product_value_type282     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
operator *(const checked_result<T> & t,const checked_result<T> & u)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
operator /(const checked_result<T> & t,const checked_result<T> & u)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
operator %(const checked_result<T> & t,const checked_result<T> & u)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>
operator <(const checked_result<T> & t,const checked_result<T> & u)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
operator >=(const checked_result<T> & t,const checked_result<T> & u)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
operator >(const checked_result<T> & t,const checked_result<T> & u)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
operator <=(const checked_result<T> & t,const checked_result<T> & u)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
operator ==(const checked_result<T> & t,const checked_result<T> & u)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
operator !=(const checked_result<T> & t,const checked_result<T> & u)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
operator ~(const checked_result<T> & t)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
operator <<(const checked_result<T> & t,const checked_result<T> & u)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
operator >>(const checked_result<T> & t,const checked_result<T> & u)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
operator |(const checked_result<T> & t,const checked_result<T> & u)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
operator ^(const checked_result<T> & t,const checked_result<T> & u)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
operator &(const checked_result<T> & t,const checked_result<T> & u)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>
operator <<(std::basic_ostream<CharT,Traits> & os,const boost::safe_numerics::checked_result<R> & 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     if(!r.exception())
1131         os << static_cast<R>(r);
1132     else
1133         os << std::error_code(r.m_e).message() << ':' << r.m_msg;
1134     return os;
1135 }
1136 
1137 template<typename CharT, typename Traits>
operator <<(std::basic_ostream<CharT,Traits> & os,const boost::safe_numerics::checked_result<signed char> & r)1138 inline std::basic_ostream<CharT, Traits> & operator<<(
1139     std::basic_ostream<CharT, Traits> & os,
1140     const boost::safe_numerics::checked_result<signed char> & r
1141 ){
1142     if(! r.exception())
1143         os << static_cast<std::int16_t>(r);
1144     else
1145         os << std::error_code(r.m_e).message() << ':' << r.m_msg;
1146     return os;
1147 }
1148 
1149 template<typename CharT, typename Traits>
operator <<(std::basic_ostream<CharT,Traits> & os,const boost::safe_numerics::checked_result<unsigned char> & r)1150 inline std::basic_ostream<CharT, Traits> & operator<<(
1151     std::basic_ostream<CharT, Traits> & os,
1152     const boost::safe_numerics::checked_result<unsigned char> & r
1153 ){
1154     if(! r.exception())
1155         os << static_cast<std::uint16_t>(r);
1156     else
1157         os << std::error_code(r.m_e).message() << ':' << r.m_msg;
1158     return os;
1159 }
1160 
1161 template<typename CharT, typename Traits, typename R>
operator >>(std::basic_istream<CharT,Traits> & is,boost::safe_numerics::checked_result<R> & r)1162 inline std::basic_istream<CharT, Traits> & operator>>(
1163     std::basic_istream<CharT, Traits> & is,
1164     boost::safe_numerics::checked_result<R> & r
1165 ){
1166     is >> r.m_r;
1167     return is;
1168 }
1169 
1170 template<typename CharT, typename Traits, typename R>
operator >>(std::basic_istream<CharT,Traits> & is,boost::safe_numerics::checked_result<signed char> & r)1171 inline std::basic_istream<CharT, Traits> & operator>>(
1172     std::basic_istream<CharT, Traits> & is,
1173     boost::safe_numerics::checked_result<signed char> & r
1174 ){
1175     std::int16_t i;
1176     is >> i;
1177     r.m_r = i;
1178     return is;
1179 }
1180 
1181 template<typename CharT, typename Traits, typename R>
operator >>(std::basic_istream<CharT,Traits> & is,boost::safe_numerics::checked_result<unsigned char> & r)1182 inline std::basic_istream<CharT, Traits> & operator>>(
1183     std::basic_istream<CharT, Traits> & is,
1184     boost::safe_numerics::checked_result<unsigned char> & r
1185 ){
1186     std::uint16_t i;
1187     is >> i;
1188     r.m_r = i;
1189     return is;
1190 }
1191 
1192 } // std
1193 
1194 /////////////////////////////////////////////////////////////////
1195 // numeric limits for checked<R>
1196 
1197 #include <limits>
1198 
1199 namespace std {
1200 
1201 template<class R>
1202 class numeric_limits<boost::safe_numerics::checked_result<R> >
1203     : public std::numeric_limits<R>
1204 {
1205     using this_type = boost::safe_numerics::checked_result<R>;
1206 public:
min()1207     constexpr static this_type min() noexcept {
1208         return this_type(std::numeric_limits<R>::min());
1209     }
max()1210     constexpr static this_type max() noexcept {
1211         return this_type(std::numeric_limits<R>::max());
1212     }
1213 };
1214 
1215 } // std
1216 
1217 #endif  // BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
1218