Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:36

0001 #ifndef BOOST_NUMERIC_EXCEPTION
0002 #define BOOST_NUMERIC_EXCEPTION
0003 
0004 //  Copyright (c) 2012 Robert Ramey
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See
0007 // accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 // contains error indicators for results of doing checked
0011 // arithmetic on native C++ types
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 // Using the system_error code facility.  This facility is more complex
0020 // than meets the eye.  To fully understand what out intent here is,
0021 // review http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html
0022 // "Giving context-specific meaning to generic error codes"
0023 
0024 namespace boost {
0025 namespace safe_numerics {
0026 
0027 // errors codes for safe numerics
0028 
0029 // in spite of the similarity, this list is distinct from the exceptions
0030 // listed in documentation for std::exception.
0031 
0032 // note: Don't reorder these.  Code in the file checked_result_operations.hpp
0033 // depends upon this order !!!
0034 enum class safe_numerics_error : std::uint8_t {
0035     success = 0,
0036     positive_overflow_error,    // result is above representational maximum
0037     negative_overflow_error,    // result is below representational minimum
0038     domain_error,               // one operand is out of valid range
0039     range_error,                // result cannot be produced for this operation
0040     precision_overflow_error,   // result lost precision
0041     underflow_error,            // result is too small to be represented
0042     negative_value_shift,       // negative value in shift operator
0043     negative_shift,             // shift a negative value
0044     shift_too_large,            // l/r shift exceeds variable size
0045     uninitialized_value         // creating of 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); // should never arrive here
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 } // safe_numerics
0073 } // boost
0074 
0075 namespace std {
0076     template <>
0077     struct is_error_code_enum<boost::safe_numerics::safe_numerics_error>
0078         : public true_type {};
0079 } // std
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 ""; // suppress bogus warning
0117     }
0118 } safe_numerics_error_category {};
0119 
0120 // constexpr - damn, can't use constexpr due to std::error_code
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 // actions for error_codes for safe numerics.  I've leveraged on
0126 // error_condition in order to do this.  I'm not sure this is a good
0127 // idea or not.
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 } // safe_numerics
0138 } // boost
0139 
0140 namespace std {
0141     template <>
0142     struct is_error_condition_enum<boost::safe_numerics::safe_numerics_actions>
0143         : public true_type {};
0144 } // std
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     // return true if a given error code corresponds to a
0158     // given safe numeric action
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         // should never arrive here
0186         assert(false);
0187         // suppress bogus warning
0188         return false; 
0189     }
0190 } safe_numerics_actions_category {};
0191 
0192 // the following function is used to "finish" implementation of conversion
0193 // of safe_numerics_error to std::error_condition.  At least for now, this
0194 // isn't being used and defining here it can lead duplicate symbol errors
0195 // depending on the compiler.  So suppress it until further notice
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 } // safe_numerics
0206 } // boost
0207 
0208 #endif // BOOST_NUMERIC_CHECKED_RESULT