File indexing completed on 2025-01-18 09:51:36
0001 #ifndef BOOST_NUMERIC_EXCEPTION
0002 #define BOOST_NUMERIC_EXCEPTION
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <algorithm>
0014 #include <system_error> // error_code, system_error
0015 #include <string>
0016 #include <cassert>
0017 #include <cstdint> // std::uint8_t
0018
0019
0020
0021
0022
0023
0024 namespace boost {
0025 namespace safe_numerics {
0026
0027
0028
0029
0030
0031
0032
0033
0034 enum class safe_numerics_error : std::uint8_t {
0035 success = 0,
0036 positive_overflow_error,
0037 negative_overflow_error,
0038 domain_error,
0039 range_error,
0040 precision_overflow_error,
0041 underflow_error,
0042 negative_value_shift,
0043 negative_shift,
0044 shift_too_large,
0045 uninitialized_value
0046 };
0047
0048 constexpr inline const char * literal_string(const safe_numerics_error & e){
0049 switch(e){
0050 case safe_numerics_error::success: return "success";
0051 case safe_numerics_error::positive_overflow_error: return "positive_overflow_error";
0052 case safe_numerics_error::negative_overflow_error: return "negative_overflow_error";
0053 case safe_numerics_error::domain_error: return "domain_error";
0054 case safe_numerics_error::range_error: return "range_error";
0055 case safe_numerics_error::precision_overflow_error: return "precision_overflow_error";
0056 case safe_numerics_error::underflow_error: return "underflow_error";
0057 case safe_numerics_error::negative_value_shift: return "negative_value_shift";
0058 case safe_numerics_error::negative_shift: return "negative_shift";
0059 case safe_numerics_error::shift_too_large: return "shift_too_large";
0060 case safe_numerics_error::uninitialized_value: return "uninitialized_value";
0061 default:
0062 assert(false);
0063 }
0064 }
0065
0066 const std::uint8_t safe_numerics_casting_error_count =
0067 static_cast<std::uint8_t>(safe_numerics_error::domain_error) + 1;
0068
0069 const std::uint8_t safe_numerics_error_count =
0070 static_cast<std::uint8_t>(safe_numerics_error::uninitialized_value) + 1;
0071
0072 }
0073 }
0074
0075 namespace std {
0076 template <>
0077 struct is_error_code_enum<boost::safe_numerics::safe_numerics_error>
0078 : public true_type {};
0079 }
0080
0081 namespace boost {
0082 namespace safe_numerics {
0083
0084 const class : public std::error_category {
0085 public:
0086 virtual const char* name() const noexcept{
0087 return "safe numerics error";
0088 }
0089 virtual std::string message(int ev) const {
0090 switch(static_cast<safe_numerics_error>(ev)){
0091 case safe_numerics_error::success:
0092 return "success";
0093 case safe_numerics_error::positive_overflow_error:
0094 return "positive overflow error";
0095 case safe_numerics_error::negative_overflow_error:
0096 return "negative overflow error";
0097 case safe_numerics_error::underflow_error:
0098 return "underflow error";
0099 case safe_numerics_error::range_error:
0100 return "range error";
0101 case safe_numerics_error::precision_overflow_error:
0102 return "precision_overflow_error";
0103 case safe_numerics_error::domain_error:
0104 return "domain error";
0105 case safe_numerics_error::negative_shift:
0106 return "negative shift";
0107 case safe_numerics_error::negative_value_shift:
0108 return "negative value shift";
0109 case safe_numerics_error::shift_too_large:
0110 return "shift too large";
0111 case safe_numerics_error::uninitialized_value:
0112 return "uninitialized value";
0113 default:
0114 assert(false);
0115 }
0116 return "";
0117 }
0118 } safe_numerics_error_category {};
0119
0120
0121 inline std::error_code make_error_code(const safe_numerics_error & e){
0122 return std::error_code(static_cast<int>(e), safe_numerics_error_category);
0123 }
0124
0125
0126
0127
0128
0129 enum class safe_numerics_actions {
0130 no_action = 0,
0131 uninitialized_value,
0132 arithmetic_error,
0133 implementation_defined_behavior,
0134 undefined_behavior
0135 };
0136
0137 }
0138 }
0139
0140 namespace std {
0141 template <>
0142 struct is_error_condition_enum<boost::safe_numerics::safe_numerics_actions>
0143 : public true_type {};
0144 }
0145
0146 namespace boost {
0147 namespace safe_numerics {
0148
0149 const class : public std::error_category {
0150 public:
0151 virtual const char* name() const noexcept {
0152 return "safe numerics error group";
0153 }
0154 virtual std::string message(int) const {
0155 return "safe numerics error group";
0156 }
0157
0158
0159 virtual bool equivalent(
0160 const std::error_code & code,
0161 int condition
0162 ) const noexcept {
0163 if(code.category() != safe_numerics_error_category)
0164 return false;
0165 switch (static_cast<safe_numerics_actions>(condition)){
0166 case safe_numerics_actions::no_action:
0167 return code == safe_numerics_error::success;
0168 case safe_numerics_actions::uninitialized_value:
0169 return code == safe_numerics_error::uninitialized_value;
0170 case safe_numerics_actions::arithmetic_error:
0171 return code == safe_numerics_error::positive_overflow_error
0172 || code == safe_numerics_error::negative_overflow_error
0173 || code == safe_numerics_error::underflow_error
0174 || code == safe_numerics_error::range_error
0175 || code == safe_numerics_error::domain_error;
0176 case safe_numerics_actions::implementation_defined_behavior:
0177 return code == safe_numerics_error::negative_value_shift
0178 || code == safe_numerics_error::negative_shift
0179 || code == safe_numerics_error::shift_too_large;
0180 case safe_numerics_actions::undefined_behavior:
0181 return false;
0182 default:
0183 ;
0184 }
0185
0186 assert(false);
0187
0188 return false;
0189 }
0190 } safe_numerics_actions_category {};
0191
0192
0193
0194
0195
0196 #if 0
0197 std::error_condition make_error_condition(const safe_numerics_error & e) {
0198 return std::error_condition(
0199 static_cast<int>(e),
0200 safe_numerics_error_category
0201 );
0202 }
0203 #endif
0204
0205 }
0206 }
0207
0208 #endif