exception.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. const std::uint8_t safe_numerics_casting_error_count =
  40. static_cast<std::uint8_t>(safe_numerics_error::domain_error) + 1;
  41. const std::uint8_t safe_numerics_error_count =
  42. static_cast<std::uint8_t>(safe_numerics_error::uninitialized_value) + 1;
  43. } // safe_numerics
  44. } // boost
  45. namespace std {
  46. template <>
  47. struct is_error_code_enum<boost::safe_numerics::safe_numerics_error>
  48. : public true_type {};
  49. } // std
  50. namespace boost {
  51. namespace safe_numerics {
  52. const class : public std::error_category {
  53. public:
  54. virtual const char* name() const noexcept{
  55. return "safe numerics error";
  56. }
  57. virtual std::string message(int ev) const {
  58. switch(static_cast<safe_numerics_error>(ev)){
  59. case safe_numerics_error::success:
  60. return "success";
  61. case safe_numerics_error::positive_overflow_error:
  62. return "positive overflow error";
  63. case safe_numerics_error::negative_overflow_error:
  64. return "negative overflow error";
  65. case safe_numerics_error::underflow_error:
  66. return "underflow error";
  67. case safe_numerics_error::range_error:
  68. return "range error";
  69. case safe_numerics_error::domain_error:
  70. return "domain error";
  71. case safe_numerics_error::negative_shift:
  72. return "negative shift";
  73. case safe_numerics_error::negative_value_shift:
  74. return "negative value shift";
  75. case safe_numerics_error::shift_too_large:
  76. return "shift too large";
  77. case safe_numerics_error::uninitialized_value:
  78. return "uninitialized value";
  79. default:
  80. assert(false);
  81. }
  82. return ""; // suppress bogus warning
  83. }
  84. } safe_numerics_error_category {};
  85. // constexpr - damn, can't use constexpr due to std::error_code
  86. inline std::error_code make_error_code(const safe_numerics_error & e){
  87. return std::error_code(static_cast<int>(e), safe_numerics_error_category);
  88. }
  89. // actions for error_codes for safe numerics. I've leveraged on
  90. // error_condition in order to do this. I'm not sure this is a good
  91. // idea or not.
  92. enum class safe_numerics_actions {
  93. no_action = 0,
  94. uninitialized_value,
  95. arithmetic_error,
  96. implementation_defined_behavior,
  97. undefined_behavior
  98. };
  99. } // safe_numerics
  100. } // boost
  101. namespace std {
  102. template <>
  103. struct is_error_condition_enum<boost::safe_numerics::safe_numerics_actions>
  104. : public true_type {};
  105. } // std
  106. namespace boost {
  107. namespace safe_numerics {
  108. const class : public std::error_category {
  109. public:
  110. virtual const char* name() const noexcept {
  111. return "safe numerics error group";
  112. }
  113. virtual std::string message(int) const {
  114. return "safe numerics error group";
  115. }
  116. // return true if a given error code corresponds to a
  117. // given safe numeric action
  118. virtual bool equivalent(
  119. const std::error_code & code,
  120. int condition
  121. ) const noexcept {
  122. if(code.category() != safe_numerics_error_category)
  123. return false;
  124. switch (static_cast<safe_numerics_actions>(condition)){
  125. case safe_numerics_actions::no_action:
  126. return code == safe_numerics_error::success;
  127. case safe_numerics_actions::uninitialized_value:
  128. return code == safe_numerics_error::uninitialized_value;
  129. case safe_numerics_actions::arithmetic_error:
  130. return code == safe_numerics_error::positive_overflow_error
  131. || code == safe_numerics_error::negative_overflow_error
  132. || code == safe_numerics_error::underflow_error
  133. || code == safe_numerics_error::range_error
  134. || code == safe_numerics_error::domain_error;
  135. case safe_numerics_actions::implementation_defined_behavior:
  136. return code == safe_numerics_error::negative_value_shift
  137. || code == safe_numerics_error::negative_shift
  138. || code == safe_numerics_error::shift_too_large;
  139. case safe_numerics_actions::undefined_behavior:
  140. return false;
  141. default:
  142. ;
  143. }
  144. // should never arrive here
  145. assert(false);
  146. // suppress bogus warning
  147. return false;
  148. }
  149. } safe_numerics_actions_category {};
  150. // the following function is used to "finish" implementation of conversion
  151. // of safe_numerics_error to std::error_condition. At least for now, this
  152. // isn't being used and defining here it can lead duplicate symbol errors
  153. // depending on the compiler. So suppress it until further notice
  154. #if 0
  155. std::error_condition make_error_condition(const safe_numerics_error & e) {
  156. return std::error_condition(
  157. static_cast<int>(e),
  158. safe_numerics_error_category
  159. );
  160. }
  161. #endif
  162. } // safe_numerics
  163. } // boost
  164. #endif // BOOST_NUMERIC_CHECKED_RESULT