safe_integer_literal.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
  2. #define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_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 <cstdint> // for intmax_t/uintmax_t
  9. #include <iosfwd>
  10. #include <type_traits> // conditional, enable_if
  11. #include <boost/mp11/utility.hpp>
  12. #include "utility.hpp"
  13. #include "safe_integer.hpp"
  14. #include "checked_integer.hpp"
  15. namespace boost {
  16. namespace safe_numerics {
  17. template<typename T, T N, class P, class E>
  18. class safe_literal_impl;
  19. template<typename T, T N, class P, class E>
  20. struct is_safe<safe_literal_impl<T, N, P, E> > : public std::true_type
  21. {};
  22. template<typename T, T N, class P, class E>
  23. struct get_promotion_policy<safe_literal_impl<T, N, P, E> > {
  24. using type = P;
  25. };
  26. template<typename T, T N, class P, class E>
  27. struct get_exception_policy<safe_literal_impl<T, N, P, E> > {
  28. using type = E;
  29. };
  30. template<typename T, T N, class P, class E>
  31. struct base_type<safe_literal_impl<T, N, P, E> > {
  32. using type = T;
  33. };
  34. template<typename T, T N, class P, class E>
  35. constexpr T base_value(
  36. const safe_literal_impl<T, N, P, E> &
  37. ) {
  38. return N;
  39. }
  40. template<typename CharT, typename Traits, typename T, T N, class P, class E>
  41. inline std::basic_ostream<CharT, Traits> & operator<<(
  42. std::basic_ostream<CharT, Traits> & os,
  43. const safe_literal_impl<T, N, P, E> &
  44. ){
  45. return os << (
  46. (std::is_same<T, signed char>::value
  47. || std::is_same<T, unsigned char>::value
  48. ) ?
  49. static_cast<int>(N)
  50. :
  51. N
  52. );
  53. }
  54. template<typename T, T N, class P, class E>
  55. class safe_literal_impl {
  56. template<
  57. class CharT,
  58. class Traits
  59. >
  60. friend std::basic_ostream<CharT, Traits> & operator<<(
  61. std::basic_ostream<CharT, Traits> & os,
  62. const safe_literal_impl &
  63. ){
  64. return os << (
  65. (::std::is_same<T, signed char>::value
  66. || ::std::is_same<T, unsigned char>::value
  67. || ::std::is_same<T, wchar_t>::value
  68. ) ?
  69. static_cast<int>(N)
  70. :
  71. N
  72. );
  73. };
  74. public:
  75. ////////////////////////////////////////////////////////////
  76. // constructors
  77. // default constructor
  78. constexpr safe_literal_impl(){}
  79. /////////////////////////////////////////////////////////////////
  80. // casting operators for intrinsic integers
  81. // convert to any type which is not safe. safe types need to be
  82. // excluded to prevent ambiguous function selection which
  83. // would otherwise occur
  84. template<
  85. class R,
  86. typename std::enable_if<
  87. ! boost::safe_numerics::is_safe<R>::value,
  88. int
  89. >::type = 0
  90. >
  91. constexpr operator R () const {
  92. // if static values don't overlap, the program can never function
  93. #if 1
  94. constexpr const interval<R> r_interval;
  95. static_assert(
  96. ! r_interval.excludes(N),
  97. "safe type cannot be constructed with this type"
  98. );
  99. #endif
  100. return validate_detail<
  101. R,
  102. std::numeric_limits<R>::min(),
  103. std::numeric_limits<R>::max(),
  104. E
  105. >::return_value(*this);
  106. }
  107. // non mutating unary operators
  108. constexpr safe_literal_impl<T, N, P, E> operator+() const { // unary plus
  109. return safe_literal_impl<T, N, P, E>();
  110. }
  111. // after much consideration, I've permitted the resulting value of a unary
  112. // - to change the type in accordance with the promotion policy.
  113. // The C++ standard does invoke integral promotions so it's changing the type as well.
  114. /* section 5.3.1 &8 of the C++ standard
  115. The operand of the unary - operator shall have arithmetic or unscoped
  116. enumeration type and the result is the negation of its operand. Integral
  117. promotion is performed on integral or enumeration operands. The negative
  118. of an unsigned quantity is computed by subtracting its value from 2n,
  119. where n is the number of bits in the promoted operand. The type of the
  120. result is the type of the promoted operand.
  121. */
  122. template<
  123. typename Tx, Tx Nx, typename = std::enable_if_t<! checked::minus(Nx).exception()>
  124. >
  125. constexpr auto minus_helper() const {
  126. return safe_literal_impl<Tx, -N, P, E>();
  127. }
  128. constexpr auto operator-() const { // unary minus
  129. return minus_helper<T, N>();
  130. }
  131. /* section 5.3.1 &10 of the C++ standard
  132. The operand of ~ shall have integral or unscoped enumeration type;
  133. the result is the ones’ complement of its operand. Integral promotions
  134. are performed. The type of the result is the type of the promoted operand.
  135. constexpr safe_literal_impl<T, checked::bitwise_not(N), P, E> operator~() const { // invert bits
  136. return safe_literal_impl<T, checked::bitwise_not(N), P, E>();
  137. }
  138. */
  139. template<
  140. typename Tx, Tx Nx, typename = std::enable_if_t<! checked::bitwise_not(Nx).exception()>
  141. >
  142. constexpr auto not_helper() const {
  143. return safe_literal_impl<Tx, ~N, P, E>();
  144. }
  145. constexpr auto operator~() const { // unary minus
  146. return not_helper<T, N>();
  147. }
  148. };
  149. template<
  150. std::intmax_t N,
  151. class P = void,
  152. class E = void
  153. >
  154. using safe_signed_literal = safe_literal_impl<
  155. typename utility::signed_stored_type<N, N>,
  156. N,
  157. P,
  158. E
  159. >;
  160. template<
  161. std::uintmax_t N,
  162. class P = void,
  163. class E = void
  164. >
  165. using safe_unsigned_literal = safe_literal_impl<
  166. typename utility::unsigned_stored_type<N, N>,
  167. N,
  168. P,
  169. E
  170. >;
  171. template<
  172. class T,
  173. T N,
  174. class P = void,
  175. class E = void,
  176. typename std::enable_if<
  177. std::is_signed<T>::value,
  178. int
  179. >::type = 0
  180. >
  181. constexpr auto make_safe_literal_impl() {
  182. return boost::safe_numerics::safe_signed_literal<N, P, E>();
  183. }
  184. template<
  185. class T,
  186. T N,
  187. class P = void,
  188. class E = void,
  189. typename std::enable_if<
  190. ! std::is_signed<T>::value,
  191. int
  192. >::type = 0
  193. >
  194. constexpr auto inline make_safe_literal_impl() {
  195. return boost::safe_numerics::safe_unsigned_literal<N, P, E>();
  196. }
  197. } // safe_numerics
  198. } // boost
  199. #define make_safe_literal(n, P, E) \
  200. boost::safe_numerics::make_safe_literal_impl<decltype(n), n, P, E>()
  201. /////////////////////////////////////////////////////////////////
  202. // numeric limits for safe_literal etc.
  203. #include <limits>
  204. namespace std {
  205. template<
  206. typename T,
  207. T N,
  208. class P,
  209. class E
  210. >
  211. class numeric_limits<boost::safe_numerics::safe_literal_impl<T, N, P, E> >
  212. : public std::numeric_limits<T>
  213. {
  214. using SL = boost::safe_numerics::safe_literal_impl<T, N, P, E>;
  215. public:
  216. constexpr static SL lowest() noexcept {
  217. return SL();
  218. }
  219. constexpr static SL min() noexcept {
  220. return SL();
  221. }
  222. constexpr static SL max() noexcept {
  223. return SL();
  224. }
  225. };
  226. } // std
  227. #endif // BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP