1 #ifndef BOOST_NUMERIC_CHECKED_RESULT 2 #define BOOST_NUMERIC_CHECKED_RESULT 3 4 // Copyright (c) 2012 Robert Ramey 5 // 6 // Distributed under the Boost Software License, Version 1.0. (See 7 // accompanying file LICENSE_1_0.txt or copy at 8 // http://www.boost.org/LICENSE_1_0.txt) 9 10 // contains operations for doing checked aritmetic on NATIVE 11 // C++ types. 12 #include <cassert> 13 #include <type_traits> // is_convertible 14 #include "exception.hpp" 15 16 namespace boost { 17 namespace safe_numerics { 18 19 template<typename R> 20 struct checked_result { 21 const safe_numerics_error m_e; 22 const union { 23 R m_r; 24 char const * m_msg; 25 }; 26 27 // don't permit construction without initial value; 28 checked_result() = delete; 29 30 // note: I implemented the following non-default copy and move 31 // constructors because I thought I needed to do this in order 32 // to make them constexpr. Turns out though that doing this creates 33 // a syntax error because the assignment results in error due 34 // to assignment "outside of object lifetime". I think this could 35 // be addressed by replacing the anonymous union above with a 36 // named union. This would create some syntax changes which would 37 // ripple through some parts of th program. So for now, we'll just 38 // rely on the default copy and move constructors. 39 #if 0 40 // copy constructor 41 constexpr /*explicit*/ checked_result(const checked_result & r) noexpect : 42 m_e(r.m_e) 43 { 44 if(safe_numerics_error::success == r.m_e) 45 m_r = r.m_r; 46 else 47 m_msg = r.m_msg; 48 } 49 50 // move constructor 51 constexpr /*explicit*/ checked_result(checked_result && r) noexcept : 52 m_e(r.m_e) 53 { 54 if(safe_numerics_error::success == r.m_e) 55 m_r = r.m_r; 56 else 57 m_msg = r.m_msg; 58 } 59 #endif 60 checked_result(const checked_result & r) = default; 61 checked_result(checked_result && r) = default; 62 checked_resultboost::safe_numerics::checked_result63 constexpr /*explicit*/ checked_result(const R & r) : 64 m_e(safe_numerics_error::success), 65 m_r(r) 66 {} 67 #if 0 68 template<typename T> 69 constexpr /*explicit*/ checked_result(const T & t) noexcept : 70 m_e(safe_numerics_error::success), 71 m_r(t) 72 {} 73 #endif checked_resultboost::safe_numerics::checked_result74 constexpr /*explicit*/ checked_result( 75 const safe_numerics_error & e, 76 const char * msg = "" 77 ) noexcept : 78 m_e(e), 79 m_msg(msg) 80 { 81 assert(m_e != safe_numerics_error::success); 82 } 83 // permit construct from another checked result type 84 template<typename T> checked_resultboost::safe_numerics::checked_result85 constexpr /*explicit*/ checked_result(const checked_result<T> & t) noexcept : 86 m_e(t.m_e) 87 { 88 static_assert( 89 std::is_convertible<T, R>::value, 90 "T must be convertible to R" 91 ); 92 if(safe_numerics_error::success == t.m_e) 93 m_r = t.m_r; 94 else 95 m_msg = t.m_msg; 96 } exceptionboost::safe_numerics::checked_result97 constexpr bool exception() const { 98 return m_e != safe_numerics_error::success; 99 } 100 101 // accesors operator Rboost::safe_numerics::checked_result102 constexpr operator R() const noexcept{ 103 // don't assert here. Let the library catch these errors 104 assert(! exception()); 105 return m_r; 106 } 107 operator safe_numerics_errorboost::safe_numerics::checked_result108 constexpr operator safe_numerics_error () const noexcept{ 109 // note that this is a legitimate operation even when 110 // the operation was successful - it will return success 111 return m_e; 112 } operator const char*boost::safe_numerics::checked_result113 constexpr operator const char *() const noexcept{ 114 assert(exception()); 115 return m_msg; 116 } 117 118 // disallow assignment 119 checked_result & operator=(const checked_result &) = delete; 120 }; 121 122 #if 0 123 template<typename R> 124 constexpr checked_result<R> make_checked_result( 125 const safe_numerics_error & e, 126 char const * const & m 127 ) noexcept { 128 return checked_result<R>(e, m); 129 } 130 #endif 131 132 template <class R> 133 class make_checked_result { 134 public: 135 template<safe_numerics_error E> invoke(char const * const & m)136 constexpr static checked_result<R> invoke( 137 char const * const & m 138 ) noexcept { 139 return checked_result<R>(E, m); 140 } 141 }; 142 143 } // safe_numerics 144 } // boost 145 146 #endif // BOOST_NUMERIC_CHECKED_RESULT 147