1 #ifndef BOOST_NUMERIC_EXCEPTION_POLICIES_HPP
2 #define BOOST_NUMERIC_EXCEPTION_POLICIES_HPP
4 // Copyright (c) 2015 Robert Ramey
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)
10 #include <boost/mp11.hpp>
11 #include <boost/config.hpp> // BOOST_NO_EXCEPTIONS
12 #include "exception.hpp"
15 namespace safe_numerics {
23 struct exception_policy {
24 static constexpr void on_arithmetic_error(
25 const safe_numerics_error & e,
30 static constexpr void on_implementation_defined_behavior(
31 const safe_numerics_error & e,
36 static constexpr void on_undefined_behavior(
37 const safe_numerics_error & e,
42 static constexpr void on_uninitialized_value(
43 const safe_numerics_error & e,
50 ////////////////////////////////////////////////////////////////////////////////
51 // pre-made error action handers
53 // ignore any error and just return.
54 struct ignore_exception {
55 constexpr ignore_exception(const safe_numerics_error &, const char * ){}
58 // emit compile time error if this is invoked.
59 struct trap_exception {};
61 // If an exceptional condition is detected at runtime throw the exception.
62 struct throw_exception {
63 #ifndef BOOST_NO_EXCEPTIONS
64 throw_exception(const safe_numerics_error & e, const char * message){
65 throw std::system_error(std::error_code(e), message);
68 trap_exception(const safe_numerics_error & e, const char * message);
72 // given an error code - return the action code which it corresponds to.
73 constexpr safe_numerics_actions
74 make_safe_numerics_action(const safe_numerics_error & e){
75 // we can't use standard algorithms since we want this to be constexpr
76 // this brute force solution is simple and pretty fast anyway
78 case safe_numerics_error::negative_overflow_error:
79 case safe_numerics_error::underflow_error:
80 case safe_numerics_error::range_error:
81 case safe_numerics_error::domain_error:
82 case safe_numerics_error::positive_overflow_error:
83 case safe_numerics_error::precision_overflow_error:
84 return safe_numerics_actions::arithmetic_error;
86 case safe_numerics_error::negative_value_shift:
87 case safe_numerics_error::negative_shift:
88 case safe_numerics_error::shift_too_large:
89 return safe_numerics_actions::implementation_defined_behavior;
91 case safe_numerics_error::uninitialized_value:
92 return safe_numerics_actions::uninitialized_value;
94 case safe_numerics_error::success:
95 return safe_numerics_actions::no_action;
99 // should never arrive here
100 //include to suppress bogus warning
101 return safe_numerics_actions::no_action;
104 ////////////////////////////////////////////////////////////////////////////////
105 // compile time error dispatcher
107 // note slightly baroque implementation of a compile time switch statement
108 // which instatiates oonly those cases which are actually invoked. This is
109 // motivated to implement the "trap" functionality which will generate a syntax
110 // error if and only a function which might fail is called.
112 namespace dispatch_switch {
114 template<class EP, safe_numerics_actions>
115 struct dispatch_case {};
118 struct dispatch_case<EP, safe_numerics_actions::uninitialized_value> {
119 constexpr static void invoke(const safe_numerics_error & e, const char * msg){
120 EP::on_uninitialized_value(e, msg);
124 struct dispatch_case<EP, safe_numerics_actions::arithmetic_error> {
125 constexpr static void invoke(const safe_numerics_error & e, const char * msg){
126 EP::on_arithmetic_error(e, msg);
130 struct dispatch_case<EP, safe_numerics_actions::implementation_defined_behavior> {
131 constexpr static void invoke(const safe_numerics_error & e, const char * msg){
132 EP::on_implementation_defined_behavior(e, msg);
136 struct dispatch_case<EP, safe_numerics_actions::undefined_behavior> {
137 constexpr static void invoke(const safe_numerics_error & e, const char * msg){
138 EP::on_undefined_behavior(e, msg);
144 template<class EP, safe_numerics_error E>
146 dispatch(const char * msg){
147 constexpr safe_numerics_actions a = make_safe_numerics_action(E);
148 dispatch_switch::dispatch_case<EP, a>::invoke(E, msg);
151 template<class EP, class R>
152 class dispatch_and_return {
154 template<safe_numerics_error E>
155 constexpr static checked_result<R> invoke(
156 char const * const & msg
158 dispatch<EP, E>(msg);
159 return checked_result<R>(E, msg);
163 ////////////////////////////////////////////////////////////////////////////////
164 // pre-made error policy classes
167 // - throw on arithmetic errors
168 // - ignore other errors.
169 // Some applications ignore these issues and still work and we don't
170 // want to update them.
171 using loose_exception_policy = exception_policy<
172 throw_exception, // arithmetic error
173 ignore_exception, // implementation defined behavior
174 ignore_exception, // undefined behavior
175 ignore_exception // uninitialized value
179 // same as above in that it doesn't check for various undefined behaviors
180 // but traps at compile time for hard arithmetic errors. This policy
181 // would be suitable for older embedded systems which depend on
182 // bit manipulation operations to work.
183 using loose_trap_policy = exception_policy<
184 trap_exception, // arithmetic error
185 ignore_exception, // implementation defined behavior
186 ignore_exception, // undefined behavior
187 ignore_exception // uninitialized value
191 // - throw at runtime on any kind of error
192 // recommended for new code. Check everything at compile time
193 // if possible and runtime if necessary. Trap or Throw as
194 // appropriate. Should guarantee code to be portable across
196 using strict_exception_policy = exception_policy<
204 // Same as above but requires code to be written in such a way as to
205 // make it impossible for errors to occur. This naturally will require
206 // extra coding effort but might be justified for embedded and/or
207 // safety critical systems.
208 using strict_trap_policy = exception_policy<
216 // One would use this first. After experimentation, one might
217 // replace some actions with ignore_exception
218 using default_exception_policy = strict_exception_policy;
220 } // namespace safe_numerics
223 #endif // BOOST_NUMERIC_EXCEPTION_POLICIES_HPP