checked_result.hpp 4.0 KB

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