diff options
Diffstat (limited to 'boost/safe_numerics/exception.hpp')
-rw-r--r-- | boost/safe_numerics/exception.hpp | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/boost/safe_numerics/exception.hpp b/boost/safe_numerics/exception.hpp new file mode 100644 index 0000000000..b67f74fb97 --- /dev/null +++ b/boost/safe_numerics/exception.hpp @@ -0,0 +1,187 @@ +#ifndef BOOST_NUMERIC_EXCEPTION +#define BOOST_NUMERIC_EXCEPTION + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// Copyright (c) 2012 Robert Ramey +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// contains error indicators for results of doing checked +// arithmetic on native C++ types + +#include <algorithm> +#include <system_error> // error_code, system_error +#include <string> +#include <cassert> +#include <cstdint> // std::uint8_t + +// Using the system_error code facility. This facility is more complex +// than meets the eye. To fully understand what out intent here is, +// review http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html +// "Giving context-specific meaning to generic error codes" + +namespace boost { +namespace safe_numerics { + +// errors codes for safe numerics + +// in spite of the similarity, this list is distinct from the exceptions +// listed in documentation for std::exception. + +// note: Don't reorder these. Code in the file checked_result_operations.hpp +// depends upon this order !!! +enum class safe_numerics_error : std::uint8_t { + success = 0, + positive_overflow_error, // result is above representational maximum + negative_overflow_error, // result is below representational minimum + domain_error, // one operand is out of valid range + range_error, // result cannot be produced for this operation + precision_overflow_error, // result lost precision + underflow_error, // result is too small to be represented + negative_value_shift, // negative value in shift operator + negative_shift, // shift a negative value + shift_too_large, // l/r shift exceeds variable size + uninitialized_value // l/r shift exceeds variable size +}; + +const std::uint8_t safe_numerics_casting_error_count = + static_cast<std::uint8_t>(safe_numerics_error::domain_error) + 1; + +const std::uint8_t safe_numerics_error_count = + static_cast<std::uint8_t>(safe_numerics_error::uninitialized_value) + 1; + +} // safe_numerics +} // boost + +namespace std { + template <> + struct is_error_code_enum<boost::safe_numerics::safe_numerics_error> + : public true_type {}; +}; + +namespace boost { +namespace safe_numerics { + +const class : public std::error_category { +public: + virtual const char* name() const noexcept{ + return "safe numerics error"; + } + virtual std::string message(int ev) const { + switch(static_cast<safe_numerics_error>(ev)){ + case safe_numerics_error::success: + return "success"; + case safe_numerics_error::positive_overflow_error: + return "positive overflow error"; + case safe_numerics_error::negative_overflow_error: + return "negative overflow error"; + case safe_numerics_error::underflow_error: + return "underflow error"; + case safe_numerics_error::range_error: + return "range error"; + case safe_numerics_error::domain_error: + return "domain error"; + case safe_numerics_error::negative_shift: + return "negative shift"; + case safe_numerics_error::negative_value_shift: + return "negative value shift"; + case safe_numerics_error::shift_too_large: + return "shift too large"; + case safe_numerics_error::uninitialized_value: + return "uninitialized value"; + default: + assert(false); + } + return ""; // suppress bogus warning + } +} safe_numerics_error_category ; + +// constexpr - damn, can't use constexpr due to std::error_code +std::error_code make_error_code(safe_numerics_error e){ + return std::error_code(static_cast<int>(e), safe_numerics_error_category); +} + +// actions for error_codes for safe numerics. I've leveraged on +// error_condition in order to do this. I'm not sure this is a good +// idea or not. + +enum class safe_numerics_actions { + no_action = 0, + uninitialized_value, + arithmetic_error, + implementation_defined_behavior, + undefined_behavior +}; + +} // safe_numerics +} // boost + +namespace std { + template <> + struct is_error_condition_enum<boost::safe_numerics::safe_numerics_actions> + : public true_type {}; +}; + +namespace boost { +namespace safe_numerics { + +const class : public std::error_category { +public: + virtual const char* name() const noexcept { + return "safe numerics error group"; + } + virtual std::string message(int) const { + return "safe numerics error group"; + } + // return true if a given error code corresponds to a + // given safe numeric action + virtual bool equivalent( + const std::error_code & code, + int condition + ) const noexcept { + if(code.category() != safe_numerics_error_category) + return false; + switch (static_cast<safe_numerics_actions>(condition)){ + case safe_numerics_actions::no_action: + return code == safe_numerics_error::success; + case safe_numerics_actions::uninitialized_value: + return code == safe_numerics_error::uninitialized_value; + case safe_numerics_actions::arithmetic_error: + return code == safe_numerics_error::positive_overflow_error + || code == safe_numerics_error::negative_overflow_error + || code == safe_numerics_error::underflow_error + || code == safe_numerics_error::range_error + || code == safe_numerics_error::domain_error; + case safe_numerics_actions::implementation_defined_behavior: + return code == safe_numerics_error::negative_value_shift + || code == safe_numerics_error::negative_shift + || code == safe_numerics_error::shift_too_large; + case safe_numerics_actions::undefined_behavior: + return false; + default: + ; + } + // should never arrive here + assert(false); + // suppress bogus warning + return false; + } +} safe_numerics_actions_category ; + +std::error_condition make_error_condition(safe_numerics_error e) { + return std::error_condition( + static_cast<int>(e), + safe_numerics_error_category + ); +} + +} // safe_numerics +} // boost + +#endif // BOOST_NUMERIC_CHECKED_RESULT |