]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | #ifndef BOOST_NUMERIC_EXCEPTION |
2 | #define BOOST_NUMERIC_EXCEPTION | |
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 error indicators for results of doing checked | |
11 | // arithmetic on native C++ types | |
12 | ||
13 | #include <algorithm> | |
14 | #include <system_error> // error_code, system_error | |
15 | #include <string> | |
16 | #include <cassert> | |
17 | #include <cstdint> // std::uint8_t | |
18 | ||
19 | // Using the system_error code facility. This facility is more complex | |
20 | // than meets the eye. To fully understand what out intent here is, | |
21 | // review http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html | |
22 | // "Giving context-specific meaning to generic error codes" | |
23 | ||
24 | namespace boost { | |
25 | namespace safe_numerics { | |
26 | ||
27 | // errors codes for safe numerics | |
28 | ||
29 | // in spite of the similarity, this list is distinct from the exceptions | |
30 | // listed in documentation for std::exception. | |
31 | ||
32 | // note: Don't reorder these. Code in the file checked_result_operations.hpp | |
33 | // depends upon this order !!! | |
34 | enum class safe_numerics_error : std::uint8_t { | |
35 | success = 0, | |
36 | positive_overflow_error, // result is above representational maximum | |
37 | negative_overflow_error, // result is below representational minimum | |
38 | domain_error, // one operand is out of valid range | |
39 | range_error, // result cannot be produced for this operation | |
40 | precision_overflow_error, // result lost precision | |
41 | underflow_error, // result is too small to be represented | |
42 | negative_value_shift, // negative value in shift operator | |
43 | negative_shift, // shift a negative value | |
44 | shift_too_large, // l/r shift exceeds variable size | |
45 | uninitialized_value // creating of uninitialized value | |
46 | }; | |
47 | ||
20effc67 TL |
48 | const char * literal_string(const safe_numerics_error & e){ |
49 | switch(e){ | |
50 | case safe_numerics_error::success: return "success"; | |
51 | case safe_numerics_error::positive_overflow_error: return "positive_overflow_error"; | |
52 | case safe_numerics_error::negative_overflow_error: return "negative_overflow_error"; | |
53 | case safe_numerics_error::domain_error: return "domain_error"; | |
54 | case safe_numerics_error::range_error: return "range_error"; | |
55 | case safe_numerics_error::precision_overflow_error: return "precision_overflow_error"; | |
56 | case safe_numerics_error::underflow_error: return "underflow_error"; | |
57 | case safe_numerics_error::negative_value_shift: return "negative_value_shift"; | |
58 | case safe_numerics_error::negative_shift: return "negative_shift"; | |
59 | case safe_numerics_error::shift_too_large: return "shift_too_large"; | |
60 | case safe_numerics_error::uninitialized_value: return "uninitialized_value"; | |
61 | default: | |
62 | assert(false); // should never arrive here | |
63 | } | |
64 | } | |
65 | ||
92f5a8d4 TL |
66 | const std::uint8_t safe_numerics_casting_error_count = |
67 | static_cast<std::uint8_t>(safe_numerics_error::domain_error) + 1; | |
68 | ||
69 | const std::uint8_t safe_numerics_error_count = | |
70 | static_cast<std::uint8_t>(safe_numerics_error::uninitialized_value) + 1; | |
71 | ||
72 | } // safe_numerics | |
73 | } // boost | |
74 | ||
75 | namespace std { | |
76 | template <> | |
77 | struct is_error_code_enum<boost::safe_numerics::safe_numerics_error> | |
78 | : public true_type {}; | |
79 | } // std | |
80 | ||
81 | namespace boost { | |
82 | namespace safe_numerics { | |
83 | ||
84 | const class : public std::error_category { | |
85 | public: | |
86 | virtual const char* name() const noexcept{ | |
87 | return "safe numerics error"; | |
88 | } | |
89 | virtual std::string message(int ev) const { | |
90 | switch(static_cast<safe_numerics_error>(ev)){ | |
91 | case safe_numerics_error::success: | |
92 | return "success"; | |
93 | case safe_numerics_error::positive_overflow_error: | |
94 | return "positive overflow error"; | |
95 | case safe_numerics_error::negative_overflow_error: | |
96 | return "negative overflow error"; | |
97 | case safe_numerics_error::underflow_error: | |
98 | return "underflow error"; | |
99 | case safe_numerics_error::range_error: | |
100 | return "range error"; | |
f67539c2 TL |
101 | case safe_numerics_error::precision_overflow_error: |
102 | return "precision_overflow_error"; | |
92f5a8d4 TL |
103 | case safe_numerics_error::domain_error: |
104 | return "domain error"; | |
105 | case safe_numerics_error::negative_shift: | |
106 | return "negative shift"; | |
107 | case safe_numerics_error::negative_value_shift: | |
108 | return "negative value shift"; | |
109 | case safe_numerics_error::shift_too_large: | |
110 | return "shift too large"; | |
111 | case safe_numerics_error::uninitialized_value: | |
112 | return "uninitialized value"; | |
113 | default: | |
114 | assert(false); | |
115 | } | |
116 | return ""; // suppress bogus warning | |
117 | } | |
118 | } safe_numerics_error_category {}; | |
119 | ||
120 | // constexpr - damn, can't use constexpr due to std::error_code | |
121 | inline std::error_code make_error_code(const safe_numerics_error & e){ | |
122 | return std::error_code(static_cast<int>(e), safe_numerics_error_category); | |
123 | } | |
124 | ||
125 | // actions for error_codes for safe numerics. I've leveraged on | |
126 | // error_condition in order to do this. I'm not sure this is a good | |
127 | // idea or not. | |
128 | ||
129 | enum class safe_numerics_actions { | |
130 | no_action = 0, | |
131 | uninitialized_value, | |
132 | arithmetic_error, | |
133 | implementation_defined_behavior, | |
134 | undefined_behavior | |
135 | }; | |
136 | ||
137 | } // safe_numerics | |
138 | } // boost | |
139 | ||
140 | namespace std { | |
141 | template <> | |
142 | struct is_error_condition_enum<boost::safe_numerics::safe_numerics_actions> | |
143 | : public true_type {}; | |
144 | } // std | |
145 | ||
146 | namespace boost { | |
147 | namespace safe_numerics { | |
148 | ||
149 | const class : public std::error_category { | |
150 | public: | |
151 | virtual const char* name() const noexcept { | |
152 | return "safe numerics error group"; | |
153 | } | |
154 | virtual std::string message(int) const { | |
155 | return "safe numerics error group"; | |
156 | } | |
157 | // return true if a given error code corresponds to a | |
158 | // given safe numeric action | |
159 | virtual bool equivalent( | |
160 | const std::error_code & code, | |
161 | int condition | |
162 | ) const noexcept { | |
163 | if(code.category() != safe_numerics_error_category) | |
164 | return false; | |
165 | switch (static_cast<safe_numerics_actions>(condition)){ | |
166 | case safe_numerics_actions::no_action: | |
167 | return code == safe_numerics_error::success; | |
168 | case safe_numerics_actions::uninitialized_value: | |
169 | return code == safe_numerics_error::uninitialized_value; | |
170 | case safe_numerics_actions::arithmetic_error: | |
171 | return code == safe_numerics_error::positive_overflow_error | |
172 | || code == safe_numerics_error::negative_overflow_error | |
173 | || code == safe_numerics_error::underflow_error | |
174 | || code == safe_numerics_error::range_error | |
175 | || code == safe_numerics_error::domain_error; | |
176 | case safe_numerics_actions::implementation_defined_behavior: | |
177 | return code == safe_numerics_error::negative_value_shift | |
178 | || code == safe_numerics_error::negative_shift | |
179 | || code == safe_numerics_error::shift_too_large; | |
180 | case safe_numerics_actions::undefined_behavior: | |
181 | return false; | |
182 | default: | |
183 | ; | |
184 | } | |
185 | // should never arrive here | |
186 | assert(false); | |
187 | // suppress bogus warning | |
188 | return false; | |
189 | } | |
190 | } safe_numerics_actions_category {}; | |
191 | ||
192 | // the following function is used to "finish" implementation of conversion | |
193 | // of safe_numerics_error to std::error_condition. At least for now, this | |
194 | // isn't being used and defining here it can lead duplicate symbol errors | |
195 | // depending on the compiler. So suppress it until further notice | |
196 | #if 0 | |
197 | std::error_condition make_error_condition(const safe_numerics_error & e) { | |
198 | return std::error_condition( | |
199 | static_cast<int>(e), | |
200 | safe_numerics_error_category | |
201 | ); | |
202 | } | |
203 | #endif | |
204 | ||
205 | } // safe_numerics | |
206 | } // boost | |
207 | ||
208 | #endif // BOOST_NUMERIC_CHECKED_RESULT |