| //// |
| Copyright 2011-2016 Beman Dawes |
| |
| Distributed under the Boost Software License, Version 1.0. |
| (http://www.boost.org/LICENSE_1_0.txt) |
| //// |
| |
| [#conversion] |
| # Endian Conversion Functions |
| :idprefix: conversion_ |
| |
| ## Introduction |
| |
| Header `boost/endian/conversion.hpp` provides byte order reversal and conversion |
| functions that convert objects of the built-in integer types between native, |
| big, or little endian byte ordering. User defined types are also supported. |
| |
| ## Reference |
| |
| Functions are implemented `inline` if appropriate. For {cpp}03 compilers, |
| `noexcept` is elided. Boost scoped enum emulation is used so that the library |
| still works for compilers that do not support scoped enums. |
| |
| ### Definitions |
| |
| *Endianness* refers to the ordering of bytes within internal or external |
| integers and other arithmetic data. Most-significant byte first is called |
| *big endian* ordering. Least-significant byte first is called |
| *little endian* ordering. Other orderings are possible and some CPU |
| architectures support both big and little ordering. |
| |
| NOTE: The names are derived from |
| http://en.wikipedia.org/wiki/Jonathan_Swift[Jonathan Swift]'s satirical novel |
| _http://en.wikipedia.org/wiki/Gulliver's_Travels[Gulliver's Travels]_, where |
| rival kingdoms opened their soft-boiled eggs at different ends. Wikipedia has an |
| extensive description of https://en.wikipedia.org/wiki/Endianness[Endianness]. |
| |
| The standard integral types ({cpp}std [basic.fundamental]) except `bool` and |
| the scoped enumeration types ({cpp}std [dcl.enum]) are collectively called the |
| *endian types*. In the absence of padding bits, which is true on the platforms |
| supported by the Boost.Endian library, endian types have the property that all |
| of their bit patterns are valid values, which means that when an object of an |
| endian type has its constituent bytes reversed, the result is another valid value. |
| This allows `endian_reverse` to take and return by value. |
| |
| Other built-in types, such as `bool`, `float`, or unscoped enumerations, do not |
| have the same property, which means that reversing their constituent bytes may |
| produce an invalid value, leading to undefined behavior. These types are therefore |
| disallowed in `endian_reverse`, but are still allowed in `endian_reverse_inplace`. |
| Even if an object becomes invalid as a result of reversing its bytes, as long as |
| its value is never read, there would be no undefined behavior. |
| |
| ### Header `<boost/endian/conversion.hpp>` Synopsis |
| |
| [subs=+quotes] |
| ``` |
| #define BOOST_ENDIAN_INTRINSIC_MSG \ |
| "`message describing presence or absence of intrinsics`" |
| |
| namespace boost |
| { |
| namespace endian |
| { |
| enum class order |
| { |
| native = `see below`, |
| big = `see below`, |
| little = `see below`, |
| }; |
| |
| // Byte reversal functions |
| |
| template <class Endian> |
| Endian endian_reverse(Endian x) noexcept; |
| |
| template <class EndianReversible> |
| EndianReversible big_to_native(EndianReversible x) noexcept; |
| template <class EndianReversible> |
| EndianReversible native_to_big(EndianReversible x) noexcept; |
| template <class EndianReversible> |
| EndianReversible little_to_native(EndianReversible x) noexcept; |
| template <class EndianReversible> |
| EndianReversible native_to_little(EndianReversible x) noexcept; |
| |
| template <order O1, order O2, class EndianReversible> |
| EndianReversible conditional_reverse(EndianReversible x) noexcept; |
| template <class EndianReversible> |
| EndianReversible conditional_reverse(EndianReversible x, |
| order order1, order order2) noexcept; |
| |
| // In-place byte reversal functions |
| |
| template <class EndianReversible> |
| void endian_reverse_inplace(EndianReversible& x) noexcept; |
| |
| template<class EndianReversibleInplace, std::size_t N> |
| void endian_reverse_inplace(EndianReversibleInplace (&x)[N]) noexcept; |
| |
| template <class EndianReversibleInplace> |
| void big_to_native_inplace(EndianReversibleInplace& x) noexcept; |
| template <class EndianReversibleInplace> |
| void native_to_big_inplace(EndianReversibleInplace& x) noexcept; |
| template <class EndianReversibleInplace> |
| void little_to_native_inplace(EndianReversibleInplace& x) noexcept; |
| template <class EndianReversibleInplace> |
| void native_to_little_inplace(EndianReversibleInplace& x) noexcept; |
| |
| template <order O1, order O2, class EndianReversibleInplace> |
| void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept; |
| template <class EndianReversibleInplace> |
| void conditional_reverse_inplace(EndianReversibleInplace& x, |
| order order1, order order2) noexcept; |
| |
| // Generic load and store functions |
| |
| template<class T, std::size_t N, order Order> |
| T endian_load( unsigned char const * p ) noexcept; |
| |
| template<class T, std::size_t N, order Order> |
| void endian_store( unsigned char * p, T const & v ) noexcept; |
| |
| // Convenience load functions |
| |
| boost::int16_t load_little_s16( unsigned char const * p ) noexcept; |
| boost::uint16_t load_little_u16( unsigned char const * p ) noexcept; |
| boost::int16_t load_big_s16( unsigned char const * p ) noexcept; |
| boost::uint16_t load_big_u16( unsigned char const * p ) noexcept; |
| |
| boost::int32_t load_little_s24( unsigned char const * p ) noexcept; |
| boost::uint32_t load_little_u24( unsigned char const * p ) noexcept; |
| boost::int32_t load_big_s24( unsigned char const * p ) noexcept; |
| boost::uint32_t load_big_u24( unsigned char const * p ) noexcept; |
| |
| boost::int32_t load_little_s32( unsigned char const * p ) noexcept; |
| boost::uint32_t load_little_u32( unsigned char const * p ) noexcept; |
| boost::int32_t load_big_s32( unsigned char const * p ) noexcept; |
| boost::uint32_t load_big_u32( unsigned char const * p ) noexcept; |
| |
| boost::int64_t load_little_s40( unsigned char const * p ) noexcept; |
| boost::uint64_t load_little_u40( unsigned char const * p ) noexcept; |
| boost::int64_t load_big_s40( unsigned char const * p ) noexcept; |
| boost::uint64_t load_big_u40( unsigned char const * p ) noexcept; |
| |
| boost::int64_t load_little_s48( unsigned char const * p ) noexcept; |
| boost::uint64_t load_little_u48( unsigned char const * p ) noexcept; |
| boost::int64_t load_big_s48( unsigned char const * p ) noexcept; |
| boost::uint64_t load_big_u48( unsigned char const * p ) noexcept; |
| |
| boost::int64_t load_little_s56( unsigned char const * p ) noexcept; |
| boost::uint64_t load_little_u56( unsigned char const * p ) noexcept; |
| boost::int64_t load_big_s56( unsigned char const * p ) noexcept; |
| boost::uint64_t load_big_u56( unsigned char const * p ) noexcept; |
| |
| boost::int64_t load_little_s64( unsigned char const * p ) noexcept; |
| boost::uint64_t load_little_u64( unsigned char const * p ) noexcept; |
| boost::int64_t load_big_s64( unsigned char const * p ) noexcept; |
| boost::uint64_t load_big_u64( unsigned char const * p ) noexcept; |
| |
| // Convenience store functions |
| |
| void store_little_s16( unsigned char * p, boost::int16_t v ) noexcept; |
| void store_little_u16( unsigned char * p, boost::uint16_t v ) noexcept; |
| void store_big_s16( unsigned char * p, boost::int16_t v ) noexcept; |
| void store_big_u16( unsigned char * p, boost::uint16_t v ) noexcept; |
| |
| void store_little_s24( unsigned char * p, boost::int32_t v ) noexcept; |
| void store_little_u24( unsigned char * p, boost::uint32_t v ) noexcept; |
| void store_big_s24( unsigned char * p, boost::int32_t v ) noexcept; |
| void store_big_u24( unsigned char * p, boost::uint32_t v ) noexcept; |
| |
| void store_little_s32( unsigned char * p, boost::int32_t v ) noexcept; |
| void store_little_u32( unsigned char * p, boost::uint32_t v ) noexcept; |
| void store_big_s32( unsigned char * p, boost::int32_t v ) noexcept; |
| void store_big_u32( unsigned char * p, boost::uint32_t v ) noexcept; |
| |
| void store_little_s40( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_little_u40( unsigned char * p, boost::uint64_t v ) noexcept; |
| void store_big_s40( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_big_u40( unsigned char * p, boost::uint64_t v ) noexcept; |
| |
| void store_little_s48( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_little_u48( unsigned char * p, boost::uint64_t v ) noexcept; |
| void store_big_s48( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_big_u48( unsigned char * p, boost::uint64_t v ) noexcept; |
| |
| void store_little_s56( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_little_u56( unsigned char * p, boost::uint64_t v ) noexcept; |
| void store_big_s56( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_big_u56( unsigned char * p, boost::uint64_t v ) noexcept; |
| |
| void store_little_s64( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_little_u64( unsigned char * p, boost::uint64_t v ) noexcept; |
| void store_big_s64( unsigned char * p, boost::int64_t v ) noexcept; |
| void store_big_u64( unsigned char * p, boost::uint64_t v ) noexcept; |
| |
| } // namespace endian |
| } // namespace boost |
| ``` |
| |
| The values of `order::little` and `order::big` shall not be equal to one |
| another. |
| |
| The value of `order::native` shall be: |
| |
| * equal to `order::big` if the execution environment is big endian, otherwise |
| * equal to `order::little` if the execution environment is little endian, |
| otherwise |
| * unequal to both `order::little` and `order::big`. |
| |
| ### Requirements |
| |
| #### Template argument requirements |
| |
| The template definitions in the `boost/endian/conversion.hpp` header refer to |
| various named requirements whose details are set out in the tables in this |
| subsection. In these tables, `T` is an object or reference type to be supplied |
| by a {cpp} program instantiating a template; `x` is a value of type (possibly |
| `const`) `T`; `mlx` is a modifiable lvalue of type `T`. |
| |
| [#conversion_endianreversible] |
| ##### EndianReversible requirements (in addition to `CopyConstructible`) |
| |
| [%header,cols=3*] |
| |=== |
| |Expression |Return |Requirements |
| |`endian_reverse(x)` |`T` |
| a|`T` is an endian type or a class type. |
| |
| If `T` is an endian type, returns the value of `x` with the order of bytes |
| reversed. |
| |
| If `T` is a class type, the function: |
| |
| * Is expected to be implemented by the user, as a non-member function in the same |
| namespace as `T` that can be found by argument dependent lookup (ADL); |
| * Should return the value of `x` with the order of bytes reversed for all data members |
| of types or arrays of types that meet the `EndianReversible` requirements. |
| |=== |
| |
| [#conversion_endianreversibleinplace] |
| ##### EndianReversibleInplace requirements |
| |
| [%header,cols=2*] |
| |=== |
| |Expression |Requirements |
| |`endian_reverse_inplace(mlx)` |
| a|`T` is an integral type, an enumeration type, `float`, `double`, a class type, |
| or an array type. |
| |
| If `T` is not a class type or an array type, reverses the order of bytes in `mlx`. |
| |
| If `T` is a class type, the function: |
| |
| * Is expected to be implemented by the user, as a non-member function in the same |
| namespace as `T` that can be found by argument dependent lookup (ADL); |
| * Should reverse the order of bytes of all data members of `mlx` that have types or |
| arrays of types that meet the `EndianReversible` or `EndianReversibleInplace` |
| requirements. |
| |
| If `T` is an array type, calls `endian_reverse_inplace` on each element. |
| |=== |
| |
| NOTE: Because there is a function template for `endian_reverse_inplace` that |
| calls `endian_reverse` for class types, only `endian_reverse` is required for a |
| user-defined type to meet the `EndianReversibleInplace` requirements. Although |
| user-defined types are not required to supply an `endian_reverse_inplace` function, |
| doing so may improve efficiency. |
| |
| #### Customization points for user-defined types (UDTs) |
| |
| This subsection describes requirements on the Endian library's implementation. |
| |
| The library's function templates requiring |
| `<<conversion_endianreversible,EndianReversible>>` are required to perform |
| reversal of endianness if needed by making an unqualified call to |
| `endian_reverse()`. |
| |
| The library's function templates requiring |
| `<<conversion_endianreversibleinplace,EndianReversibleInplace>>` are required to |
| perform reversal of endianness if needed by making an unqualified call to |
| `endian_reverse_inplace()`. |
| |
| See `example/udt_conversion_example.cpp` for an example user-defined type. |
| |
| ### Byte Reversal Functions |
| |
| ``` |
| template <class Endian> |
| Endian endian_reverse(Endian x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Requires:: `Endian` must be a standard integral type that is not `bool`, |
| or a scoped enumeration type. |
| Returns:: `x`, with the order of its constituent bytes reversed. |
| |
| ``` |
| template <class EndianReversible> |
| EndianReversible big_to_native(EndianReversible x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: `conditional_reverse<order::big, order::native>(x)`. |
| |
| ``` |
| template <class EndianReversible> |
| EndianReversible native_to_big(EndianReversible x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: `conditional_reverse<order::native, order::big>(x)`. |
| |
| ``` |
| template <class EndianReversible> |
| EndianReversible little_to_native(EndianReversible x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: `conditional_reverse<order::little, order::native>(x)`. |
| |
| ``` |
| template <class EndianReversible> |
| EndianReversible native_to_little(EndianReversible x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: `conditional_reverse<order::native, order::little>(x)`. |
| |
| ``` |
| template <order O1, order O2, class EndianReversible> |
| EndianReversible conditional_reverse(EndianReversible x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: `x` if `O1 == O2,` otherwise `endian_reverse(x)`. |
| Remarks:: Whether `x` or `endian_reverse(x)` is to be returned shall be |
| determined at compile time. |
| |
| ``` |
| template <class EndianReversible> |
| EndianReversible conditional_reverse(EndianReversible x, |
| order order1, order order2) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: |
| `order1 == order2? x: endian_reverse(x)`. |
| |
| ### In-place Byte Reversal Functions |
| |
| ``` |
| template <class EndianReversible> |
| void endian_reverse_inplace(EndianReversible& x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: When `EndianReversible` is a class type, |
| `x = endian_reverse(x);`. When `EndianReversible` is an integral |
| type, an enumeration type, `float`, or `double`, reverses the |
| order of the constituent bytes of `x`. Otherwise, the program is |
| ill-formed. |
| |
| ``` |
| template<class EndianReversibleInplace, std::size_t N> |
| void endian_reverse_inplace(EndianReversibleInplace (&x)[N]) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: Calls `endian_reverse_inplace(x[i])` for `i` from `0` to `N-1`. |
| |
| ``` |
| template <class EndianReversibleInplace> |
| void big_to_native_inplace(EndianReversibleInplace& x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: `conditional_reverse_inplace<order::big, order::native>(x)`. |
| |
| ``` |
| template <class EndianReversibleInplace> |
| void native_to_big_inplace(EndianReversibleInplace& x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: `conditional_reverse_inplace<order::native, order::big>(x)`. |
| |
| ``` |
| template <class EndianReversibleInplace> |
| void little_to_native_inplace(EndianReversibleInplace& x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: `conditional_reverse_inplace<order::little, order::native>(x)`. |
| |
| ``` |
| template <class EndianReversibleInplace> |
| void native_to_little_inplace(EndianReversibleInplace& x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: `conditional_reverse_inplace<order::native, order::little>(x)`. |
| |
| ``` |
| template <order O1, order O2, class EndianReversibleInplace> |
| void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: None if `O1 == O2,` otherwise `endian_reverse_inplace(x)`. |
| Remarks:: Which effect applies shall be determined at compile time. |
| |
| ``` |
| template <class EndianReversibleInplace> |
| void conditional_reverse_inplace(EndianReversibleInplace& x, |
| order order1, order order2) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: |
| If `order1 == order2` then `endian_reverse_inplace(x)`. |
| |
| ### Generic Load and Store Functions |
| |
| ``` |
| template<class T, std::size_t N, order Order> |
| T endian_load( unsigned char const * p ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Requires:: `sizeof(T)` must be 1, 2, 4, or 8. `N` must be between 1 and |
| `sizeof(T)`, inclusive. `T` must be trivially copyable. If `N` is not |
| equal to `sizeof(T)`, `T` must be integral or `enum`. |
| |
| Effects:: Reads `N` bytes starting from `p`, in forward or reverse order |
| depending on whether `Order` matches the native endianness or not, |
| interprets the resulting bit pattern as a value of type `T`, and returns it. |
| If `sizeof(T)` is bigger than `N`, zero-extends when `T` is unsigned, |
| sign-extends otherwise. |
| |
| ``` |
| template<class T, std::size_t N, order Order> |
| void endian_store( unsigned char * p, T const & v ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Requires:: `sizeof(T)` must be 1, 2, 4, or 8. `N` must be between 1 and |
| `sizeof(T)`, inclusive. `T` must be trivially copyable. If `N` is not |
| equal to `sizeof(T)`, `T` must be integral or `enum`. |
| |
| Effects:: Writes to `p` the `N` least significant bytes from the object |
| representation of `v`, in forward or reverse order depending on whether |
| `Order` matches the native endianness or not. |
| |
| ### Convenience Load Functions |
| |
| ``` |
| inline boost::intM_t load_little_sN( unsigned char const * p ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Reads an N-bit signed little-endian integer from `p`. |
| + |
| Returns:: `endian_load<boost::intM_t, N/8, order::little>( p )`. |
| |
| ``` |
| inline boost::uintM_t load_little_uN( unsigned char const * p ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Reads an N-bit unsigned little-endian integer from `p`. |
| + |
| Returns:: `endian_load<boost::uintM_t, N/8, order::little>( p )`. |
| |
| ``` |
| inline boost::intM_t load_big_sN( unsigned char const * p ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Reads an N-bit signed big-endian integer from `p`. |
| + |
| Returns:: `endian_load<boost::intM_t, N/8, order::big>( p )`. |
| |
| ``` |
| inline boost::uintM_t load_big_uN( unsigned char const * p ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Reads an N-bit unsigned big-endian integer from `p`. |
| + |
| Returns:: |
| `endian_load<boost::uintM_t, N/8, order::big>( p )`. |
| |
| ### Convenience Store Functions |
| |
| ``` |
| inline void store_little_sN( unsigned char * p, boost::intM_t v ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Writes an N-bit signed little-endian integer to `p`. |
| + |
| Effects:: `endian_store<boost::intM_t, N/8, order::little>( p, v )`. |
| |
| ``` |
| inline void store_little_uN( unsigned char * p, boost::uintM_t v ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Writes an N-bit unsigned little-endian integer to `p`. |
| + |
| Effects:: `endian_store<boost::uintM_t, N/8, order::little>( p, v )`. |
| |
| ``` |
| inline void store_big_sN( unsigned char * p, boost::intM_t v ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Writes an N-bit signed big-endian integer to `p`. |
| + |
| Effects:: `endian_store<boost::intM_t, N/8, order::big>( p, v )`. |
| |
| ``` |
| inline void store_big_uN( unsigned char * p, boost::uintM_t v ) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Writes an N-bit unsigned big-endian integer to `p`. |
| + |
| Effects:: |
| `endian_store<boost::uintM_t, N/8, order::big>( p, v )`. |
| |
| ## FAQ |
| |
| See the <<overview_faq,Overview FAQ>> for a library-wide FAQ. |
| |
| Why are both value returning and modify-in-place functions provided?:: |
| Returning the result by value is the standard C and {cpp} idiom for functions |
| that compute a value from an argument. Modify-in-place functions allow cleaner |
| code in many real-world endian use cases and are more efficient for user-defined |
| types that have members such as string data that do not need to be reversed. |
| Thus both forms are provided. |
| |
| Why not use the Linux names (htobe16, htole16, be16toh, le16toh, etc.) ?:: |
| Those names are non-standard and vary even between POSIX-like operating |
| systems. A {cpp} library TS was going to use those names, but found they were |
| sometimes implemented as macros. Since macros do not respect scoping and |
| namespace rules, to use them would be very error prone. |
| |
| ## Acknowledgements |
| |
| Tomas Puverle was instrumental in identifying and articulating the need to |
| support endian conversion as separate from endian integer types. Phil Endecott |
| suggested the form of the value returning signatures. Vicente Botet and other |
| reviewers suggested supporting user defined types. General reverse template |
| implementation approach using `std::reverse` suggested by Mathias Gaunard. |
| Portable implementation approach for 16, 32, and 64-bit integers suggested by |
| tymofey, with avoidance of undefined behavior as suggested by Giovanni Piero |
| Deretta, and a further refinement suggested by Pyry Jahkola. Intrinsic builtins |
| implementation approach for 16, 32, and 64-bit integers suggested by several |
| reviewers, and by David Stone, who provided his Boost licensed macro |
| implementation that became the starting point for |
| `boost/endian/detail/intrinsic.hpp`. Pierre Talbot provided the |
| `int8_t endian_reverse()` and templated `endian_reverse_inplace()` |
| implementations. |