1 #ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
2 #define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
4 // Copyright (c) 2012 Robert Ramey
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)
10 #include <cstdint> // for intmax_t/uintmax_t
12 #include <type_traits> // conditional, enable_if
13 #include <boost/mp11/utility.hpp>
15 #include "utility.hpp"
16 #include "safe_integer.hpp"
17 #include "checked_integer.hpp"
20 namespace safe_numerics {
22 template<typename T, T N, class P, class E>
23 class safe_literal_impl;
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
29 template<typename T, T N, class P, class E>
30 struct get_promotion_policy<safe_literal_impl<T, N, P, E> > {
34 template<typename T, T N, class P, class E>
35 struct get_exception_policy<safe_literal_impl<T, N, P, E> > {
38 template<typename T, T N, class P, class E>
39 struct base_type<safe_literal_impl<T, N, P, E> > {
43 template<typename T, T N, class P, class E>
44 constexpr T base_value(
45 const safe_literal_impl<T, N, P, E> &
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> &
56 (std::is_same<T, signed char>::value
57 || std::is_same<T, unsigned char>::value
65 template<typename T, T N, class P, class E>
66 class safe_literal_impl {
72 friend std::basic_ostream<CharT, Traits> & operator<<(
73 std::basic_ostream<CharT, Traits> & os,
74 const safe_literal_impl &
77 (::std::is_same<T, signed char>::value
78 || ::std::is_same<T, unsigned char>::value
79 || ::std::is_same<T, wchar_t>::value
89 ////////////////////////////////////////////////////////////
91 // default constructor
92 constexpr safe_literal_impl(){}
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
101 typename std::enable_if<
102 ! boost::safe_numerics::is_safe<R>::value,
106 constexpr operator R () const {
110 // non mutating unary operators
111 constexpr safe_literal_impl<T, N, P, E> operator+() const { // unary plus
112 return safe_literal_impl<T, N, P, E>();
114 // after much consideration, I've permitted the resulting value of a unary
115 // - to change the type in accordance with the promotion policy.
116 // The C++ standard does invoke integral promotions so it's changing the type as well.
118 /* section 5.3.1 &8 of the C++ standard
119 The operand of the unary - operator shall have arithmetic or unscoped
120 enumeration type and the result is the negation of its operand. Integral
121 promotion is performed on integral or enumeration operands. The negative
122 of an unsigned quantity is computed by subtracting its value from 2n,
123 where n is the number of bits in the promoted operand. The type of the
124 result is the type of the promoted operand.
127 typename Tx, Tx Nx, typename = std::enable_if_t<! checked::minus(Nx).exception()>
129 constexpr auto minus_helper() const {
130 return safe_literal_impl<Tx, -N, P, E>();
133 constexpr auto operator-() const { // unary minus
134 return minus_helper<T, N>();
137 /* section 5.3.1 &10 of the C++ standard
138 The operand of ~ shall have integral or unscoped enumeration type;
139 the result is the ones’ complement of its operand. Integral promotions
140 are performed. The type of the result is the type of the promoted operand.
141 constexpr safe_literal_impl<T, checked::bitwise_not(N), P, E> operator~() const { // invert bits
142 return safe_literal_impl<T, checked::bitwise_not(N), P, E>();
146 typename Tx, Tx Nx, typename = std::enable_if_t<! checked::bitwise_not(Nx).exception()>
148 constexpr auto not_helper() const {
149 return safe_literal_impl<Tx, ~N, P, E>();
152 constexpr auto operator~() const { // unary minus
153 return not_helper<T, N>();
162 using safe_signed_literal = safe_literal_impl<
163 typename utility::signed_stored_type<N, N>,
174 using safe_unsigned_literal = safe_literal_impl<
175 typename utility::unsigned_stored_type<N, N>,
186 typename std::enable_if<
187 std::is_signed<T>::value,
191 constexpr auto make_safe_literal_impl() {
192 return boost::safe_numerics::safe_signed_literal<N, P, E>();
200 typename std::enable_if<
201 ! std::is_signed<T>::value,
205 constexpr auto make_safe_literal_impl() {
206 return boost::safe_numerics::safe_unsigned_literal<N, P, E>();
212 #define make_safe_literal(n, P, E) \
213 boost::safe_numerics::make_safe_literal_impl<decltype(n), n, P, E>()
215 /////////////////////////////////////////////////////////////////
216 // numeric limits for safe_literal etc.
228 class numeric_limits<boost::safe_numerics::safe_literal_impl<T, N, P, E> >
229 : public std::numeric_limits<T>
231 using SL = boost::safe_numerics::safe_literal_impl<T, N, P, E>;
233 constexpr static SL lowest() noexcept {
236 constexpr static SL min() noexcept {
239 constexpr static SL max() noexcept {
246 #endif // BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP