]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/boost/safe_numerics/safe_base_operations.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / safe_numerics / safe_base_operations.hpp
index d97ac921db97bbcca491dc2e32dfbdb5fbe67437..1c5d9ec50b0bc8a296fc95837a8045e9b70d3f5f 100644 (file)
@@ -10,7 +10,8 @@
 #include <limits>
 #include <type_traits> // is_base_of, is_same, is_floating_point, conditional
 #include <algorithm>   // max
-#include <cassert>
+#include <istream>
+#include <ostream>
 
 #include <boost/config.hpp>
 
@@ -63,7 +64,6 @@ struct validate_detail {
 
     template<typename T>
     constexpr static R return_value(const T & t){
-
         constexpr const interval<r_type> t_interval{
             checked::cast<R>(base_value(std::numeric_limits<T>::min())),
             checked::cast<R>(base_value(std::numeric_limits<T>::max()))
@@ -74,7 +74,6 @@ struct validate_detail {
             true != static_cast<bool>(r_interval.excludes(t_interval)),
             "can't cast from ranges that don't overlap"
         );
-
         return std::conditional<
             static_cast<bool>(r_interval.includes(t_interval)),
             exception_not_possible,
@@ -90,70 +89,45 @@ validated_cast(const T & t) const {
     return validate_detail<Stored,Min,Max,E>::return_value(t);
 }
 
-template<class Stored, Stored Min, Stored Max, class P, class E>
-template<typename T, T N, class P1, class E1>
-constexpr Stored safe_base<Stored, Min, Max, P, E>::
-validated_cast(const safe_literal_impl<T, N, P1, E1> &) const {
-    constexpr const interval<Stored> this_interval{};
-    // if static values don't overlap, the program can never function
-    static_assert(
-        this_interval.includes(N),
-        "safe type cannot be constructed from this value"
-    );
-    return static_cast<Stored>(N);
-}
-
 /////////////////////////////////////////////////////////////////
 // constructors
 
-template<class Stored, Stored Min, Stored Max, class P, class E>
-    constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
-    const Stored & rhs,
-    skip_validation
-) :
-    m_t(rhs)
-{}
-
+// default constructor
 template<class Stored, Stored Min, Stored Max, class P, class E>
 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(){
     dispatch<E, safe_numerics_error::uninitialized_value>(
         "safe values must be initialized"
     );
 }
-
-// construct an instance of a safe type
-// from an instance of a convertible underlying type.
+// construct an instance of a safe type from an instance of a convertible underlying type.
 template<class Stored, Stored Min, Stored Max, class P, class E>
-template<class T>
 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
-    const T & t,
-    typename std::enable_if<
-        is_safe<T>::value,
-        bool
-    >::type
+    const Stored & rhs,
+    skip_validation
 ) :
-    m_t(validated_cast(t))
+    m_t(rhs)
 {}
 
+// construct an instance from an instance of a convertible underlying type.
 template<class Stored, Stored Min, Stored Max, class P, class E>
-template<class T>
-constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
-    const T & t,
-    typename std::enable_if<
-        std::is_integral<T>::value,
-        bool
-    >::type
-) :
+    template<
+        class T,
+        typename std::enable_if<
+            std::is_convertible<T, Stored>::value,
+            bool
+        >::type
+    >
+constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(const T &t) :
     m_t(validated_cast(t))
 {}
 
+// construct an instance of a safe type from a literal value
 template<class Stored, Stored Min, Stored Max, class P, class E>
-template<class T, T value>
+template<typename T, T N, class Px, class Ex>
 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
-
-    const std::integral_constant<T, value> &
+    const safe_literal_impl<T, N, Px, Ex> & t
 ) :
-    m_t(validated_cast(value))
+    m_t(validated_cast(t))
 {}
 
 /////////////////////////////////////////////////////////////////
@@ -171,28 +145,18 @@ template<
 constexpr safe_base<Stored, Min, Max, P, E>::
 operator R () const {
     // if static values don't overlap, the program can never function
-    #if 1
     constexpr const interval<R> r_interval;
     constexpr const interval<Stored> this_interval(Min, Max);
     static_assert(
         ! r_interval.excludes(this_interval),
         "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);
-}
-
-// cast to the underlying builtin type from a safe type
-template<class Stored, Stored Min, Stored Max, class P, class E>
-constexpr safe_base<Stored, Min, Max, P, E>::
-operator Stored () const {
-    return m_t;
+    >::return_value(m_t);
 }
 
 /////////////////////////////////////////////////////////////////
@@ -487,7 +451,7 @@ private:
 
         return t_interval - u_interval;
     }
-    static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
+    constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
 
     constexpr static const interval<result_base_type> return_interval{
         r_type_interval.l.exception()
@@ -609,7 +573,7 @@ private:
         return t_interval * u_interval;
     }
 
-    static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
+    constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
 
     constexpr static const interval<result_base_type> return_interval{
         r_type_interval.l.exception()
@@ -697,7 +661,7 @@ private:
     // if exception possible
     using exception_policy = typename common_exception_policy<T, U>::type;
 
-    constexpr static int bits = std::min(
+    constexpr static const int bits = std::min(
         std::numeric_limits<std::uintmax_t>::digits,
         std::max(std::initializer_list<int>{
             std::numeric_limits<result_base_type>::digits,
@@ -768,7 +732,7 @@ private:
         );
     }
 
-    static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
+    constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
 
     constexpr static const interval<result_base_type> return_interval{
         r_type_interval.l.exception()
@@ -852,7 +816,7 @@ private:
     // if exception possible
     using exception_policy = typename common_exception_policy<T, U>::type;
 
-    constexpr static int bits = std::min(
+    constexpr static const int bits = std::min(
         std::numeric_limits<std::uintmax_t>::digits,
         std::max(std::initializer_list<int>{
             std::numeric_limits<result_base_type>::digits,
@@ -925,7 +889,7 @@ private:
         );
     }
 
-    static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
+    constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
 
     constexpr static const interval<result_base_type> return_interval{
         r_type_interval.l.exception()
@@ -1180,7 +1144,11 @@ constexpr operator!=(const T & lhs, const U & rhs) {
     return ! (lhs == rhs);
 }
 
-/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+// The following operators only make sense when applied to integet types
+
+/////////////////////////////////////////////////////////////////////////
 // shift operators
 
 // left shift
@@ -1237,7 +1205,7 @@ private:
         return (t_interval << u_interval);
     }
 
-    static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
+    constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
 
     constexpr static const interval<result_base_type> return_interval{
         r_type_interval.l.exception()
@@ -1258,8 +1226,8 @@ private:
         return false;
     }
 
-    constexpr static auto rl = return_interval.l;
-    constexpr static auto ru = return_interval.u;
+    constexpr static const auto rl = return_interval.l;
+    constexpr static const auto ru = return_interval.u;
 
 public:
     using type =
@@ -1295,10 +1263,12 @@ constexpr operator<<(const T & t, const U & u){
     // INT13-CPP
     // C++ standards document N4618 & 5.8.2
     static_assert(
-        std::numeric_limits<T>::is_integer, "shifted value must be an integer"
+        boost::safe_numerics::Integer<T>::value,
+        "shifted value must be an integer"
     );
     static_assert(
-        std::numeric_limits<U>::is_integer, "shift amount must be an integer"
+        boost::safe_numerics::Integer<U>::value,
+        "bit shift count must be an integer"
     );
     return left_shift_result<T, U>::return_value(t, u);
 }
@@ -1370,7 +1340,7 @@ struct right_shift_result {
         return (t_interval() >> u_interval());
     }
 
-    static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
+    constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
 
     constexpr static const interval<result_base_type> return_interval{
         r_type_interval.l.exception()
@@ -1431,10 +1401,12 @@ typename boost::lazy_enable_if_c<
 constexpr operator>>(const T & t, const U & u){
     // INT13-CPP
     static_assert(
-        std::numeric_limits<T>::is_integer, "shifted value must be an integer"
+        boost::safe_numerics::Integer<T>::value,
+        "shifted value must be an integer"
     );
     static_assert(
-        std::numeric_limits<U>::is_integer, "shift amount must be an integer"
+        boost::safe_numerics::Integer<U>::value,
+        "bit shift count must be an integer"
     );
     return right_shift_result<T, U>::return_value(t, u);
 }
@@ -1466,20 +1438,6 @@ private:
 
     using r_type = typename std::make_unsigned<result_base_type>::type;
     using r_type_interval_t = interval<r_type>;
-
-    #if 0
-    // breaks compilation for earlier versions of clant
-    constexpr static const r_type_interval_t r_interval{
-        r_type(0),
-        utility::round_out(
-            std::max(
-                static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
-                static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
-            )
-        )
-    };
-    #endif
-
     using exception_policy = typename common_exception_policy<T, U>::type;
 
 public:
@@ -1514,6 +1472,14 @@ typename boost::lazy_enable_if_c<
     bitwise_or_result<T, U>
 >::type
 constexpr operator|(const T & t, const U & u){
+    static_assert(
+        boost::safe_numerics::Integer<T>::value,
+        "bitwise or arguments must be an integers"
+    );
+    static_assert(
+        boost::safe_numerics::Integer<U>::value,
+        "bitwise or arguments must be an integers"
+    );
     return bitwise_or_result<T, U>::return_value(t, u);
 }
 
@@ -1541,19 +1507,6 @@ private:
 
     using r_type = typename std::make_unsigned<result_base_type>::type;
     using r_type_interval_t = interval<r_type>;
-
-    #if 0
-    // breaks compilation for earlier versions of clant
-    constexpr static const r_type_interval_t r_interval{
-        r_type(0),
-        utility::round_out(
-            std::min(
-                static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
-                static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
-            )
-        )
-    };
-    #endif
     using exception_policy = typename common_exception_policy<T, U>::type;
 
 public:
@@ -1588,6 +1541,14 @@ typename boost::lazy_enable_if_c<
     bitwise_and_result<T, U>
 >::type
 constexpr operator&(const T & t, const U & u){
+    static_assert(
+        boost::safe_numerics::Integer<T>::value,
+        "bitwise and arguments must be an integers"
+    );
+    static_assert(
+        boost::safe_numerics::Integer<U>::value,
+        "bitwise and arguments must be an integers"
+    );
     return bitwise_and_result<T, U>::return_value(t, u);
 }
 
@@ -1614,20 +1575,6 @@ struct bitwise_xor_result {
 
     using r_type = typename std::make_unsigned<result_base_type>::type;
     using r_type_interval_t = interval<r_type>;
-
-    #if 0
-    // breaks compilation for earlier versions of clant
-    constexpr static const r_type_interval_t r_interval{
-        r_type(0),
-        utility::round_out(
-            std::max(
-                static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
-                static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
-            )
-        )
-    };
-    #endif
-
     using exception_policy = typename common_exception_policy<T, U>::type;
 
 public:
@@ -1662,6 +1609,14 @@ typename boost::lazy_enable_if_c<
     bitwise_xor_result<T, U>
 >::type
 constexpr operator^(const T & t, const U & u){
+    static_assert(
+        boost::safe_numerics::Integer<T>::value,
+        "bitwise xor arguments must be an integers"
+    );
+    static_assert(
+        boost::safe_numerics::Integer<U>::value,
+        "bitwise xor arguments must be an integers"
+    );
     return bitwise_xor_result<T, U>::return_value(t, u);
 }
 
@@ -1726,16 +1681,30 @@ void safe_base<T, Min, Max, P, E>::input(
         m_t = validated_cast(x);
     }
     else{
+        if(std::is_unsigned<T>::value){
+            // reading a negative number into an unsigned variable cannot result in
+            // a correct result.  But, C++ reads the absolute value, multiplies
+            // it by -1 and stores the resulting value.  This is crazy - but there
+            // it is!  Oh, and it doesn't set the failbit. We fix this behavior here
+            is >> std::ws;
+            int x = is.peek();
+            // if the input string starts with a '-', we know its an error
+            if(x == '-'){
+                // set fail bit
+                is.setstate(std::ios_base::failbit);
+            }
+        }
         is >> m_t;
-        validated_cast(m_t);
-    }
-    if(is.fail()){
-        boost::safe_numerics::dispatch<
-            E,
-            boost::safe_numerics::safe_numerics_error::domain_error
-        >(
-            "error in file input"
-        );
+        if(is.fail()){
+            boost::safe_numerics::dispatch<
+                E,
+                boost::safe_numerics::safe_numerics_error::domain_error
+            >(
+                "error in file input"
+            );
+        }
+        else
+            validated_cast(m_t);
     }
 }