| 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 | constexpr static void on_arithmetic_error( |
| 25 | const safe_numerics_error & e, |
| 26 | const char * msg |
| 27 | ){ |
| 28 | AE()(e, msg); |
| 29 | } |
| 30 | constexpr static void on_implementation_defined_behavior( |
| 31 | const safe_numerics_error & e, |
| 32 | const char * msg |
| 33 | ){ |
| 34 | IDB()(e, msg); |
| 35 | } |
| 36 | constexpr static void on_undefined_behavior( |
| 37 | const safe_numerics_error & e, |
| 38 | const char * msg |
| 39 | ){ |
| 40 | UB()(e, msg); |
| 41 | } |
| 42 | constexpr static 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() = default; |
| 56 | constexpr void operator () ( |
| 57 | const boost::safe_numerics::safe_numerics_error &, |
| 58 | const char * |
| 59 | ){} |
| 60 | }; |
| 61 | |
| 62 | // emit compile time error if this is invoked. |
| 63 | struct trap_exception { |
| 64 | constexpr trap_exception() = default; |
| 65 | // error will occur on operator call. |
| 66 | // hopefully this will display arguments |
| 67 | }; |
| 68 | |
| 69 | // If an exceptional condition is detected at runtime throw the exception. |
| 70 | struct throw_exception { |
| 71 | constexpr throw_exception() = default; |
| 72 | #ifndef BOOST_NO_EXCEPTIONS |
| 73 | void operator()( |
| 74 | const safe_numerics_error & e, |
| 75 | const char * message |
| 76 | ){ |
| 77 | throw std::system_error(std::error_code(e), message); |
| 78 | } |
| 79 | #else |
| 80 | constexpr trap_exception()(const safe_numerics_error & e, const char * message); |
| 81 | #endif |
| 82 | }; |
| 83 | |
| 84 | // given an error code - return the action code which it corresponds to. |
| 85 | constexpr inline safe_numerics_actions |
| 86 | make_safe_numerics_action(const safe_numerics_error & e){ |
| 87 | // we can't use standard algorithms since we want this to be constexpr |
| 88 | // this brute force solution is simple and pretty fast anyway |
| 89 | switch(e){ |
| 90 | case safe_numerics_error::negative_overflow_error: |
| 91 | case safe_numerics_error::underflow_error: |
| 92 | case safe_numerics_error::range_error: |
| 93 | case safe_numerics_error::domain_error: |
| 94 | case safe_numerics_error::positive_overflow_error: |
| 95 | case safe_numerics_error::precision_overflow_error: |
| 96 | return safe_numerics_actions::arithmetic_error; |
| 97 | |
| 98 | case safe_numerics_error::negative_value_shift: |
| 99 | case safe_numerics_error::negative_shift: |
| 100 | case safe_numerics_error::shift_too_large: |
| 101 | return safe_numerics_actions::implementation_defined_behavior; |
| 102 | |
| 103 | case safe_numerics_error::uninitialized_value: |
| 104 | return safe_numerics_actions::uninitialized_value; |
| 105 | |
| 106 | case safe_numerics_error::success: |
| 107 | return safe_numerics_actions::no_action; |
| 108 | default: |
| 109 | assert(false); |
| 110 | } |
| 111 | // should never arrive here |
| 112 | //include to suppress bogus warning |
| 113 | return safe_numerics_actions::no_action; |
| 114 | } |
| 115 | |
| 116 | //////////////////////////////////////////////////////////////////////////////// |
| 117 | // pre-made error policy classes |
| 118 | |
| 119 | // loose exception |
| 120 | // - throw on arithmetic errors |
| 121 | // - ignore other errors. |
| 122 | // Some applications ignore these issues and still work and we don't |
| 123 | // want to update them. |
| 124 | using loose_exception_policy = exception_policy< |
| 125 | throw_exception, // arithmetic error |
| 126 | ignore_exception, // implementation defined behavior |
| 127 | ignore_exception, // undefined behavior |
| 128 | ignore_exception // uninitialized value |
| 129 | >; |
| 130 | |
| 131 | // loose trap |
| 132 | // same as above in that it doesn't check for various undefined behaviors |
| 133 | // but traps at compile time for hard arithmetic errors. This policy |
| 134 | // would be suitable for older embedded systems which depend on |
| 135 | // bit manipulation operations to work. |
| 136 | using loose_trap_policy = exception_policy< |
| 137 | trap_exception, // arithmetic error |
| 138 | ignore_exception, // implementation defined behavior |
| 139 | ignore_exception, // undefined behavior |
| 140 | ignore_exception // uninitialized value |
| 141 | >; |
| 142 | |
| 143 | // strict exception |
| 144 | // - throw at runtime on any kind of error |
| 145 | // recommended for new code. Check everything at compile time |
| 146 | // if possible and runtime if necessary. Trap or Throw as |
| 147 | // appropriate. Should guarantee code to be portable across |
| 148 | // architectures. |
| 149 | using strict_exception_policy = exception_policy< |
| 150 | throw_exception, |
| 151 | throw_exception, |
| 152 | throw_exception, |
| 153 | ignore_exception |
| 154 | >; |
| 155 | |
| 156 | // strict trap |
| 157 | // Same as above but requires code to be written in such a way as to |
| 158 | // make it impossible for errors to occur. This naturally will require |
| 159 | // extra coding effort but might be justified for embedded and/or |
| 160 | // safety critical systems. |
| 161 | using strict_trap_policy = exception_policy< |
| 162 | trap_exception, |
| 163 | trap_exception, |
| 164 | trap_exception, |
| 165 | trap_exception |
| 166 | >; |
| 167 | |
| 168 | // default policy |
| 169 | // One would use this first. After experimentation, one might |
| 170 | // replace some actions with ignore_exception |
| 171 | using default_exception_policy = strict_exception_policy; |
| 172 | |
| 173 | } // namespace safe_numerics |
| 174 | } // namespace boost |
| 175 | |
| 176 | #endif // BOOST_NUMERIC_EXCEPTION_POLICIES_HPP |
| 177 | |