123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- #ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
- #define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
- // Copyright (c) 2012 Robert Ramey
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #include <cstdint> // for intmax_t/uintmax_t
- #include <iosfwd>
- #include <type_traits> // conditional, enable_if
- #include <boost/mp11/utility.hpp>
- #include "utility.hpp"
- #include "safe_integer.hpp"
- #include "checked_integer.hpp"
- namespace boost {
- namespace safe_numerics {
- template<typename T, T N, class P, class E>
- class safe_literal_impl;
- template<typename T, T N, class P, class E>
- struct is_safe<safe_literal_impl<T, N, P, E> > : public std::true_type
- {};
- template<typename T, T N, class P, class E>
- struct get_promotion_policy<safe_literal_impl<T, N, P, E> > {
- using type = P;
- };
- template<typename T, T N, class P, class E>
- struct get_exception_policy<safe_literal_impl<T, N, P, E> > {
- using type = E;
- };
- template<typename T, T N, class P, class E>
- struct base_type<safe_literal_impl<T, N, P, E> > {
- using type = T;
- };
- template<typename T, T N, class P, class E>
- constexpr T base_value(
- const safe_literal_impl<T, N, P, E> &
- ) {
- return N;
- }
- template<typename CharT, typename Traits, typename T, T N, class P, class E>
- inline std::basic_ostream<CharT, Traits> & operator<<(
- std::basic_ostream<CharT, Traits> & os,
- const safe_literal_impl<T, N, P, E> &
- ){
- return os << (
- (std::is_same<T, signed char>::value
- || std::is_same<T, unsigned char>::value
- ) ?
- static_cast<int>(N)
- :
- N
- );
- }
- template<typename T, T N, class P, class E>
- class safe_literal_impl {
- template<
- class CharT,
- class Traits
- >
- friend std::basic_ostream<CharT, Traits> & operator<<(
- std::basic_ostream<CharT, Traits> & os,
- const safe_literal_impl &
- ){
- return os << (
- (::std::is_same<T, signed char>::value
- || ::std::is_same<T, unsigned char>::value
- || ::std::is_same<T, wchar_t>::value
- ) ?
- static_cast<int>(N)
- :
- N
- );
- };
- public:
- ////////////////////////////////////////////////////////////
- // constructors
- // default constructor
- constexpr safe_literal_impl(){}
- /////////////////////////////////////////////////////////////////
- // casting operators for intrinsic integers
- // convert to any type which is not safe. safe types need to be
- // excluded to prevent ambiguous function selection which
- // would otherwise occur
- template<
- class R,
- typename std::enable_if<
- ! boost::safe_numerics::is_safe<R>::value,
- int
- >::type = 0
- >
- constexpr operator R () const {
- // if static values don't overlap, the program can never function
- #if 1
- constexpr const interval<R> r_interval;
- static_assert(
- ! r_interval.excludes(N),
- "safe type cannot be constructed with this type"
- );
- #endif
- return validate_detail<
- R,
- std::numeric_limits<R>::min(),
- std::numeric_limits<R>::max(),
- E
- >::return_value(*this);
- }
- // non mutating unary operators
- constexpr safe_literal_impl<T, N, P, E> operator+() const { // unary plus
- return safe_literal_impl<T, N, P, E>();
- }
- // after much consideration, I've permitted the resulting value of a unary
- // - to change the type in accordance with the promotion policy.
- // The C++ standard does invoke integral promotions so it's changing the type as well.
- /* section 5.3.1 &8 of the C++ standard
- The operand of the unary - operator shall have arithmetic or unscoped
- enumeration type and the result is the negation of its operand. Integral
- promotion is performed on integral or enumeration operands. The negative
- of an unsigned quantity is computed by subtracting its value from 2n,
- where n is the number of bits in the promoted operand. The type of the
- result is the type of the promoted operand.
- */
- template<
- typename Tx, Tx Nx, typename = std::enable_if_t<! checked::minus(Nx).exception()>
- >
- constexpr auto minus_helper() const {
- return safe_literal_impl<Tx, -N, P, E>();
- }
- constexpr auto operator-() const { // unary minus
- return minus_helper<T, N>();
- }
- /* section 5.3.1 &10 of the C++ standard
- The operand of ~ shall have integral or unscoped enumeration type;
- the result is the ones’ complement of its operand. Integral promotions
- are performed. The type of the result is the type of the promoted operand.
- constexpr safe_literal_impl<T, checked::bitwise_not(N), P, E> operator~() const { // invert bits
- return safe_literal_impl<T, checked::bitwise_not(N), P, E>();
- }
- */
- template<
- typename Tx, Tx Nx, typename = std::enable_if_t<! checked::bitwise_not(Nx).exception()>
- >
- constexpr auto not_helper() const {
- return safe_literal_impl<Tx, ~N, P, E>();
- }
- constexpr auto operator~() const { // unary minus
- return not_helper<T, N>();
- }
- };
- template<
- std::intmax_t N,
- class P = void,
- class E = void
- >
- using safe_signed_literal = safe_literal_impl<
- typename utility::signed_stored_type<N, N>,
- N,
- P,
- E
- >;
- template<
- std::uintmax_t N,
- class P = void,
- class E = void
- >
- using safe_unsigned_literal = safe_literal_impl<
- typename utility::unsigned_stored_type<N, N>,
- N,
- P,
- E
- >;
- template<
- class T,
- T N,
- class P = void,
- class E = void,
- typename std::enable_if<
- std::is_signed<T>::value,
- int
- >::type = 0
- >
- constexpr auto make_safe_literal_impl() {
- return boost::safe_numerics::safe_signed_literal<N, P, E>();
- }
- template<
- class T,
- T N,
- class P = void,
- class E = void,
- typename std::enable_if<
- ! std::is_signed<T>::value,
- int
- >::type = 0
- >
- constexpr auto inline make_safe_literal_impl() {
- return boost::safe_numerics::safe_unsigned_literal<N, P, E>();
- }
- } // safe_numerics
- } // boost
- #define make_safe_literal(n, P, E) \
- boost::safe_numerics::make_safe_literal_impl<decltype(n), n, P, E>()
- /////////////////////////////////////////////////////////////////
- // numeric limits for safe_literal etc.
- #include <limits>
- namespace std {
- template<
- typename T,
- T N,
- class P,
- class E
- >
- class numeric_limits<boost::safe_numerics::safe_literal_impl<T, N, P, E> >
- : public std::numeric_limits<T>
- {
- using SL = boost::safe_numerics::safe_literal_impl<T, N, P, E>;
- public:
- constexpr static SL lowest() noexcept {
- return SL();
- }
- constexpr static SL min() noexcept {
- return SL();
- }
- constexpr static SL max() noexcept {
- return SL();
- }
- };
- } // std
- #endif // BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP
|