]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
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 | |
20effc67 | 60 | |
92f5a8d4 TL |
61 | checked_result(const checked_result & r) = default; |
62 | checked_result(checked_result && r) = default; | |
63 | ||
20effc67 | 64 | constexpr /*explicit*/ checked_result(const R & r) noexcept : |
92f5a8d4 TL |
65 | m_e(safe_numerics_error::success), |
66 | m_r(r) | |
67 | {} | |
20effc67 | 68 | |
92f5a8d4 TL |
69 | constexpr /*explicit*/ checked_result( |
70 | const safe_numerics_error & e, | |
71 | const char * msg = "" | |
72 | ) noexcept : | |
73 | m_e(e), | |
74 | m_msg(msg) | |
75 | { | |
76 | assert(m_e != safe_numerics_error::success); | |
77 | } | |
20effc67 | 78 | |
92f5a8d4 TL |
79 | // permit construct from another checked result type |
80 | template<typename T> | |
81 | constexpr /*explicit*/ checked_result(const checked_result<T> & t) noexcept : | |
82 | m_e(t.m_e) | |
83 | { | |
84 | static_assert( | |
85 | std::is_convertible<T, R>::value, | |
86 | "T must be convertible to R" | |
87 | ); | |
88 | if(safe_numerics_error::success == t.m_e) | |
89 | m_r = t.m_r; | |
90 | else | |
91 | m_msg = t.m_msg; | |
92 | } | |
20effc67 | 93 | |
92f5a8d4 TL |
94 | constexpr bool exception() const { |
95 | return m_e != safe_numerics_error::success; | |
96 | } | |
97 | ||
98 | // accesors | |
99 | constexpr operator R() const noexcept{ | |
100 | // don't assert here. Let the library catch these errors | |
20effc67 | 101 | // assert(! exception()); |
92f5a8d4 TL |
102 | return m_r; |
103 | } | |
104 | ||
105 | constexpr operator safe_numerics_error () const noexcept{ | |
106 | // note that this is a legitimate operation even when | |
107 | // the operation was successful - it will return success | |
108 | return m_e; | |
109 | } | |
110 | constexpr operator const char *() const noexcept{ | |
111 | assert(exception()); | |
112 | return m_msg; | |
113 | } | |
114 | ||
115 | // disallow assignment | |
116 | checked_result & operator=(const checked_result &) = delete; | |
117 | }; | |
118 | ||
92f5a8d4 TL |
119 | template <class R> |
120 | class make_checked_result { | |
121 | public: | |
122 | template<safe_numerics_error E> | |
123 | constexpr static checked_result<R> invoke( | |
124 | char const * const & m | |
125 | ) noexcept { | |
126 | return checked_result<R>(E, m); | |
127 | } | |
128 | }; | |
129 | ||
130 | } // safe_numerics | |
131 | } // boost | |
132 | ||
133 | #endif // BOOST_NUMERIC_CHECKED_RESULT |