File indexing completed on 2025-01-30 09:59:43
0001 #ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
0002 #define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
0003
0004
0005
0006
0007
0008
0009
0010 #include <cstdint> // for intmax_t/uintmax_t
0011 #include <iosfwd>
0012 #include <type_traits> // conditional, enable_if
0013 #include <boost/mp11/utility.hpp>
0014
0015 #include "utility.hpp"
0016 #include "safe_integer.hpp"
0017 #include "checked_integer.hpp"
0018
0019 namespace boost {
0020 namespace safe_numerics {
0021
0022 template<typename T, T N, class P, class E>
0023 class safe_literal_impl;
0024
0025 template<typename T, T N, class P, class E>
0026 struct is_safe<safe_literal_impl<T, N, P, E> > : public std::true_type
0027 {};
0028
0029 template<typename T, T N, class P, class E>
0030 struct get_promotion_policy<safe_literal_impl<T, N, P, E> > {
0031 using type = P;
0032 };
0033
0034 template<typename T, T N, class P, class E>
0035 struct get_exception_policy<safe_literal_impl<T, N, P, E> > {
0036 using type = E;
0037 };
0038 template<typename T, T N, class P, class E>
0039 struct base_type<safe_literal_impl<T, N, P, E> > {
0040 using type = T;
0041 };
0042
0043 template<typename T, T N, class P, class E>
0044 constexpr T base_value(
0045 const safe_literal_impl<T, N, P, E> &
0046 ) {
0047 return N;
0048 }
0049
0050 template<typename CharT, typename Traits, typename T, T N, class P, class E>
0051 inline std::basic_ostream<CharT, Traits> & operator<<(
0052 std::basic_ostream<CharT, Traits> & os,
0053 const safe_literal_impl<T, N, P, E> &
0054 ){
0055 return os << (
0056 (std::is_same<T, signed char>::value
0057 || std::is_same<T, unsigned char>::value
0058 ) ?
0059 static_cast<int>(N)
0060 :
0061 N
0062 );
0063 }
0064
0065 template<typename T, T N, class P, class E>
0066 class safe_literal_impl {
0067
0068 template<
0069 class CharT,
0070 class Traits
0071 >
0072 friend std::basic_ostream<CharT, Traits> & operator<<(
0073 std::basic_ostream<CharT, Traits> & os,
0074 const safe_literal_impl &
0075 ){
0076 return os << (
0077 (::std::is_same<T, signed char>::value
0078 || ::std::is_same<T, unsigned char>::value
0079 || ::std::is_same<T, wchar_t>::value
0080 ) ?
0081 static_cast<int>(N)
0082 :
0083 N
0084 );
0085 };
0086
0087 public:
0088
0089
0090
0091
0092 constexpr safe_literal_impl(){}
0093
0094
0095
0096
0097
0098
0099 template<
0100 class R,
0101 typename std::enable_if<
0102 ! boost::safe_numerics::is_safe<R>::value,
0103 int
0104 >::type = 0
0105 >
0106 constexpr operator R () const {
0107
0108 #if 1
0109 constexpr const interval<R> r_interval;
0110 static_assert(
0111 ! r_interval.excludes(N),
0112 "safe type cannot be constructed with this type"
0113 );
0114 #endif
0115
0116 return validate_detail<
0117 R,
0118 std::numeric_limits<R>::min(),
0119 std::numeric_limits<R>::max(),
0120 E
0121 >::return_value(*this);
0122 }
0123
0124
0125 constexpr safe_literal_impl<T, N, P, E> operator+() const {
0126 return safe_literal_impl<T, N, P, E>();
0127 }
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 template<
0141 typename Tx, Tx Nx, typename = std::enable_if_t<! checked::minus(Nx).exception()>
0142 >
0143 constexpr auto minus_helper() const {
0144 return safe_literal_impl<Tx, -N, P, E>();
0145 }
0146
0147 constexpr auto operator-() const {
0148 return minus_helper<T, N>();
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 template<
0160 typename Tx, Tx Nx, typename = std::enable_if_t<! checked::bitwise_not(Nx).exception()>
0161 >
0162 constexpr auto not_helper() const {
0163 return safe_literal_impl<Tx, ~N, P, E>();
0164 }
0165
0166 constexpr auto operator~() const {
0167 return not_helper<T, N>();
0168 }
0169 };
0170
0171 template<
0172 std::intmax_t N,
0173 class P = void,
0174 class E = void
0175 >
0176 using safe_signed_literal = safe_literal_impl<
0177 typename utility::signed_stored_type<N, N>,
0178 N,
0179 P,
0180 E
0181 >;
0182
0183 template<
0184 std::uintmax_t N,
0185 class P = void,
0186 class E = void
0187 >
0188 using safe_unsigned_literal = safe_literal_impl<
0189 typename utility::unsigned_stored_type<N, N>,
0190 N,
0191 P,
0192 E
0193 >;
0194
0195 template<
0196 class T,
0197 T N,
0198 class P = void,
0199 class E = void,
0200 typename std::enable_if<
0201 std::is_signed<T>::value,
0202 int
0203 >::type = 0
0204 >
0205 constexpr auto make_safe_literal_impl() {
0206 return boost::safe_numerics::safe_signed_literal<N, P, E>();
0207 }
0208
0209 template<
0210 class T,
0211 T N,
0212 class P = void,
0213 class E = void,
0214 typename std::enable_if<
0215 ! std::is_signed<T>::value,
0216 int
0217 >::type = 0
0218 >
0219 constexpr auto inline make_safe_literal_impl() {
0220 return boost::safe_numerics::safe_unsigned_literal<N, P, E>();
0221 }
0222
0223 }
0224 }
0225
0226 #define make_safe_literal(n, P, E) \
0227 boost::safe_numerics::make_safe_literal_impl<decltype(n), n, P, E>()
0228
0229
0230
0231
0232 #include <limits>
0233
0234 namespace std {
0235
0236 template<
0237 typename T,
0238 T N,
0239 class P,
0240 class E
0241 >
0242 class numeric_limits<boost::safe_numerics::safe_literal_impl<T, N, P, E> >
0243 : public std::numeric_limits<T>
0244 {
0245 using SL = boost::safe_numerics::safe_literal_impl<T, N, P, E>;
0246 public:
0247 constexpr static SL lowest() noexcept {
0248 return SL();
0249 }
0250 constexpr static SL min() noexcept {
0251 return SL();
0252 }
0253 constexpr static SL max() noexcept {
0254 return SL();
0255 }
0256 };
0257
0258 }
0259
0260 #endif