diff --git a/include/boost/endian/conversion.hpp b/include/boost/endian/conversion.hpp index c975514..f125a56 100644 --- a/include/boost/endian/conversion.hpp +++ b/include/boost/endian/conversion.hpp @@ -10,12 +10,14 @@ #include #include +#include +#include +#include +#include #include #include #include #include -#include -#include // for memcpy //------------------------------------- synopsis ---------------------------------------// @@ -139,229 +141,241 @@ namespace endian //----------------------------------- end synopsis -------------------------------------// - namespace detail - { - // generic reverse function template implementation approach using std::reverse - // suggested by Mathias Gaunard. Primary motivation for inclusion is to have an - // independent implementation to test against. +namespace detail +{ - template - inline T std_endian_reverse(T x) BOOST_NOEXCEPT - { - T tmp(x); - std::reverse( - reinterpret_cast(&tmp), - reinterpret_cast(&tmp) + sizeof(T)); - return tmp; - } +template struct is_endian_reversible: boost::integral_constant::value || ( boost::is_integral::value && !boost::is_same::value )> +{ +}; - // conditional unaligned reverse copy, patterned after std::reverse_copy - template - inline void big_reverse_copy(T from, char* to) BOOST_NOEXCEPT; - template - inline void big_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT; - template - inline void little_reverse_copy(T from, char* to) BOOST_NOEXCEPT; - template - inline void little_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT; - } // namespace detail +} // namespace detail + +template +inline EndianReversible big_to_native( EndianReversible x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible::value ); + +#if BOOST_ENDIAN_BIG_BYTE - template - inline EndianReversible big_to_native(EndianReversible x) BOOST_NOEXCEPT - { -# if BOOST_ENDIAN_BIG_BYTE return x; -# else + +#else + return endian_reverse(x); -# endif + +#endif } - template - inline EndianReversible native_to_big(EndianReversible x) BOOST_NOEXCEPT - { -# if BOOST_ENDIAN_BIG_BYTE +template +inline EndianReversible native_to_big( EndianReversible x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible::value ); + +#if BOOST_ENDIAN_BIG_BYTE + return x; -# else - return endian_reverse(x); -# endif - } - template - inline EndianReversible little_to_native(EndianReversible x) BOOST_NOEXCEPT - { -# if BOOST_ENDIAN_LITTLE_BYTE +#else + + return endian_reverse(x); + +#endif +} + +template +inline EndianReversible little_to_native( EndianReversible x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible::value ); + +#if BOOST_ENDIAN_LITTLE_BYTE + return x; -# else - return endian_reverse(x); -# endif - } - template - inline EndianReversible native_to_little(EndianReversible x) BOOST_NOEXCEPT - { -# if BOOST_ENDIAN_LITTLE_BYTE +#else + + return endian_reverse(x); + +#endif +} + +template +inline EndianReversible native_to_little( EndianReversible x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible::value ); + +#if BOOST_ENDIAN_LITTLE_BYTE + return x; -# else + +#else + return endian_reverse(x); -# endif - } - namespace detail - { - // Primary template and specializations to support endian_reverse(). - // See rationale in endian_reverse() below. - template - class value_converter ; // primary template - template class value_converter - {public: T operator()(T x) BOOST_NOEXCEPT {return x;}}; - template class value_converter - {public: T operator()(T x) BOOST_NOEXCEPT {return x;}}; - template class value_converter - {public: T operator()(T x) BOOST_NOEXCEPT {return endian_reverse(x);}}; - template class value_converter - {public: T operator()(T x) BOOST_NOEXCEPT {return endian_reverse(x);}}; - } +#endif +} - // generic conditional reverse - template - inline EndianReversible conditional_reverse(EndianReversible from) BOOST_NOEXCEPT { - // work around lack of function template partial specialization by instantiating - // a function object of a class that is partially specialized on the two order - // template parameters, and then calling its operator(). - detail::value_converter tmp; - return tmp(from); - } +namespace detail +{ - // runtime conditional reverse - template - inline EndianReversible conditional_reverse(EndianReversible from, - BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order) BOOST_NOEXCEPT - { - return from_order == to_order ? from : endian_reverse(from); - } +template +inline EndianReversible conditional_reverse_impl( EndianReversible x, boost::true_type ) BOOST_NOEXCEPT +{ + return x; +} + +template +inline EndianReversible conditional_reverse_impl( EndianReversible x, boost::false_type ) BOOST_NOEXCEPT +{ + return endian_reverse( x ); +} + +} // namespace detail + +// generic conditional reverse +template +inline EndianReversible conditional_reverse( EndianReversible x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible::value ); + return detail::conditional_reverse_impl( x, boost::integral_constant() ); +} + +// runtime conditional reverse +template +inline EndianReversible conditional_reverse( EndianReversible x, + BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible::value ); + return from_order == to_order? x: endian_reverse( x ); +} //--------------------------------------------------------------------------------------// // reverse-in-place implementation // //--------------------------------------------------------------------------------------// - template -# if BOOST_ENDIAN_BIG_BYTE - inline void big_to_native_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} -# else - inline void big_to_native_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT - { endian_reverse_inplace(x); } -# endif - template -# if BOOST_ENDIAN_BIG_BYTE - inline void native_to_big_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} -# else - inline void native_to_big_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT - { - endian_reverse_inplace(x); - } -# endif +namespace detail +{ - template -# if BOOST_ENDIAN_LITTLE_BYTE - inline void little_to_native_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} -# else - inline void little_to_native_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT - { endian_reverse_inplace(x); } -# endif - template -# if BOOST_ENDIAN_LITTLE_BYTE - inline void native_to_little_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} -# else - inline void native_to_little_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT - { - endian_reverse_inplace(x); - } -# endif +template struct is_endian_reversible_inplace: boost::integral_constant::value || ( boost::is_integral::value && !boost::is_same::value )> +{ +}; - namespace detail - { - // Primary template and specializations support generic - // endian_reverse_inplace(). - // See rationale in endian_reverse_inplace() below. - template - class converter; // primary template - template class converter - {public: void operator()(T&) BOOST_NOEXCEPT {/*no effect*/}}; - template class converter - {public: void operator()(T&) BOOST_NOEXCEPT {/*no effect*/}}; - template class converter - {public: void operator()(T& x) BOOST_NOEXCEPT { endian_reverse_inplace(x); }}; - template class converter - {public: void operator()(T& x) BOOST_NOEXCEPT { endian_reverse_inplace(x); }}; - } // namespace detail +} // namespace detail - // generic conditional reverse in place - template - inline void conditional_reverse_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT - { - // work around lack of function template partial specialization by instantiating - // a function object of a class that is partially specialized on the two order - // template parameters, and then calling its operator(). - detail::converter tmp; - tmp(x); // call operator () - } +#if BOOST_ENDIAN_BIG_BYTE - // runtime reverse in place - template - inline void conditional_reverse_inplace(EndianReversibleInplace& x, - BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order) - BOOST_NOEXCEPT - { - if (from_order != to_order) - endian_reverse_inplace(x); - } +template +inline void big_to_native_inplace( EndianReversibleInplace& ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); +} +#else - namespace detail - { - template - inline void big_reverse_copy(T from, char* to) BOOST_NOEXCEPT +template +inline void big_to_native_inplace( EndianReversibleInplace& x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); + endian_reverse_inplace( x ); +} + +#endif + +#if BOOST_ENDIAN_BIG_BYTE + +template +inline void native_to_big_inplace( EndianReversibleInplace& ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); +} + +#else + +template +inline void native_to_big_inplace( EndianReversibleInplace& x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); + endian_reverse_inplace( x ); +} + +#endif + +#if BOOST_ENDIAN_LITTLE_BYTE + +template +inline void little_to_native_inplace( EndianReversibleInplace& ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); +} + +#else + +template +inline void little_to_native_inplace( EndianReversibleInplace& x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); + endian_reverse_inplace( x ); +} + +#endif + +#if BOOST_ENDIAN_LITTLE_BYTE + +template +inline void native_to_little_inplace( EndianReversibleInplace& ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); +} + +#else + +template +inline void native_to_little_inplace( EndianReversibleInplace& x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); + endian_reverse_inplace( x ); +} + +#endif + +namespace detail +{ + +template +inline void conditional_reverse_inplace_impl( EndianReversibleInplace&, boost::true_type ) BOOST_NOEXCEPT +{ +} + +template +inline void conditional_reverse_inplace_impl( EndianReversibleInplace& x, boost::false_type ) BOOST_NOEXCEPT +{ + endian_reverse_inplace( x ); +} + +} // namespace detail + +// generic conditional reverse in place +template +inline void conditional_reverse_inplace( EndianReversibleInplace& x ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); + detail::conditional_reverse_inplace_impl( x, boost::integral_constant() ); +} + +// runtime reverse in place +template +inline void conditional_reverse_inplace( EndianReversibleInplace& x, + BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order ) BOOST_NOEXCEPT +{ + BOOST_STATIC_ASSERT( detail::is_endian_reversible_inplace::value ); + + if( from_order != to_order ) { -# if BOOST_ENDIAN_BIG_BYTE - std::memcpy(to, reinterpret_cast(&from), sizeof(T)); -# else - std::reverse_copy(reinterpret_cast(&from), - reinterpret_cast(&from) + sizeof(T), to); -# endif + endian_reverse_inplace( x ); } - template - inline void big_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT - { -# if BOOST_ENDIAN_BIG_BYTE - std::memcpy(reinterpret_cast(&to), from, sizeof(T)); -# else - std::reverse_copy(from, from + sizeof(T), reinterpret_cast(&to)); -# endif - } - template - inline void little_reverse_copy(T from, char* to) BOOST_NOEXCEPT - { -# if BOOST_ENDIAN_LITTLE_BYTE - std::memcpy(to, reinterpret_cast(&from), sizeof(T)); -# else - std::reverse_copy(reinterpret_cast(&from), - reinterpret_cast(&from) + sizeof(T), to); -# endif - } - template - inline void little_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT - { -# if BOOST_ENDIAN_LITTLE_BYTE - std::memcpy(reinterpret_cast(&to), from, sizeof(T)); -# else - std::reverse_copy(from, from + sizeof(T), reinterpret_cast(&to)); -# endif - } - } // namespace detail +} + } // namespace endian } // namespace boost diff --git a/test/conversion_test.cpp b/test/conversion_test.cpp index 823d62c..1399df3 100644 --- a/test/conversion_test.cpp +++ b/test/conversion_test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace be = boost::endian; using std::cout; @@ -27,6 +28,13 @@ using boost::uint32_t; using boost::int64_t; using boost::uint64_t; +template inline T std_endian_reverse(T x) BOOST_NOEXCEPT +{ + T tmp(x); + std::reverse( reinterpret_cast(&tmp), reinterpret_cast(&tmp) + sizeof(T) ); + return tmp; +} + namespace { @@ -102,9 +110,9 @@ namespace # if BOOST_ENDIAN_BIG_BYTE BOOST_TEST_EQ(native, big); - BOOST_TEST_EQ(be::detail::std_endian_reverse(native), little); + BOOST_TEST_EQ(::std_endian_reverse(native), little); # else - BOOST_TEST_EQ(be::detail::std_endian_reverse(native), big); + BOOST_TEST_EQ(::std_endian_reverse(native), big); BOOST_TEST_EQ(native, little); # endif