exception_policies.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #ifndef BOOST_NUMERIC_EXCEPTION_POLICIES_HPP
  2. #define BOOST_NUMERIC_EXCEPTION_POLICIES_HPP
  3. // Copyright (c) 2015 Robert Ramey
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #include <boost/mp11.hpp>
  9. #include <boost/config.hpp> // BOOST_NO_EXCEPTIONS
  10. #include "exception.hpp"
  11. namespace boost {
  12. namespace safe_numerics {
  13. template<
  14. typename AE,
  15. typename IDB,
  16. typename UB,
  17. typename UV
  18. >
  19. struct exception_policy {
  20. constexpr static void on_arithmetic_error(
  21. const safe_numerics_error & e,
  22. const char * msg
  23. ){
  24. AE()(e, msg);
  25. }
  26. constexpr static void on_implementation_defined_behavior(
  27. const safe_numerics_error & e,
  28. const char * msg
  29. ){
  30. IDB()(e, msg);
  31. }
  32. constexpr static void on_undefined_behavior(
  33. const safe_numerics_error & e,
  34. const char * msg
  35. ){
  36. UB()(e, msg);
  37. }
  38. constexpr static void on_uninitialized_value(
  39. const safe_numerics_error & e,
  40. const char * msg
  41. ){
  42. UV()(e, msg);
  43. }
  44. };
  45. ////////////////////////////////////////////////////////////////////////////////
  46. // pre-made error action handers
  47. // ignore any error and just return.
  48. struct ignore_exception {
  49. constexpr ignore_exception() = default;
  50. constexpr void operator () (
  51. const boost::safe_numerics::safe_numerics_error &,
  52. const char *
  53. ){}
  54. };
  55. // emit compile time error if this is invoked.
  56. struct trap_exception {
  57. constexpr trap_exception() = default;
  58. // error will occur on operator call.
  59. // hopefully this will display arguments
  60. };
  61. // If an exceptional condition is detected at runtime throw the exception.
  62. struct throw_exception {
  63. constexpr throw_exception() = default;
  64. #ifndef BOOST_NO_EXCEPTIONS
  65. void operator()(
  66. const safe_numerics_error & e,
  67. const char * message
  68. ){
  69. throw std::system_error(std::error_code(e), message);
  70. }
  71. #else
  72. constexpr trap_exception()(const safe_numerics_error & e, const char * message);
  73. #endif
  74. };
  75. // given an error code - return the action code which it corresponds to.
  76. constexpr inline safe_numerics_actions
  77. make_safe_numerics_action(const safe_numerics_error & e){
  78. // we can't use standard algorithms since we want this to be constexpr
  79. // this brute force solution is simple and pretty fast anyway
  80. switch(e){
  81. case safe_numerics_error::negative_overflow_error:
  82. case safe_numerics_error::underflow_error:
  83. case safe_numerics_error::range_error:
  84. case safe_numerics_error::domain_error:
  85. case safe_numerics_error::positive_overflow_error:
  86. case safe_numerics_error::precision_overflow_error:
  87. return safe_numerics_actions::arithmetic_error;
  88. case safe_numerics_error::negative_value_shift:
  89. case safe_numerics_error::negative_shift:
  90. case safe_numerics_error::shift_too_large:
  91. return safe_numerics_actions::implementation_defined_behavior;
  92. case safe_numerics_error::uninitialized_value:
  93. return safe_numerics_actions::uninitialized_value;
  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. // compile time error dispatcher
  105. // note slightly baroque implementation of a compile time switch statement
  106. // which instatiates only those cases which are actually invoked. This is
  107. // motivated to implement the "trap" functionality which will generate a syntax
  108. // error if and only a function which might fail is called.
  109. namespace dispatch_switch {
  110. template<class EP, safe_numerics_actions>
  111. struct dispatch_case {};
  112. template<class EP>
  113. struct dispatch_case<EP, safe_numerics_actions::uninitialized_value> {
  114. constexpr static void invoke(const safe_numerics_error & e, const char * msg){
  115. EP::on_uninitialized_value(e, msg);
  116. }
  117. };
  118. template<class EP>
  119. struct dispatch_case<EP, safe_numerics_actions::arithmetic_error> {
  120. constexpr static void invoke(const safe_numerics_error & e, const char * msg){
  121. EP::on_arithmetic_error(e, msg);
  122. }
  123. };
  124. template<class EP>
  125. struct dispatch_case<EP, safe_numerics_actions::implementation_defined_behavior> {
  126. constexpr static void invoke(const safe_numerics_error & e, const char * msg){
  127. EP::on_implementation_defined_behavior(e, msg);
  128. }
  129. };
  130. template<class EP>
  131. struct dispatch_case<EP, safe_numerics_actions::undefined_behavior> {
  132. constexpr static void invoke(const safe_numerics_error & e, const char * msg){
  133. EP::on_undefined_behavior(e, msg);
  134. }
  135. };
  136. } // dispatch_switch
  137. template<class EP, safe_numerics_error E>
  138. constexpr inline void
  139. dispatch(const char * msg){
  140. constexpr safe_numerics_actions a = make_safe_numerics_action(E);
  141. dispatch_switch::dispatch_case<EP, a>::invoke(E, msg);
  142. }
  143. template<class EP, class R>
  144. class dispatch_and_return {
  145. public:
  146. template<safe_numerics_error E>
  147. constexpr static checked_result<R> invoke(
  148. char const * const & msg
  149. ) {
  150. dispatch<EP, E>(msg);
  151. return checked_result<R>(E, msg);
  152. }
  153. };
  154. ////////////////////////////////////////////////////////////////////////////////
  155. // pre-made error policy classes
  156. // loose exception
  157. // - throw on arithmetic errors
  158. // - ignore other errors.
  159. // Some applications ignore these issues and still work and we don't
  160. // want to update them.
  161. using loose_exception_policy = exception_policy<
  162. throw_exception, // arithmetic error
  163. ignore_exception, // implementation defined behavior
  164. ignore_exception, // undefined behavior
  165. ignore_exception // uninitialized value
  166. >;
  167. // loose trap
  168. // same as above in that it doesn't check for various undefined behaviors
  169. // but traps at compile time for hard arithmetic errors. This policy
  170. // would be suitable for older embedded systems which depend on
  171. // bit manipulation operations to work.
  172. using loose_trap_policy = exception_policy<
  173. trap_exception, // arithmetic error
  174. ignore_exception, // implementation defined behavior
  175. ignore_exception, // undefined behavior
  176. ignore_exception // uninitialized value
  177. >;
  178. // strict exception
  179. // - throw at runtime on any kind of error
  180. // recommended for new code. Check everything at compile time
  181. // if possible and runtime if necessary. Trap or Throw as
  182. // appropriate. Should guarantee code to be portable across
  183. // architectures.
  184. using strict_exception_policy = exception_policy<
  185. throw_exception,
  186. throw_exception,
  187. throw_exception,
  188. ignore_exception
  189. >;
  190. // strict trap
  191. // Same as above but requires code to be written in such a way as to
  192. // make it impossible for errors to occur. This naturally will require
  193. // extra coding effort but might be justified for embedded and/or
  194. // safety critical systems.
  195. using strict_trap_policy = exception_policy<
  196. trap_exception,
  197. trap_exception,
  198. trap_exception,
  199. trap_exception
  200. >;
  201. // default policy
  202. // One would use this first. After experimentation, one might
  203. // replace some actions with ignore_exception
  204. using default_exception_policy = strict_exception_policy;
  205. } // namespace safe_numerics
  206. } // namespace boost
  207. #endif // BOOST_NUMERIC_EXCEPTION_POLICIES_HPP