Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / safe_numerics / exception_policies.hpp
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 {
24     static constexpr void on_arithmetic_error(
25         const safe_numerics_error & e,
26         const char * msg
27     ){
28         AE(e, msg);
29     }
30     static constexpr void on_implementation_defined_behavior(
31         const safe_numerics_error & e,
32         const char * msg
33     ){
34         IDB(e, msg);
35     }
36     static constexpr void on_undefined_behavior(
37         const safe_numerics_error & e,
38         const char * msg
39     ){
40         UB(e, msg);
41     }
42     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 {
55     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
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);
66     }
67     #else
68     trap_exception(const safe_numerics_error & e, const char * message);
69     #endif
70 };
71
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
77     switch(e){
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;
85
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;
90
91     case safe_numerics_error::uninitialized_value:
92         return safe_numerics_actions::uninitialized_value;
93
94     case safe_numerics_error::success:
95         return safe_numerics_actions::no_action;
96     default:
97         assert(false);
98     }
99     // should never arrive here
100     //include to suppress bogus warning
101     return safe_numerics_actions::no_action;
102 }
103
104 ////////////////////////////////////////////////////////////////////////////////
105 // compile time error dispatcher
106
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.
111
112 namespace dispatch_switch {
113
114     template<class EP, safe_numerics_actions>
115     struct dispatch_case {};
116
117     template<class EP>
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);
121         }
122     };
123     template<class EP>
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);
127         }
128     };
129     template<class EP>
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);
133         }
134     };
135     template<class EP>
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);
139         }
140     };
141
142 } // dispatch_switch
143
144 template<class EP, safe_numerics_error E>
145 constexpr void
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);
149 }
150
151 template<class EP, class R>
152 class dispatch_and_return {
153 public:
154     template<safe_numerics_error E>
155     constexpr static checked_result<R> invoke(
156         char const * const & msg
157     ) {
158         dispatch<EP, E>(msg);
159         return checked_result<R>(E, msg);
160     }
161 };
162
163 ////////////////////////////////////////////////////////////////////////////////
164 // pre-made error policy classes
165
166 // loose exception
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
176 >;
177
178 // loose trap
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
188 >;
189
190 // strict exception
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
195 // architectures.
196 using strict_exception_policy = exception_policy<
197     throw_exception,
198     throw_exception,
199     throw_exception,
200     ignore_exception
201 >;
202
203 // strict trap
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<
209     trap_exception,
210     trap_exception,
211     trap_exception,
212     trap_exception
213 >;
214
215 // default 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;
219
220 } // namespace safe_numerics
221 } // namespace boost
222
223 #endif // BOOST_NUMERIC_EXCEPTION_POLICIES_HPP