From f185d014f28b40ddbaafc17c998bc5ed22c5ce68 Mon Sep 17 00:00:00 2001 From: Robert Ramey Date: Fri, 3 Jul 2015 15:30:54 -0700 Subject: [PATCH] added in binary operations |, &, and ^ --- include/checked.hpp | 72 +++++++++++++ include/safe_base.hpp | 39 +------ include/safe_base_operations.hpp | 168 +++++++++++++++++++++++++------ 3 files changed, 211 insertions(+), 68 deletions(-) diff --git a/include/checked.hpp b/include/checked.hpp index 210dbc4..e4e4975 100644 --- a/include/checked.hpp +++ b/include/checked.hpp @@ -838,6 +838,78 @@ SAFE_NUMERIC_CONSTEXPR checked_result right_shift( ; } +/////////////////////////////////// +// bitwise operations + +template +SAFE_NUMERIC_CONSTEXPR checked_result bitwise_or( + const T & t, + const U & u +) { + static_assert( + std::is_integral::value && std::is_signed::value + && std::is_integral::value && std::is_signed::value, + "only intrinsic unsigned integers permitted" + ); + const checked_result ru = cast(u); + const checked_result rt = cast(t); + return + rt != checked_result::exception_type::no_exception ? + rt + : + ru != checked_result::exception_type::no_exception ? + ru + : + static_cast(ru) | static_cast(rt) + ; +} + +template +SAFE_NUMERIC_CONSTEXPR checked_result bitwise_and( + const T & t, + const U & u +) { + static_assert( + std::is_integral::value && std::is_signed::value + && std::is_integral::value && std::is_signed::value, + "only intrinsic unsigned integers permitted" + ); + const checked_result ru = cast(u); + const checked_result rt = cast(t); + return + rt != checked_result::exception_type::no_exception ? + rt + : + ru != checked_result::exception_type::no_exception ? + ru + : + static_cast(ru) & static_cast(rt) + ; +} + +template +SAFE_NUMERIC_CONSTEXPR checked_result bitwise_xor( + const T & t, + const U & u +) { + static_assert( + std::is_integral::value && std::is_signed::value + && std::is_integral::value && std::is_signed::value, + "only intrinsic unsigned integers permitted" + ); + const checked_result ru = cast(u); + const checked_result rt = cast(t); + return + rt != checked_result::exception_type::no_exception ? + rt + : + ru != checked_result::exception_type::no_exception ? + ru + : + static_cast(ru) ^ static_cast(rt) + ; +} + } // checked } // numeric } // boost diff --git a/include/safe_base.hpp b/include/safe_base.hpp index 74874d6..4349cad 100644 --- a/include/safe_base.hpp +++ b/include/safe_base.hpp @@ -163,6 +163,7 @@ class safe_base { template SAFE_NUMERIC_CONSTEXPR bool validate(const T & t) const { + // INT08-C return ! ( boost::numeric::checked::greater_than( base_value(t), @@ -340,44 +341,6 @@ public: ); return *this = ~(m_t); } - -/* - - ///////////////////////////////////////////////////////////////// - // logical operators - - template - Stored inline operator>>(const U & rhs) const { - // verify that U is an integer type - static_assert( - std::numeric_limits::is_integer, - "right hand side is not an integer type" - ); - if(m_t < 0) - boost::numeric::overflow("right shift of negative number undefined"); - typedef decltype(Stored() >> U()) result_type; - if(rhs > boost::numeric::bits::value) - boost::numeric::overflow("conversion of negative value to unsigned"); - - return m_t >> rhs; - } - template - Stored inline operator<<(const U & rhs) const { - // verify that U is an integer type - static_assert( - std::numeric_limits::is_integer, - "right hand side is not an integer type" - ); - if(m_t < 0) - boost::numeric::overflow("right shift of negative number undefined"); - typedef decltype(Stored() >> U()) result_type; - if(rhs > boost::numeric::bits::value) - boost::numeric::overflow("conversion of negative value to unsigned"); - return m_t << rhs; - } - -*/ - }; diff --git a/include/safe_base_operations.hpp b/include/safe_base_operations.hpp index 087a02e..27396a4 100644 --- a/include/safe_base_operations.hpp +++ b/include/safe_base_operations.hpp @@ -642,7 +642,7 @@ SAFE_NUMERIC_CONSTEXPR inline operator>>(const T & t, const U & u){ // note: it's possible to trap some sitations at compile and skip // the error checking. May later - for now check all the time. - SAFE_NUMERIC_CONSTEXPR const checked_result r = { + const checked_result r = { checked::right_shift(base_value(t), base_value(u)) }; r.template dispatch(); @@ -650,42 +650,150 @@ SAFE_NUMERIC_CONSTEXPR inline operator>>(const T & t, const U & u){ } ///////////////////////////////////////////////////////////////// -// logical operators -/* -template -typename boost::enable_if< - boost::is_integral, - typename multiply_result_type::type +// bitwise operators + +// operator | +template +struct or_result { + typedef common_policies P; + typedef typename P::promotion_policy::template or_result< + T, + U, + typename P::promotion_policy, + typename P::exception_policy + >::type type; +}; + +template +typename boost::lazy_enable_if< + boost::mpl::or_< + boost::numeric::is_safe, + boost::numeric::is_safe + >, + or_result >::type -inline operator|(const T & lhs, const safe_base & rhs) { - return rhs | lhs; -} -template -typename boost::enable_if< - boost::is_integral, - typename multiply_result_type::type ->::type -inline operator|(const T & lhs, const safe_base & rhs) { - return rhs | lhs; +SAFE_NUMERIC_CONSTEXPR inline operator|(const T & t, const U & u){ + // argument dependent lookup should guarentee that we only get here + // only if one of the types is a safe type. Verify this here + typedef or_result or_; + typedef typename or_::P::exception_policy exception_policy; + typedef typename or_::type result_type; + static_assert( + boost::numeric::is_safe::value, + "Promotion failed to return safe type" + ); + + static_assert( + std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed) + && std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed), + // INT13-C + "bitwise operations are only applicable to unsigned integers" + ); + + typedef typename base_type::type result_base_type; + + static_assert( + std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed), + // INT13-C + "bitwise operations should return unsigned integers" + ); + + checked_result r = checked::bitwise_or(t, u); + r.template dispatch(); + return r; } -template -typename boost::enable_if< - boost::is_integral, - decltype(T() & Stored()) +// operator & +template +typename boost::lazy_enable_if< + boost::mpl::or_< + boost::numeric::is_safe, + boost::numeric::is_safe + >, + or_result >::type -inline operator&(const T & lhs, const safe_base & rhs) { - return rhs & lhs; +SAFE_NUMERIC_CONSTEXPR inline operator&(const T & t, const U & u){ + // argument dependent lookup should guarentee that we only get here + // only if one of the types is a safe type. Verify this here + typedef or_result and_; + typedef typename and_::P::exception_policy exception_policy; + typedef typename and_::type result_type; + static_assert( + boost::numeric::is_safe::value, + "Promotion failed to return safe type" + ); + + static_assert( + std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed) + && std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed), + // INT13-C + "bitwise operations are only applicable to unsigned integers" + ); + + typedef typename base_type::type result_base_type; + + static_assert( + std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed), + // INT13-C + "bitwise operations should return unsigned integers" + ); + + checked_result r = checked::bitwise_and(t, u); + r.template dispatch(); + return r; } -template -typename boost::enable_if< - boost::is_integral, - decltype(T() ^ Stored()) + +// operator ^ +template +typename boost::lazy_enable_if< + boost::mpl::or_< + boost::numeric::is_safe, + boost::numeric::is_safe + >, + or_result >::type -inline operator^(const T & lhs, const safe_base & rhs) { - return rhs ^ lhs; +SAFE_NUMERIC_CONSTEXPR inline operator^(const T & t, const U & u){ + // argument dependent lookup should guarentee that we only get here + // only if one of the types is a safe type. Verify this here + typedef or_result xor_; + typedef typename xor_::P::exception_policy exception_policy; + typedef typename xor_::type result_type; + static_assert( + boost::numeric::is_safe::value, + "Promotion failed to return safe type" + ); + + static_assert( + std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed) + && std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed), + // INT13-C + "bitwise operations are only applicable to unsigned integers" + ); + + typedef typename base_type::type result_base_type; + + static_assert( + std::numeric_limits::is_integer + && (! std::numeric_limits::is_signed), + // INT13-C + "bitwise operations should return unsigned integers" + ); + + checked_result r = checked::bitwise_xor(t, u); + r.template dispatch(); + return r; } -*/ + +///////////////////////////////////////////////////////////////// +// stream operators template< class T,