//// 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 ## 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 3.9.1) except `bool` are collectively called the *endian types*. ### Header `` 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`, }; template Endian endian_reverse(Endian x) noexcept; template EndianReversible big_to_native(EndianReversible x) noexcept; template EndianReversible native_to_big(EndianReversible x) noexcept; template EndianReversible little_to_native(EndianReversible x) noexcept; template EndianReversible native_to_little(EndianReversible x) noexcept; template EndianReversible conditional_reverse(EndianReversible x) noexcept; template EndianReversible conditional_reverse(EndianReversible x, order order1, order order2) noexcept; template void endian_reverse_inplace(EndianReversible& x) noexcept; template void big_to_native_inplace(EndianReversibleInplace& x) noexcept; template void native_to_big_inplace(EndianReversibleInplace& x) noexcept; template void little_to_native_inplace(EndianReversibleInplace& x) noexcept; template void native_to_little_inplace(EndianReversibleInplace& x) noexcept; template void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept; template void conditional_reverse_inplace(EndianReversibleInplace& x, order order1, order order2) 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: * Returns 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, and; * Is a non-member function in the same namespace as `T` that can be found by argument dependent lookup (ADL). |=== [#conversion_endianreversibleinplace] ##### EndianReversibleInplace requirements (in addition to `CopyConstructible`) [%header,cols=2*] |=== |Expression |Requirements |`endian_reverse_inplace(mlx)` a|`T` is an endian type or a class type. If `T` is an endian type, reverses the order of bytes in `mlx`. If `T` is a class type, the function: * Reverses the order of bytes of all data members of `mlx` that have types or arrays of types that meet the `EndianReversible` or `EndianReversibleInplace` requirements, and; * Is a non-member function in the same namespace as `T` that can be found by argument dependent lookup (ADL). |=== NOTE: Because there is a function template for `endian_reverse_inplace` that calls `endian_reverse`, 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 `<>` are required to perform reversal of endianness if needed by making an unqualified call to `endian_reverse()`. The library's function templates requiring `<>` 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. ### Functions ``` template Endian endian_reverse(Endian x) noexcept; ``` [none] * {blank} + Requires:: `Endian` must be a standard integral type that is not `bool`. Returns:: `x`, with the order of its constituent bytes reversed. ``` template EndianReversible big_to_native(EndianReversible x) noexcept; ``` [none] * {blank} + Returns:: `conditional_reverse(x)`. ``` template EndianReversible native_to_big(EndianReversible x) noexcept; ``` [none] * {blank} + Returns:: `conditional_reverse(x)`. ``` template EndianReversible little_to_native(EndianReversible x) noexcept; ``` [none] * {blank} + Returns:: `conditional_reverse(x)`. ``` template EndianReversible native_to_little(EndianReversible x) noexcept; ``` [none] * {blank} + Returns:: `conditional_reverse(x)`. ``` template 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 EndianReversible conditional_reverse(EndianReversible x, order order1, order order2) noexcept; ``` [none] * {blank} + Returns:: `order1 == order2 ? x : endian_reverse(x)`. ``` template void endian_reverse_inplace(EndianReversible& x) noexcept; ``` [none] * {blank} + Effects:: `x` `= endian_reverse(x)`. ``` template void big_to_native_inplace(EndianReversibleInplace& x) noexcept; ``` [none] * {blank} + Effects:: `conditional_reverse_inplace(x)`. ``` template void native_to_big_inplace(EndianReversibleInplace& x) noexcept; ``` [none] * {blank} + Effects:: `conditional_reverse_inplace(x)`. ``` template void little_to_native_inplace(EndianReversibleInplace& x) noexcept; ``` [none] * {blank} + Effects:: `conditional_reverse_inplace(x)`. ``` template void native_to_little_inplace(EndianReversibleInplace& x) noexcept; ``` [none] * {blank} + Effects:: `conditional_reverse_inplace(x)`. ``` template 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 void conditional_reverse_inplace(EndianReversibleInplace& x, order order1, order order2) noexcept; ``` [none] * {blank} + Effects:: If `order1 == order2` then `endian_reverse_inplace(x)`. [none] ## FAQ See the <> 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.