Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:36

0001 #ifndef BOOST_NUMERIC_SAFE_BASE_HPP
0002 #define BOOST_NUMERIC_SAFE_BASE_HPP
0003 
0004 //  Copyright (c) 2012 Robert Ramey
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See
0007 // accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #include <limits>
0011 #include <type_traits> // is_integral, enable_if, conditional is_convertible
0012 #include <boost/config.hpp> // BOOST_CLANG
0013 #include "concept/exception_policy.hpp"
0014 #include "concept/promotion_policy.hpp"
0015 
0016 #include "safe_common.hpp"
0017 #include "exception_policies.hpp"
0018 
0019 #include "boost/concept/assert.hpp"
0020 
0021 namespace boost {
0022 namespace safe_numerics {
0023 
0024 /////////////////////////////////////////////////////////////////
0025 // forward declarations to support friend function declarations
0026 // in safe_base
0027 
0028 template<
0029     class Stored,
0030     Stored Min,
0031     Stored Max,
0032     class P, // promotion polic
0033     class E  // exception policy
0034 >
0035 class safe_base;
0036 
0037 template<
0038     class T,
0039     T Min,
0040     T Max,
0041     class P,
0042     class E
0043 >
0044 struct is_safe<safe_base<T, Min, Max, P, E> > : public std::true_type
0045 {};
0046 
0047 template<
0048     class T,
0049     T Min,
0050     T Max,
0051     class P,
0052     class E
0053 >
0054 struct get_promotion_policy<safe_base<T, Min, Max, P, E> > {
0055     using type = P;
0056 };
0057 
0058 template<
0059     class T,
0060     T Min,
0061     T Max,
0062     class P,
0063     class E
0064 >
0065 struct get_exception_policy<safe_base<T, Min, Max, P, E> > {
0066     using type = E;
0067 };
0068 
0069 template<
0070     class T,
0071     T Min,
0072     T Max,
0073     class P,
0074     class E
0075 >
0076 struct base_type<safe_base<T, Min, Max, P, E> > {
0077     using type = T;
0078 };
0079 
0080 template<
0081     class T,
0082     T Min,
0083     T Max,
0084     class P,
0085     class E
0086 >
0087 constexpr T base_value(
0088     const safe_base<T, Min, Max, P, E>  & st
0089 ) {
0090     return static_cast<T>(st);
0091 }
0092 
0093 template<
0094     typename T,
0095     T N,
0096     class P, // promotion policy
0097     class E  // exception policy
0098 >
0099 class safe_literal_impl;
0100 
0101 // works for both GCC and clang
0102 #if BOOST_CLANG==1
0103 #pragma GCC diagnostic push
0104 #pragma GCC diagnostic ignored "-Wmismatched-tags"
0105 #endif
0106 
0107 /////////////////////////////////////////////////////////////////
0108 // Main implementation
0109 
0110 // note in the current version of the library, it is a requirement than type
0111 // type "Stored" be a scalar type.  Problem is when violates this rule, the error message (on clang)
0112 // is "A non-type template parameter cannot have type ... " where ... is some non-scalar type
0113 // The example which triggered this investigation is safe<safe<int>> .  It was difficult to make
0114 // the trip from the error message to the source of the problem, hence we're including this
0115 // comment here.
0116 template<
0117     class Stored,
0118     Stored Min,
0119     Stored Max,
0120     class P, // promotion polic
0121     class E  // exception policy
0122 >
0123 class safe_base {
0124 private:
0125     BOOST_CONCEPT_ASSERT((PromotionPolicy<P>));
0126     BOOST_CONCEPT_ASSERT((ExceptionPolicy<E>));
0127     Stored m_t;
0128 
0129     template<class T>
0130     constexpr Stored validated_cast(const T & t) const;
0131 
0132     // stream support
0133 
0134     template<class CharT, class Traits>
0135     void output(std::basic_ostream<CharT, Traits> & os) const;
0136 
0137     // note usage of friend declaration to mark function as
0138     // a global function rather than a member function.  If
0139     // this is not done, the compiler will confuse this with
0140     // a member operator overload on the << operator.  Weird
0141     // I know.  But it's documented here
0142     // http://en.cppreference.com/w/cpp/language/friend
0143     // under the heading "Template friend operators"
0144     template<class CharT, class Traits>
0145     friend std::basic_ostream<CharT, Traits> &
0146     operator<<(
0147         std::basic_ostream<CharT, Traits> & os,
0148         const safe_base & t
0149     ){
0150         t.output(os);
0151         return os;
0152     }
0153 
0154     template<class CharT, class Traits>
0155     void input(std::basic_istream<CharT, Traits> & is);
0156 
0157     // see above
0158     template<class CharT, class Traits>
0159     friend inline std::basic_istream<CharT, Traits> &
0160     operator>>(
0161         std::basic_istream<CharT, Traits> & is,
0162         safe_base & t
0163     ){
0164         t.input(is);
0165         return is;
0166     }
0167     
0168 public:
0169     ////////////////////////////////////////////////////////////
0170     // constructors
0171 
0172     constexpr safe_base();
0173 
0174     struct skip_validation{};
0175 
0176     constexpr explicit safe_base(const Stored & rhs, skip_validation);
0177 
0178     // construct an instance of a safe type from an instance of a convertible underlying type.
0179     template<
0180         class T,
0181         typename std::enable_if<
0182             std::is_convertible<T, Stored>::value,
0183             bool
0184         >::type = 0
0185     >
0186     constexpr /*explicit*/ safe_base(const T & t);
0187 
0188     // construct an instance of a safe type from a literal value
0189     template<typename T, T N, class Px, class Ex>
0190     constexpr /*explicit*/ safe_base(const safe_literal_impl<T, N, Px, Ex> & t);
0191 
0192     // note: Rule of Five. Supply all or none of the following
0193     // a) user-defined destructor
0194     ~safe_base() = default;
0195     // b) copy-constructor
0196     constexpr safe_base(const safe_base &) = default;
0197     // c) copy-assignment
0198     constexpr safe_base & operator=(const safe_base &) = default;
0199     // d) move constructor
0200     constexpr safe_base(safe_base &&) = default;
0201     // e) move assignment operator
0202     constexpr safe_base & operator=(safe_base &&) = default;
0203 
0204     /////////////////////////////////////////////////////////////////
0205     // casting operators for intrinsic integers
0206     // convert to any type which is not safe.  safe types need to be
0207     // excluded to prevent ambiguous function selection which
0208     // would otherwise occur.  validity of safe types is checked in
0209     // the constructor of safe types
0210     template<
0211         class R,
0212         typename std::enable_if<
0213             ! boost::safe_numerics::is_safe<R>::value,
0214             int
0215         >::type = 0
0216     >
0217     constexpr /*explicit*/ operator R () const;
0218 
0219     /////////////////////////////////////////////////////////////////
0220     // modification binary operators
0221     template<class T>
0222     constexpr safe_base &
0223     operator=(const T & rhs){
0224         m_t = validated_cast(rhs);
0225         return *this;
0226     }
0227 
0228     // mutating unary operators
0229     constexpr safe_base & operator++(){      // pre increment
0230         return *this = *this + 1;
0231     }
0232     constexpr safe_base & operator--(){      // pre decrement
0233         return *this = *this - 1;
0234     }
0235     constexpr safe_base operator++(int){   // post increment
0236         safe_base old_t = *this;
0237         ++(*this);
0238         return old_t;
0239     }
0240     constexpr safe_base operator--(int){ // post decrement
0241         safe_base old_t = *this;
0242         --(*this);
0243         return old_t;
0244     }
0245     // non mutating unary operators
0246     constexpr auto operator+() const { // unary plus
0247         return *this;
0248     }
0249     // after much consideration, I've permited the resulting value of a unary
0250     // - to change the type.  The C++ standard does invoke integral promotions
0251     // so it's changing the type as well.
0252 
0253     /*  section 5.3.1 &8 of the C++ standard
0254     The operand of the unary - operator shall have arithmetic or unscoped
0255     enumeration type and the result is the negation of its operand. Integral
0256     promotion is performed on integral or enumeration operands. The negative
0257     of an unsigned quantity is computed by subtracting its value from 2n,
0258     where n is the number of bits in the promoted operand. The type of the
0259     result is the type of the promoted operand.
0260     */
0261     constexpr auto operator-() const { // unary minus
0262         // if this is a unsigned type and the promotion policy is native
0263         // the result will be unsigned. But then the operation will fail
0264         // according to the requirements of arithmetic correctness.
0265         // if this is an unsigned type and the promotion policy is automatic.
0266         // the result will be signed.
0267         return 0 - *this;
0268     }
0269     /*   section 5.3.1 &10 of the C++ standard
0270     The operand of ~ shall have integral or unscoped enumeration type; 
0271     the result is the ones’ complement of its operand. Integral promotions 
0272     are performed. The type of the result is the type of the promoted operand.
0273     */
0274     constexpr auto operator~() const { // complement
0275         return ~Stored(0u) ^ *this;
0276     }
0277 };
0278 
0279 } // safe_numerics
0280 } // boost
0281 
0282 /////////////////////////////////////////////////////////////////
0283 // numeric limits for safe<int> etc.
0284 
0285 #include <limits>
0286 
0287 namespace std {
0288 
0289 template<
0290     class T,
0291     T Min,
0292     T Max,
0293     class P,
0294     class E
0295 >
0296 class numeric_limits<boost::safe_numerics::safe_base<T, Min, Max, P, E> >
0297     : public std::numeric_limits<T>
0298 {
0299     using SB = boost::safe_numerics::safe_base<T, Min, Max, P, E>;
0300 public:
0301     constexpr static SB lowest() noexcept {
0302         return SB(Min, typename SB::skip_validation());
0303     }
0304     constexpr static SB min() noexcept {
0305         return SB(Min, typename SB::skip_validation());
0306     }
0307     constexpr static SB max() noexcept {
0308         return SB(Max, typename SB::skip_validation());
0309     }
0310 };
0311 
0312 } // std
0313 
0314 #if BOOST_CLANG==1
0315 #pragma GCC diagnostic pop
0316 #endif
0317 
0318 #endif // BOOST_NUMERIC_SAFE_BASE_HPP