exception.hpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #ifndef BOOST_NUMERIC_EXCEPTION
  2. #define BOOST_NUMERIC_EXCEPTION
  3. // Copyright (c) 2012 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. // contains error indicators for results of doing checked
  9. // arithmetic on native C++ types
  10. #include <algorithm>
  11. #include <system_error> // error_code, system_error
  12. #include <string>
  13. #include <cassert>
  14. #include <cstdint> // std::uint8_t
  15. // Using the system_error code facility. This facility is more complex
  16. // than meets the eye. To fully understand what out intent here is,
  17. // review http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html
  18. // "Giving context-specific meaning to generic error codes"
  19. namespace boost {
  20. namespace safe_numerics {
  21. // errors codes for safe numerics
  22. // in spite of the similarity, this list is distinct from the exceptions
  23. // listed in documentation for std::exception.
  24. // note: Don't reorder these. Code in the file checked_result_operations.hpp
  25. // depends upon this order !!!
  26. enum class safe_numerics_error : std::uint8_t {
  27. success = 0,
  28. positive_overflow_error, // result is above representational maximum
  29. negative_overflow_error, // result is below representational minimum
  30. domain_error, // one operand is out of valid range
  31. range_error, // result cannot be produced for this operation
  32. precision_overflow_error, // result lost precision
  33. underflow_error, // result is too small to be represented
  34. negative_value_shift, // negative value in shift operator
  35. negative_shift, // shift a negative value
  36. shift_too_large, // l/r shift exceeds variable size
  37. uninitialized_value // creating of uninitialized value
  38. };
  39. constexpr inline const char * literal_string(const safe_numerics_error & e){
  40. switch(e){
  41. case safe_numerics_error::success: return "success";
  42. case safe_numerics_error::positive_overflow_error: return "positive_overflow_error";
  43. case safe_numerics_error::negative_overflow_error: return "negative_overflow_error";
  44. case safe_numerics_error::domain_error: return "domain_error";
  45. case safe_numerics_error::range_error: return "range_error";
  46. case safe_numerics_error::precision_overflow_error: return "precision_overflow_error";
  47. case safe_numerics_error::underflow_error: return "underflow_error";
  48. case safe_numerics_error::negative_value_shift: return "negative_value_shift";
  49. case safe_numerics_error::negative_shift: return "negative_shift";
  50. case safe_numerics_error::shift_too_large: return "shift_too_large";
  51. case safe_numerics_error::uninitialized_value: return "uninitialized_value";
  52. default:
  53. assert(false); // should never arrive here
  54. }
  55. }
  56. const std::uint8_t safe_numerics_casting_error_count =
  57. static_cast<std::uint8_t>(safe_numerics_error::domain_error) + 1;
  58. const std::uint8_t safe_numerics_error_count =
  59. static_cast<std::uint8_t>(safe_numerics_error::uninitialized_value) + 1;
  60. } // safe_numerics
  61. } // boost
  62. namespace std {
  63. template <>
  64. struct is_error_code_enum<boost::safe_numerics::safe_numerics_error>
  65. : public true_type {};
  66. } // std
  67. namespace boost {
  68. namespace safe_numerics {
  69. const class : public std::error_category {
  70. public:
  71. virtual const char* name() const noexcept{
  72. return "safe numerics error";
  73. }
  74. virtual std::string message(int ev) const {
  75. switch(static_cast<safe_numerics_error>(ev)){
  76. case safe_numerics_error::success:
  77. return "success";
  78. case safe_numerics_error::positive_overflow_error:
  79. return "positive overflow error";
  80. case safe_numerics_error::negative_overflow_error:
  81. return "negative overflow error";
  82. case safe_numerics_error::underflow_error:
  83. return "underflow error";
  84. case safe_numerics_error::range_error:
  85. return "range error";
  86. case safe_numerics_error::precision_overflow_error:
  87. return "precision_overflow_error";
  88. case safe_numerics_error::domain_error:
  89. return "domain error";
  90. case safe_numerics_error::negative_shift:
  91. return "negative shift";
  92. case safe_numerics_error::negative_value_shift:
  93. return "negative value shift";
  94. case safe_numerics_error::shift_too_large:
  95. return "shift too large";
  96. case safe_numerics_error::uninitialized_value:
  97. return "uninitialized value";
  98. default:
  99. assert(false);
  100. }
  101. return ""; // suppress bogus warning
  102. }
  103. } safe_numerics_error_category {};
  104. // constexpr - damn, can't use constexpr due to std::error_code
  105. inline std::error_code make_error_code(const safe_numerics_error & e){
  106. return std::error_code(static_cast<int>(e), safe_numerics_error_category);
  107. }
  108. // actions for error_codes for safe numerics. I've leveraged on
  109. // error_condition in order to do this. I'm not sure this is a good
  110. // idea or not.
  111. enum class safe_numerics_actions {
  112. no_action = 0,
  113. uninitialized_value,
  114. arithmetic_error,
  115. implementation_defined_behavior,
  116. undefined_behavior
  117. };
  118. } // safe_numerics
  119. } // boost
  120. namespace std {
  121. template <>
  122. struct is_error_condition_enum<boost::safe_numerics::safe_numerics_actions>
  123. : public true_type {};
  124. } // std
  125. namespace boost {
  126. namespace safe_numerics {
  127. const class : public std::error_category {
  128. public:
  129. virtual const char* name() const noexcept {
  130. return "safe numerics error group";
  131. }
  132. virtual std::string message(int) const {
  133. return "safe numerics error group";
  134. }
  135. // return true if a given error code corresponds to a
  136. // given safe numeric action
  137. virtual bool equivalent(
  138. const std::error_code & code,
  139. int condition
  140. ) const noexcept {
  141. if(code.category() != safe_numerics_error_category)
  142. return false;
  143. switch (static_cast<safe_numerics_actions>(condition)){
  144. case safe_numerics_actions::no_action:
  145. return code == safe_numerics_error::success;
  146. case safe_numerics_actions::uninitialized_value:
  147. return code == safe_numerics_error::uninitialized_value;
  148. case safe_numerics_actions::arithmetic_error:
  149. return code == safe_numerics_error::positive_overflow_error
  150. || code == safe_numerics_error::negative_overflow_error
  151. || code == safe_numerics_error::underflow_error
  152. || code == safe_numerics_error::range_error
  153. || code == safe_numerics_error::domain_error;
  154. case safe_numerics_actions::implementation_defined_behavior:
  155. return code == safe_numerics_error::negative_value_shift
  156. || code == safe_numerics_error::negative_shift
  157. || code == safe_numerics_error::shift_too_large;
  158. case safe_numerics_actions::undefined_behavior:
  159. return false;
  160. default:
  161. ;
  162. }
  163. // should never arrive here
  164. assert(false);
  165. // suppress bogus warning
  166. return false;
  167. }
  168. } safe_numerics_actions_category {};
  169. // the following function is used to "finish" implementation of conversion
  170. // of safe_numerics_error to std::error_condition. At least for now, this
  171. // isn't being used and defining here it can lead duplicate symbol errors
  172. // depending on the compiler. So suppress it until further notice
  173. #if 0
  174. std::error_condition make_error_condition(const safe_numerics_error & e) {
  175. return std::error_condition(
  176. static_cast<int>(e),
  177. safe_numerics_error_category
  178. );
  179. }
  180. #endif
  181. } // safe_numerics
  182. } // boost
  183. #endif // BOOST_NUMERIC_CHECKED_RESULT