safe_base.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #ifndef BOOST_NUMERIC_SAFE_BASE_HPP
  2. #define BOOST_NUMERIC_SAFE_BASE_HPP
  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. #include <limits>
  9. #include <type_traits> // is_integral, enable_if, conditional
  10. #include <boost/config.hpp> // BOOST_CLANG
  11. #include "concept/exception_policy.hpp"
  12. #include "concept/promotion_policy.hpp"
  13. #include "safe_common.hpp"
  14. #include "exception_policies.hpp"
  15. #include "boost/concept/assert.hpp"
  16. namespace boost {
  17. namespace safe_numerics {
  18. /////////////////////////////////////////////////////////////////
  19. // forward declarations to support friend function declarations
  20. // in safe_base
  21. template<
  22. class Stored,
  23. Stored Min,
  24. Stored Max,
  25. class P, // promotion polic
  26. class E // exception policy
  27. >
  28. class safe_base;
  29. template<
  30. class T,
  31. T Min,
  32. T Max,
  33. class P,
  34. class E
  35. >
  36. struct is_safe<safe_base<T, Min, Max, P, E> > : public std::true_type
  37. {};
  38. template<
  39. class T,
  40. T Min,
  41. T Max,
  42. class P,
  43. class E
  44. >
  45. struct get_promotion_policy<safe_base<T, Min, Max, P, E> > {
  46. using type = P;
  47. };
  48. template<
  49. class T,
  50. T Min,
  51. T Max,
  52. class P,
  53. class E
  54. >
  55. struct get_exception_policy<safe_base<T, Min, Max, P, E> > {
  56. using type = E;
  57. };
  58. template<
  59. class T,
  60. T Min,
  61. T Max,
  62. class P,
  63. class E
  64. >
  65. struct base_type<safe_base<T, Min, Max, P, E> > {
  66. using type = T;
  67. };
  68. template<
  69. class T,
  70. T Min,
  71. T Max,
  72. class P,
  73. class E
  74. >
  75. constexpr T base_value(
  76. const safe_base<T, Min, Max, P, E> & st
  77. ) {
  78. return static_cast<T>(st);
  79. }
  80. template<
  81. typename T,
  82. T N,
  83. class P, // promotion policy
  84. class E // exception policy
  85. >
  86. class safe_literal_impl;
  87. // works for both GCC and clang
  88. #if BOOST_CLANG==1
  89. #pragma GCC diagnostic push
  90. #pragma GCC diagnostic ignored "-Wmismatched-tags"
  91. #endif
  92. /////////////////////////////////////////////////////////////////
  93. // Main implementation
  94. template<
  95. class Stored,
  96. Stored Min,
  97. Stored Max,
  98. class P, // promotion polic
  99. class E // exception policy
  100. >
  101. class safe_base {
  102. private:
  103. BOOST_CONCEPT_ASSERT((PromotionPolicy<P>));
  104. BOOST_CONCEPT_ASSERT((ExceptionPolicy<E>));
  105. Stored m_t;
  106. template<
  107. class StoredX,
  108. StoredX MinX,
  109. StoredX MaxX,
  110. class PX, // promotion polic
  111. class EX // exception policy
  112. >
  113. friend class safe_base;
  114. friend class std::numeric_limits<safe_base>;
  115. template<class T>
  116. constexpr Stored validated_cast(const T & t) const;
  117. template<typename T, T N, class P1, class E1>
  118. constexpr Stored validated_cast(
  119. const safe_literal_impl<T, N, P1, E1> & t
  120. ) const;
  121. // stream support
  122. template<class CharT, class Traits>
  123. void output(std::basic_ostream<CharT, Traits> & os) const;
  124. // note usage of friend declaration to mark function as
  125. // a global function rather than a member function. If
  126. // this is not done, the compiler will confuse this with
  127. // a member operator overload on the << operator. Weird
  128. // I know. But it's documented here
  129. // http://en.cppreference.com/w/cpp/language/friend
  130. // under the heading "Template friend operators"
  131. template<class CharT, class Traits>
  132. friend std::basic_ostream<CharT, Traits> &
  133. operator<<(
  134. std::basic_ostream<CharT, Traits> & os,
  135. const safe_base & t
  136. ){
  137. t.output(os);
  138. return os;
  139. }
  140. template<class CharT, class Traits>
  141. void input(std::basic_istream<CharT, Traits> & is);
  142. // see above
  143. template<class CharT, class Traits>
  144. friend inline std::basic_istream<CharT, Traits> &
  145. operator>>(
  146. std::basic_istream<CharT, Traits> & is,
  147. safe_base & t
  148. ){
  149. t.input(is);
  150. return is;
  151. }
  152. public:
  153. ////////////////////////////////////////////////////////////
  154. // constructors
  155. struct skip_validation{};
  156. constexpr explicit safe_base(const Stored & rhs, skip_validation);
  157. constexpr safe_base();
  158. // construct an instance of a safe type
  159. // from an instance of a convertible underlying type.
  160. template<class T>
  161. constexpr /*explicit*/ safe_base(
  162. const T & t,
  163. typename std::enable_if<
  164. is_safe<T>::value,
  165. bool
  166. >::type = true
  167. );
  168. template<class T>
  169. constexpr /*explicit*/ safe_base(
  170. const T & t,
  171. typename std::enable_if<
  172. std::is_integral<T>::value,
  173. bool
  174. >::type = true
  175. );
  176. template<class T, T value>
  177. constexpr /*explicit*/ safe_base(
  178. const std::integral_constant<T, value> &
  179. );
  180. // note: Rule of Five. Supply all or none of the following
  181. // a) user-defined destructor
  182. ~safe_base() = default;
  183. // b) copy-constructor
  184. constexpr safe_base(const safe_base &) = default;
  185. // c) copy-assignment
  186. constexpr safe_base & operator=(const safe_base &) = default;
  187. // d) move constructor
  188. constexpr safe_base(safe_base &&) = default;
  189. // e) move assignment operator
  190. constexpr safe_base & operator=(safe_base &&) = default;
  191. /////////////////////////////////////////////////////////////////
  192. // casting operators for intrinsic integers
  193. // convert to any type which is not safe. safe types need to be
  194. // excluded to prevent ambiguous function selection which
  195. // would otherwise occur. validity of safe types is checked in
  196. // the constructor of safe types
  197. template<
  198. class R,
  199. typename std::enable_if<
  200. ! boost::safe_numerics::is_safe<R>::value,
  201. int
  202. >::type = 0
  203. >
  204. constexpr /*explicit*/ operator R () const;
  205. constexpr /*explicit*/ operator Stored () const;
  206. /////////////////////////////////////////////////////////////////
  207. // modification binary operators
  208. template<class T>
  209. constexpr safe_base &
  210. operator=(const T & rhs){
  211. m_t = validated_cast(rhs);
  212. return *this;
  213. }
  214. // required to passify VS2017
  215. constexpr safe_base &
  216. operator=(const Stored & rhs){
  217. m_t = validated_cast(rhs);
  218. return *this;
  219. }
  220. // mutating unary operators
  221. safe_base & operator++(){ // pre increment
  222. return *this = *this + 1;
  223. }
  224. safe_base & operator--(){ // pre decrement
  225. return *this = *this - 1;
  226. }
  227. safe_base operator++(int){ // post increment
  228. safe_base old_t = *this;
  229. ++(*this);
  230. return old_t;
  231. }
  232. safe_base operator--(int){ // post decrement
  233. safe_base old_t = *this;
  234. --(*this);
  235. return old_t;
  236. }
  237. // non mutating unary operators
  238. constexpr auto operator+() const { // unary plus
  239. return *this;
  240. }
  241. // after much consideration, I've permited the resulting value of a unary
  242. // - to change the type. The C++ standard does invoke integral promotions
  243. // so it's changing the type as well.
  244. /* section 5.3.1 &8 of the C++ standard
  245. The operand of the unary - operator shall have arithmetic or unscoped
  246. enumeration type and the result is the negation of its operand. Integral
  247. promotion is performed on integral or enumeration operands. The negative
  248. of an unsigned quantity is computed by subtracting its value from 2n,
  249. where n is the number of bits in the promoted operand. The type of the
  250. result is the type of the promoted operand.
  251. */
  252. constexpr auto operator-() const { // unary minus
  253. // if this is a unsigned type and the promotion policy is native
  254. // the result will be unsigned. But then the operation will fail
  255. // according to the requirements of arithmetic correctness.
  256. // if this is an unsigned type and the promotion policy is automatic.
  257. // the result will be signed.
  258. return 0 - *this;
  259. }
  260. /* section 5.3.1 &10 of the C++ standard
  261. The operand of ~ shall have integral or unscoped enumeration type;
  262. the result is the ones’ complement of its operand. Integral promotions
  263. are performed. The type of the result is the type of the promoted operand.
  264. */
  265. constexpr auto operator~() const { // complement
  266. return ~Stored(0u) ^ *this;
  267. }
  268. };
  269. } // safe_numerics
  270. } // boost
  271. /////////////////////////////////////////////////////////////////
  272. // numeric limits for safe<int> etc.
  273. #include <limits>
  274. namespace std {
  275. template<
  276. class T,
  277. T Min,
  278. T Max,
  279. class P,
  280. class E
  281. >
  282. class numeric_limits<boost::safe_numerics::safe_base<T, Min, Max, P, E> >
  283. : public std::numeric_limits<T>
  284. {
  285. using SB = boost::safe_numerics::safe_base<T, Min, Max, P, E>;
  286. public:
  287. constexpr static SB lowest() noexcept {
  288. return SB(Min, typename SB::skip_validation());
  289. }
  290. constexpr static SB min() noexcept {
  291. return SB(Min, typename SB::skip_validation());
  292. }
  293. constexpr static SB max() noexcept {
  294. return SB(Max, typename SB::skip_validation());
  295. }
  296. };
  297. } // std
  298. #if BOOST_CLANG==1
  299. #pragma GCC diagnostic pop
  300. #endif
  301. #endif // BOOST_NUMERIC_SAFE_BASE_HPP