summaryrefslogtreecommitdiff
path: root/boost/safe_numerics/exception.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/safe_numerics/exception.hpp')
-rw-r--r--boost/safe_numerics/exception.hpp187
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