• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BOOST_NUMERIC_EXCEPTION_POLICIES_HPP
2 #define BOOST_NUMERIC_EXCEPTION_POLICIES_HPP
3 
4 //  Copyright (c) 2015 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 #include <boost/mp11.hpp>
11 #include <boost/config.hpp> // BOOST_NO_EXCEPTIONS
12 #include "exception.hpp"
13 
14 namespace boost {
15 namespace safe_numerics {
16 
17 template<
18     typename AE,
19     typename IDB,
20     typename UB,
21     typename UV
22 >
23 struct exception_policy {
on_arithmetic_errorboost::safe_numerics::exception_policy24     static constexpr void on_arithmetic_error(
25         const safe_numerics_error & e,
26         const char * msg
27     ){
28         AE(e, msg);
29     }
on_implementation_defined_behaviorboost::safe_numerics::exception_policy30     static constexpr void on_implementation_defined_behavior(
31         const safe_numerics_error & e,
32         const char * msg
33     ){
34         IDB(e, msg);
35     }
on_undefined_behaviorboost::safe_numerics::exception_policy36     static constexpr void on_undefined_behavior(
37         const safe_numerics_error & e,
38         const char * msg
39     ){
40         UB(e, msg);
41     }
on_uninitialized_valueboost::safe_numerics::exception_policy42     static constexpr void on_uninitialized_value(
43         const safe_numerics_error & e,
44         const char * msg
45     ){
46         UV(e, msg);
47     }
48 };
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 // pre-made error action handers
52 
53 // ignore any error and just return.
54 struct ignore_exception {
ignore_exceptionboost::safe_numerics::ignore_exception55     constexpr ignore_exception(const safe_numerics_error &, const char * ){}
56 };
57 
58 // emit compile time error if this is invoked.
59 struct trap_exception {
60 #if 1
61     //constexpr trap_exception(const safe_numerics_error & e, const char * );
62     trap_exception() = delete;
63     trap_exception(const trap_exception &) = delete;
64     trap_exception(trap_exception &&) = delete;
65 #endif
66 };
67 
68 // If an exceptional condition is detected at runtime throw the exception.
69 struct throw_exception {
70     #ifndef BOOST_NO_EXCEPTIONS
throw_exceptionboost::safe_numerics::throw_exception71     throw_exception(const safe_numerics_error & e, const char * message){
72         throw std::system_error(std::error_code(e), message);
73     }
74     #else
75     trap_exception(const safe_numerics_error & e, const char * message);
76     #endif
77 };
78 
79 // given an error code - return the action code which it corresponds to.
80 constexpr safe_numerics_actions
make_safe_numerics_action(const safe_numerics_error & e)81 make_safe_numerics_action(const safe_numerics_error & e){
82     // we can't use standard algorithms since we want this to be constexpr
83     // this brute force solution is simple and pretty fast anyway
84     switch(e){
85     case safe_numerics_error::negative_overflow_error:
86     case safe_numerics_error::underflow_error:
87     case safe_numerics_error::range_error:
88     case safe_numerics_error::domain_error:
89     case safe_numerics_error::positive_overflow_error:
90     case safe_numerics_error::precision_overflow_error:
91         return safe_numerics_actions::arithmetic_error;
92 
93     case safe_numerics_error::negative_value_shift:
94     case safe_numerics_error::negative_shift:
95     case safe_numerics_error::shift_too_large:
96         return safe_numerics_actions::implementation_defined_behavior;
97 
98     case safe_numerics_error::uninitialized_value:
99         return safe_numerics_actions::uninitialized_value;
100 
101     case safe_numerics_error::success:
102         return safe_numerics_actions::no_action;
103     default:
104         assert(false);
105     }
106     // should never arrive here
107     //include to suppress bogus warning
108     return safe_numerics_actions::no_action;
109 }
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 // compile time error dispatcher
113 
114 // note slightly baroque implementation of a compile time switch statement
115 // which instatiates only those cases which are actually invoked.  This is
116 // motivated to implement the "trap" functionality which will generate a syntax
117 // error if and only a function which might fail is called.
118 
119 namespace dispatch_switch {
120 
121     template<class EP, safe_numerics_actions>
122     struct dispatch_case {};
123 
124     template<class EP>
125     struct dispatch_case<EP, safe_numerics_actions::uninitialized_value> {
invokeboost::safe_numerics::dispatch_switch::dispatch_case126         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
127             EP::on_uninitialized_value(e, msg);
128         }
129     };
130     template<class EP>
131     struct dispatch_case<EP, safe_numerics_actions::arithmetic_error> {
invokeboost::safe_numerics::dispatch_switch::dispatch_case132         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
133             EP::on_arithmetic_error(e, msg);
134         }
135     };
136     template<class EP>
137     struct dispatch_case<EP, safe_numerics_actions::implementation_defined_behavior> {
invokeboost::safe_numerics::dispatch_switch::dispatch_case138         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
139             EP::on_implementation_defined_behavior(e, msg);
140         }
141     };
142     template<class EP>
143     struct dispatch_case<EP, safe_numerics_actions::undefined_behavior> {
invokeboost::safe_numerics::dispatch_switch::dispatch_case144         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
145             EP::on_undefined_behavior(e, msg);
146         }
147     };
148 
149 } // dispatch_switch
150 
151 template<class EP, safe_numerics_error E>
152 constexpr void
dispatch(const char * msg)153 dispatch(const char * msg){
154     constexpr safe_numerics_actions a = make_safe_numerics_action(E);
155     dispatch_switch::dispatch_case<EP, a>::invoke(E, msg);
156 }
157 
158 template<class EP, class R>
159 class dispatch_and_return {
160 public:
161     template<safe_numerics_error E>
invoke(char const * const & msg)162     constexpr static checked_result<R> invoke(
163         char const * const & msg
164     ) {
165         dispatch<EP, E>(msg);
166         return checked_result<R>(E, msg);
167     }
168 };
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 // pre-made error policy classes
172 
173 // loose exception
174 // - throw on arithmetic errors
175 // - ignore other errors.
176 // Some applications ignore these issues and still work and we don't
177 // want to update them.
178 using loose_exception_policy = exception_policy<
179     throw_exception,    // arithmetic error
180     ignore_exception,   // implementation defined behavior
181     ignore_exception,   // undefined behavior
182     ignore_exception     // uninitialized value
183 >;
184 
185 // loose trap
186 // same as above in that it doesn't check for various undefined behaviors
187 // but traps at compile time for hard arithmetic errors.  This policy
188 // would be suitable for older embedded systems which depend on
189 // bit manipulation operations to work.
190 using loose_trap_policy = exception_policy<
191     trap_exception,    // arithmetic error
192     ignore_exception,  // implementation defined behavior
193     ignore_exception,  // undefined behavior
194     ignore_exception   // uninitialized value
195 >;
196 
197 // strict exception
198 // - throw at runtime on any kind of error
199 // recommended for new code.  Check everything at compile time
200 // if possible and runtime if necessary.  Trap or Throw as
201 // appropriate.  Should guarantee code to be portable across
202 // architectures.
203 using strict_exception_policy = exception_policy<
204     throw_exception,
205     throw_exception,
206     throw_exception,
207     ignore_exception
208 >;
209 
210 // strict trap
211 // Same as above but requires code to be written in such a way as to
212 // make it impossible for errors to occur.  This naturally will require
213 // extra coding effort but might be justified for embedded and/or
214 // safety critical systems.
215 using strict_trap_policy = exception_policy<
216     trap_exception,
217     trap_exception,
218     trap_exception,
219     trap_exception
220 >;
221 
222 // default policy
223 // One would use this first. After experimentation, one might
224 // replace some actions with ignore_exception
225 using default_exception_policy = strict_exception_policy;
226 
227 } // namespace safe_numerics
228 } // namespace boost
229 
230 #endif // BOOST_NUMERIC_EXCEPTION_POLICIES_HPP
231