• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
base_value(const safe_literal_impl<T,N,P,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>
operator <<(std::basic_ostream<CharT,Traits> & os,const safe_literal_impl<T,N,P,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     >
operator <<(std::basic_ostream<CharT,Traits> & os,const safe_literal_impl &)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
safe_literal_impl()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     >
operator R() const106     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
operator +() const125     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     >
minus_helper() const143     constexpr auto minus_helper() const {
144         return safe_literal_impl<Tx, -N, P, E>();
145     }
146 
operator -() const147     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     >
not_helper() const162     constexpr auto not_helper() const {
163         return safe_literal_impl<Tx, ~N, P, E>();
164     }
165 
operator ~() const166     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 >
make_safe_literal_impl()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 >
make_safe_literal_impl()219 constexpr auto 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:
lowest()247     constexpr static SL lowest() noexcept {
248         return SL();
249     }
min()250     constexpr static SL min() noexcept {
251         return SL();
252     }
max()253     constexpr static SL max() noexcept {
254         return SL();
255     }
256 };
257 
258 } // std
259 
260 #endif // BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
261