exception_policies.hpp 7.1 KB

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