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