exception_policies.hpp 7.3 KB

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