• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BOOST_NUMERIC_CHECKED_RESULT
2 #define BOOST_NUMERIC_CHECKED_RESULT
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 // contains operations for doing checked aritmetic on NATIVE
11 // C++ types.
12 #include <cassert>
13 #include <type_traits> // is_convertible
14 #include "exception.hpp"
15 
16 namespace boost {
17 namespace safe_numerics {
18 
19 template<typename R>
20 struct checked_result {
21     const safe_numerics_error m_e;
22     const union {
23         R m_r;
24         char const * m_msg;
25     };
26 
27     // don't permit construction without initial value;
28     checked_result() = delete;
29 
30     // note: I implemented the following non-default copy and move
31     // constructors because I thought I needed to do this in order
32     // to make them constexpr.  Turns out though that doing this creates
33     // a syntax error because the assignment results in error due
34     // to assignment "outside of object lifetime".  I think this could
35     // be addressed by replacing the anonymous union above with a
36     // named union.  This would create some syntax changes which would
37     // ripple through some parts of th program.  So for now, we'll just
38     // rely on the default copy and move constructors.
39     #if 0
40     // copy constructor
41     constexpr /*explicit*/ checked_result(const checked_result & r) noexpect :
42         m_e(r.m_e)
43     {
44         if(safe_numerics_error::success == r.m_e)
45             m_r = r.m_r;
46         else
47             m_msg = r.m_msg;
48     }
49 
50     // move constructor
51     constexpr /*explicit*/ checked_result(checked_result && r) noexcept :
52         m_e(r.m_e)
53     {
54         if(safe_numerics_error::success == r.m_e)
55             m_r = r.m_r;
56         else
57             m_msg = r.m_msg;
58     }
59     #endif
60     checked_result(const checked_result & r) = default;
61     checked_result(checked_result && r) = default;
62 
checked_resultboost::safe_numerics::checked_result63     constexpr /*explicit*/ checked_result(const R & r) :
64         m_e(safe_numerics_error::success),
65         m_r(r)
66     {}
67     #if 0
68     template<typename T>
69     constexpr /*explicit*/ checked_result(const T & t) noexcept :
70         m_e(safe_numerics_error::success),
71         m_r(t)
72     {}
73     #endif
checked_resultboost::safe_numerics::checked_result74     constexpr /*explicit*/ checked_result(
75         const safe_numerics_error & e,
76         const char * msg = ""
77     )  noexcept :
78         m_e(e),
79         m_msg(msg)
80     {
81         assert(m_e != safe_numerics_error::success);
82     }
83     // permit construct from another checked result type
84     template<typename T>
checked_resultboost::safe_numerics::checked_result85     constexpr /*explicit*/ checked_result(const checked_result<T> & t) noexcept :
86         m_e(t.m_e)
87     {
88         static_assert(
89             std::is_convertible<T, R>::value,
90             "T must be convertible to R"
91         );
92         if(safe_numerics_error::success == t.m_e)
93             m_r = t.m_r;
94         else
95             m_msg = t.m_msg;
96     }
exceptionboost::safe_numerics::checked_result97     constexpr bool exception() const {
98         return m_e != safe_numerics_error::success;
99     }
100 
101     // accesors
operator Rboost::safe_numerics::checked_result102     constexpr operator R() const  noexcept{
103         // don't assert here.  Let the library catch these errors
104         assert(! exception());
105         return m_r;
106     }
107 
operator safe_numerics_errorboost::safe_numerics::checked_result108     constexpr operator safe_numerics_error () const  noexcept{
109         // note that this is a legitimate operation even when
110         // the operation was successful - it will return success
111         return m_e;
112     }
operator const char*boost::safe_numerics::checked_result113     constexpr operator const char *() const  noexcept{
114         assert(exception());
115         return m_msg;
116     }
117 
118     // disallow assignment
119     checked_result & operator=(const checked_result &) = delete;
120 };
121 
122 #if 0
123 template<typename R>
124 constexpr checked_result<R> make_checked_result(
125     const safe_numerics_error & e,
126     char const * const & m
127 )  noexcept {
128     return checked_result<R>(e, m);
129 }
130 #endif
131 
132 template <class R>
133 class make_checked_result {
134 public:
135     template<safe_numerics_error E>
invoke(char const * const & m)136     constexpr static checked_result<R> invoke(
137         char const * const & m
138     ) noexcept {
139         return checked_result<R>(E, m);
140     }
141 };
142 
143 } // safe_numerics
144 } // boost
145 
146 #endif  // BOOST_NUMERIC_CHECKED_RESULT
147