Chris@102: // boost/endian/conversion.hpp -------------------------------------------------------// Chris@102: Chris@102: // Copyright Beman Dawes 2010, 2011, 2014 Chris@102: Chris@102: // Distributed under the Boost Software License, Version 1.0. Chris@102: // http://www.boost.org/LICENSE_1_0.txt Chris@102: Chris@102: #ifndef BOOST_ENDIAN_CONVERSION_HPP Chris@102: #define BOOST_ENDIAN_CONVERSION_HPP Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include // for memcpy Chris@102: Chris@102: //------------------------------------- synopsis ---------------------------------------// Chris@102: Chris@102: namespace boost Chris@102: { Chris@102: namespace endian Chris@102: { Chris@102: #ifndef BOOST_ENDIAN_ORDER_ENUM_DEFINED Chris@102: BOOST_SCOPED_ENUM_START(order) Chris@102: { Chris@102: big, little, Chris@102: # ifdef BOOST_BIG_ENDIAN Chris@102: native = big Chris@102: # else Chris@102: native = little Chris@102: # endif Chris@102: }; BOOST_SCOPED_ENUM_END Chris@102: # define BOOST_ENDIAN_ORDER_ENUM_DEFINED Chris@102: #endif Chris@102: Chris@102: //--------------------------------------------------------------------------------------// Chris@102: // // Chris@102: // return-by-value interfaces // Chris@102: // suggested by Phil Endecott // Chris@102: // // Chris@102: // user-defined types (UDTs) // Chris@102: // // Chris@102: // All return-by-value conversion function templates are required to be implemented in // Chris@102: // terms of an unqualified call to "endian_reverse(x)", a function returning the // Chris@102: // value of x with endianness reversed. This provides a customization point for any // Chris@102: // UDT that provides a "endian_reverse" free-function meeting the requirements. // Chris@102: // It must be defined in the same namespace as the UDT itself so that it will be found // Chris@102: // by argument dependent lookup (ADL). // Chris@102: // // Chris@102: //--------------------------------------------------------------------------------------// Chris@102: Chris@102: // customization for exact-length arithmetic types. See doc/conversion.html/#FAQ Chris@102: inline int8_t endian_reverse(int8_t x) BOOST_NOEXCEPT; Chris@102: inline int16_t endian_reverse(int16_t x) BOOST_NOEXCEPT; Chris@102: inline int32_t endian_reverse(int32_t x) BOOST_NOEXCEPT; Chris@102: inline int64_t endian_reverse(int64_t x) BOOST_NOEXCEPT; Chris@102: inline uint8_t endian_reverse(uint8_t x) BOOST_NOEXCEPT; Chris@102: inline uint16_t endian_reverse(uint16_t x) BOOST_NOEXCEPT; Chris@102: inline uint32_t endian_reverse(uint32_t x) BOOST_NOEXCEPT; Chris@102: inline uint64_t endian_reverse(uint64_t x) BOOST_NOEXCEPT; Chris@102: Chris@102: // reverse byte order unless native endianness is big Chris@102: template Chris@102: inline EndianReversible big_to_native(EndianReversible x) BOOST_NOEXCEPT; Chris@102: // Returns: x if native endian order is big, otherwise endian_reverse(x) Chris@102: template Chris@102: inline EndianReversible native_to_big(EndianReversible x) BOOST_NOEXCEPT; Chris@102: // Returns: x if native endian order is big, otherwise endian_reverse(x) Chris@102: Chris@102: // reverse byte order unless native endianness is little Chris@102: template Chris@102: inline EndianReversible little_to_native(EndianReversible x) BOOST_NOEXCEPT; Chris@102: // Returns: x if native endian order is little, otherwise endian_reverse(x) Chris@102: template Chris@102: inline EndianReversible native_to_little(EndianReversible x) BOOST_NOEXCEPT; Chris@102: // Returns: x if native endian order is little, otherwise endian_reverse(x) Chris@102: Chris@102: // generic conditional reverse byte order Chris@102: template Chris@102: inline EndianReversible conditional_reverse(EndianReversible from) BOOST_NOEXCEPT; Chris@102: // Returns: If From == To have different values, from. Chris@102: // Otherwise endian_reverse(from). Chris@102: // Remarks: The From == To test, and as a consequence which form the return takes, is Chris@102: // is determined at compile time. Chris@102: Chris@102: // runtime conditional reverse byte order Chris@102: template Chris@102: inline EndianReversible conditional_reverse(EndianReversible from, Chris@102: BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order) Chris@102: BOOST_NOEXCEPT; Chris@102: // Returns: from_order == to_order ? from : endian_reverse(from). Chris@102: Chris@102: //------------------------------------------------------------------------------------// Chris@102: Chris@102: Chris@102: // Q: What happended to bswap, htobe, and the other synonym functions based on names Chris@102: // popularized by BSD, OS X, and Linux? Chris@102: // A: Turned out these may be implemented as macros on some systems. Ditto POSIX names Chris@102: // for such functionality. Since macros would cause endless problems with functions Chris@102: // of the same names, and these functions are just synonyms anyhow, they have been Chris@102: // removed. Chris@102: Chris@102: Chris@102: //------------------------------------------------------------------------------------// Chris@102: // // Chris@102: // reverse in place interfaces // Chris@102: // // Chris@102: // user-defined types (UDTs) // Chris@102: // // Chris@102: // All reverse in place function templates are required to be implemented in terms // Chris@102: // of an unqualified call to "endian_reverse_inplace(x)", a function reversing // Chris@102: // the endianness of x, which is a non-const reference. This provides a // Chris@102: // customization point for any UDT that provides a "reverse_inplace" free-function // Chris@102: // meeting the requirements. The free-function must be declared in the same // Chris@102: // namespace as the UDT itself so that it will be found by argument-dependent // Chris@102: // lookup (ADL). // Chris@102: // // Chris@102: //------------------------------------------------------------------------------------// Chris@102: Chris@102: // reverse in place Chris@102: template Chris@102: inline void endian_reverse_inplace(EndianReversible& x) BOOST_NOEXCEPT; Chris@102: // Effects: x = endian_reverse(x) Chris@102: Chris@102: // reverse in place unless native endianness is big Chris@102: template Chris@102: inline void big_to_native_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT; Chris@102: // Effects: none if native byte-order is big, otherwise endian_reverse_inplace(x) Chris@102: template Chris@102: inline void native_to_big_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT; Chris@102: // Effects: none if native byte-order is big, otherwise endian_reverse_inplace(x) Chris@102: Chris@102: // reverse in place unless native endianness is little Chris@102: template Chris@102: inline void little_to_native_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT; Chris@102: // Effects: none if native byte-order is little, otherwise endian_reverse_inplace(x); Chris@102: template Chris@102: inline void native_to_little_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT; Chris@102: // Effects: none if native byte-order is little, otherwise endian_reverse_inplace(x); Chris@102: Chris@102: // generic conditional reverse in place Chris@102: template Chris@102: inline void conditional_reverse_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT; Chris@102: Chris@102: // runtime reverse in place Chris@102: template Chris@102: inline void conditional_reverse_inplace(EndianReversibleInplace& x, Chris@102: BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order) Chris@102: BOOST_NOEXCEPT; Chris@102: Chris@102: //----------------------------------- end synopsis -------------------------------------// Chris@102: Chris@102: namespace detail Chris@102: { Chris@102: // generic reverse function template implementation approach using std::reverse Chris@102: // suggested by Mathias Gaunard. Primary motivation for inclusion is to have an Chris@102: // independent implementation to test against. Chris@102: Chris@102: template Chris@102: inline T std_endian_reverse(T x) BOOST_NOEXCEPT Chris@102: { Chris@102: T tmp(x); Chris@102: std::reverse( Chris@102: reinterpret_cast(&tmp), Chris@102: reinterpret_cast(&tmp) + sizeof(T)); Chris@102: return tmp; Chris@102: } Chris@102: Chris@102: // conditional unaligned reverse copy, patterned after std::reverse_copy Chris@102: template Chris@102: inline void big_reverse_copy(T from, char* to) BOOST_NOEXCEPT; Chris@102: template Chris@102: inline void big_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT; Chris@102: template Chris@102: inline void little_reverse_copy(T from, char* to) BOOST_NOEXCEPT; Chris@102: template Chris@102: inline void little_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT; Chris@102: } // namespace detail Chris@102: Chris@102: //--------------------------------------------------------------------------------------// Chris@102: // // Chris@102: // return-by-value implementation // Chris@102: // // Chris@102: // -- portable approach suggested by tymofey, with avoidance of undefined behavior // Chris@102: // as suggested by Giovanni Piero Deretta, with a further refinement suggested // Chris@102: // by Pyry Jahkola. // Chris@102: // -- intrinsic approach suggested by reviewers, and by David Stone, who provided // Chris@102: // his Boost licensed macro implementation (detail/intrinsic.hpp) // Chris@102: // // Chris@102: //--------------------------------------------------------------------------------------// Chris@102: Chris@102: inline int8_t endian_reverse(int8_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: return x; Chris@102: } Chris@102: Chris@102: inline int16_t endian_reverse(int16_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_ENDIAN_NO_INTRINSICS Chris@102: return (static_cast(x) << 8) Chris@102: | (static_cast(x) >> 8); Chris@102: # else Chris@102: return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(static_cast(x)); Chris@102: # endif Chris@102: } Chris@102: Chris@102: inline int32_t endian_reverse(int32_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_ENDIAN_NO_INTRINSICS Chris@102: uint32_t step16; Chris@102: step16 = static_cast(x) << 16 | static_cast(x) >> 16; Chris@102: return Chris@102: ((static_cast(step16) << 8) & 0xff00ff00) Chris@102: | ((static_cast(step16) >> 8) & 0x00ff00ff); Chris@102: # else Chris@102: return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(static_cast(x)); Chris@102: # endif Chris@102: } Chris@102: Chris@102: inline int64_t endian_reverse(int64_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_ENDIAN_NO_INTRINSICS Chris@102: uint64_t step32, step16; Chris@102: step32 = static_cast(x) << 32 | static_cast(x) >> 32; Chris@102: step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16 Chris@102: | (step32 & 0xFFFF0000FFFF0000ULL) >> 16; Chris@102: return static_cast((step16 & 0x00FF00FF00FF00FFULL) << 8 Chris@102: | (step16 & 0xFF00FF00FF00FF00ULL) >> 8); Chris@102: # else Chris@102: return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(static_cast(x)); Chris@102: # endif Chris@102: } Chris@102: Chris@102: inline uint8_t endian_reverse(uint8_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: return x; Chris@102: } Chris@102: Chris@102: inline uint16_t endian_reverse(uint16_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_ENDIAN_NO_INTRINSICS Chris@102: return (x << 8) Chris@102: | (x >> 8); Chris@102: # else Chris@102: return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x); Chris@102: # endif Chris@102: } Chris@102: Chris@102: inline uint32_t endian_reverse(uint32_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_ENDIAN_NO_INTRINSICS Chris@102: uint32_t step16; Chris@102: step16 = x << 16 | x >> 16; Chris@102: return Chris@102: ((step16 << 8) & 0xff00ff00) Chris@102: | ((step16 >> 8) & 0x00ff00ff); Chris@102: # else Chris@102: return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x); Chris@102: # endif Chris@102: } Chris@102: Chris@102: inline uint64_t endian_reverse(uint64_t x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_ENDIAN_NO_INTRINSICS Chris@102: uint64_t step32, step16; Chris@102: step32 = x << 32 | x >> 32; Chris@102: step16 = (step32 & 0x0000FFFF0000FFFFULL) << 16 Chris@102: | (step32 & 0xFFFF0000FFFF0000ULL) >> 16; Chris@102: return (step16 & 0x00FF00FF00FF00FFULL) << 8 Chris@102: | (step16 & 0xFF00FF00FF00FF00ULL) >> 8; Chris@102: # else Chris@102: return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x); Chris@102: # endif Chris@102: } Chris@102: Chris@102: template Chris@102: inline EndianReversible big_to_native(EndianReversible x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_BIG_ENDIAN Chris@102: return x; Chris@102: # else Chris@102: return endian_reverse(x); Chris@102: # endif Chris@102: } Chris@102: Chris@102: template Chris@102: inline EndianReversible native_to_big(EndianReversible x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_BIG_ENDIAN Chris@102: return x; Chris@102: # else Chris@102: return endian_reverse(x); Chris@102: # endif Chris@102: } Chris@102: Chris@102: template Chris@102: inline EndianReversible little_to_native(EndianReversible x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_LITTLE_ENDIAN Chris@102: return x; Chris@102: # else Chris@102: return endian_reverse(x); Chris@102: # endif Chris@102: } Chris@102: Chris@102: template Chris@102: inline EndianReversible native_to_little(EndianReversible x) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_LITTLE_ENDIAN Chris@102: return x; Chris@102: # else Chris@102: return endian_reverse(x); Chris@102: # endif Chris@102: } Chris@102: Chris@102: namespace detail Chris@102: { Chris@102: // Primary template and specializations to support endian_reverse(). Chris@102: // See rationale in endian_reverse() below. Chris@102: template Chris@102: class value_converter ; // primary template Chris@102: template class value_converter Chris@102: {public: T operator()(T x) BOOST_NOEXCEPT {return x;}}; Chris@102: template class value_converter Chris@102: {public: T operator()(T x) BOOST_NOEXCEPT {return x;}}; Chris@102: template class value_converter Chris@102: {public: T operator()(T x) BOOST_NOEXCEPT {return endian_reverse(x);}}; Chris@102: template class value_converter Chris@102: {public: T operator()(T x) BOOST_NOEXCEPT {return endian_reverse(x);}}; Chris@102: } Chris@102: Chris@102: // generic conditional reverse Chris@102: template Chris@102: inline EndianReversible conditional_reverse(EndianReversible from) BOOST_NOEXCEPT { Chris@102: // work around lack of function template partial specialization by instantiating Chris@102: // a function object of a class that is partially specialized on the two order Chris@102: // template parameters, and then calling its operator(). Chris@102: detail::value_converter tmp; Chris@102: return tmp(from); Chris@102: } Chris@102: Chris@102: // runtime conditional reverse Chris@102: template Chris@102: inline EndianReversible conditional_reverse(EndianReversible from, Chris@102: BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order) BOOST_NOEXCEPT Chris@102: { Chris@102: return from_order == to_order ? from : endian_reverse(from); Chris@102: } Chris@102: Chris@102: //--------------------------------------------------------------------------------------// Chris@102: // reverse-in-place implementation // Chris@102: //--------------------------------------------------------------------------------------// Chris@102: Chris@102: // reverse in place Chris@102: template Chris@102: inline void endian_reverse_inplace(EndianReversible& x) BOOST_NOEXCEPT Chris@102: { Chris@102: x = endian_reverse(x); Chris@102: } Chris@102: Chris@102: template Chris@102: # ifdef BOOST_BIG_ENDIAN Chris@102: inline void big_to_native_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} Chris@102: # else Chris@102: inline void big_to_native_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT Chris@102: { endian_reverse_inplace(x); } Chris@102: # endif Chris@102: template Chris@102: # ifdef BOOST_BIG_ENDIAN Chris@102: inline void native_to_big_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} Chris@102: # else Chris@102: inline void native_to_big_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT Chris@102: { Chris@102: endian_reverse_inplace(x); Chris@102: } Chris@102: # endif Chris@102: Chris@102: template Chris@102: # ifdef BOOST_LITTLE_ENDIAN Chris@102: inline void little_to_native_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} Chris@102: # else Chris@102: inline void little_to_native_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT Chris@102: { endian_reverse_inplace(x); } Chris@102: # endif Chris@102: template Chris@102: # ifdef BOOST_LITTLE_ENDIAN Chris@102: inline void native_to_little_inplace(EndianReversibleInplace&) BOOST_NOEXCEPT {} Chris@102: # else Chris@102: inline void native_to_little_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT Chris@102: { Chris@102: endian_reverse_inplace(x); Chris@102: } Chris@102: # endif Chris@102: Chris@102: namespace detail Chris@102: { Chris@102: // Primary template and specializations support generic Chris@102: // endian_reverse_inplace(). Chris@102: // See rationale in endian_reverse_inplace() below. Chris@102: template Chris@102: class converter; // primary template Chris@102: template class converter Chris@102: {public: void operator()(T&) BOOST_NOEXCEPT {/*no effect*/}}; Chris@102: template class converter Chris@102: {public: void operator()(T&) BOOST_NOEXCEPT {/*no effect*/}}; Chris@102: template class converter Chris@102: {public: void operator()(T& x) BOOST_NOEXCEPT { endian_reverse_inplace(x); }}; Chris@102: template class converter Chris@102: {public: void operator()(T& x) BOOST_NOEXCEPT { endian_reverse_inplace(x); }}; Chris@102: } // namespace detail Chris@102: Chris@102: // generic conditional reverse in place Chris@102: template Chris@102: inline void conditional_reverse_inplace(EndianReversibleInplace& x) BOOST_NOEXCEPT Chris@102: { Chris@102: // work around lack of function template partial specialization by instantiating Chris@102: // a function object of a class that is partially specialized on the two order Chris@102: // template parameters, and then calling its operator(). Chris@102: detail::converter tmp; Chris@102: tmp(x); // call operator () Chris@102: } Chris@102: Chris@102: // runtime reverse in place Chris@102: template Chris@102: inline void conditional_reverse_inplace(EndianReversibleInplace& x, Chris@102: BOOST_SCOPED_ENUM(order) from_order, BOOST_SCOPED_ENUM(order) to_order) Chris@102: BOOST_NOEXCEPT Chris@102: { Chris@102: if (from_order != to_order) Chris@102: endian_reverse_inplace(x); Chris@102: } Chris@102: Chris@102: Chris@102: namespace detail Chris@102: { Chris@102: template Chris@102: inline void big_reverse_copy(T from, char* to) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_BIG_ENDIAN Chris@102: std::memcpy(to, reinterpret_cast(&from), sizeof(T)); Chris@102: # else Chris@102: std::reverse_copy(reinterpret_cast(&from), Chris@102: reinterpret_cast(&from) + sizeof(T), to); Chris@102: # endif Chris@102: } Chris@102: template Chris@102: inline void big_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_BIG_ENDIAN Chris@102: std::memcpy(reinterpret_cast(&to), from, sizeof(T)); Chris@102: # else Chris@102: std::reverse_copy(from, from + sizeof(T), reinterpret_cast(&to)); Chris@102: # endif Chris@102: } Chris@102: template Chris@102: inline void little_reverse_copy(T from, char* to) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_LITTLE_ENDIAN Chris@102: std::memcpy(to, reinterpret_cast(&from), sizeof(T)); Chris@102: # else Chris@102: std::reverse_copy(reinterpret_cast(&from), Chris@102: reinterpret_cast(&from) + sizeof(T), to); Chris@102: # endif Chris@102: } Chris@102: template Chris@102: inline void little_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT Chris@102: { Chris@102: # ifdef BOOST_LITTLE_ENDIAN Chris@102: std::memcpy(reinterpret_cast(&to), from, sizeof(T)); Chris@102: # else Chris@102: std::reverse_copy(from, from + sizeof(T), reinterpret_cast(&to)); Chris@102: # endif Chris@102: } Chris@102: } // namespace detail Chris@102: } // namespace endian Chris@102: } // namespace boost Chris@102: Chris@102: #endif // BOOST_ENDIAN_CONVERSION_HPP