From 607cc7da73a0cd467366b529963cd31dfc6fe8e5 Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Sun, 24 Mar 2019 19:38:16 -0400 Subject: [PATCH] Convert Endian Conversion Functions to asciidoc --- doc/endian.adoc | 2 + doc/endian/conversion.adoc | 341 +++++++++++++++++++++++++++++++++++++ 2 files changed, 343 insertions(+) create mode 100644 doc/endian/conversion.adoc diff --git a/doc/endian.adoc b/doc/endian.adoc index 1f4911c..8f09fd2 100644 --- a/doc/endian.adoc +++ b/doc/endian.adoc @@ -18,6 +18,8 @@ Beman Dawes include::endian/overview.adoc[] +include::endian/conversion.adoc[] + include::endian/choosing_approach.adoc[] include::endian/mini_review_topics.adoc[] diff --git a/doc/endian/conversion.adoc b/doc/endian/conversion.adoc new file mode 100644 index 0000000..30a955a --- /dev/null +++ b/doc/endian/conversion.adoc @@ -0,0 +1,341 @@ +//// +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`, + }; + + int8_t endian_reverse(int8_t x) noexcept; + int16_t endian_reverse(int16_t x) noexcept; + int32_t endian_reverse(int32_t x) noexcept; + int64_t endian_reverse(int64_t x) noexcept; + uint8_t endian_reverse(uint8_t x) noexcept; + uint16_t endian_reverse(uint16_t x) noexcept; + uint32_t endian_reverse(uint32_t x) noexcept; + uint64_t endian_reverse(uint64_t 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 + +``` +int8_t endian_reverse(int8_t x) noexcept; +int16_t endian_reverse(int16_t x) noexcept; +int32_t endian_reverse(int32_t x) noexcept; +int64_t endian_reverse(int64_t x) noexcept; +uint8_t endian_reverse(uint8_t x) noexcept; +uint16_t endian_reverse(uint16_t x) noexcept; +uint32_t endian_reverse(uint32_t x) noexcept; +uint64_t endian_reverse(uint64_t x) noexcept; +``` +[horizontal] +Returns:: `x`, with the order of its constituent bytes reversed. +Remarks:: The type of `x` meets the `EndianReversible` requirements. + +NOTE: The Boost.Endian library does not provide overloads for the {cpp} standard +library supplied types. + +``` +template +EndianReversible big_to_native(EndianReversible x) noexcept; +``` +[horizontal] +Returns:: `conditional_reverse(x)`. + +``` +template +EndianReversible native_to_big(EndianReversible x) noexcept; +``` +[horizontal] +Returns:: `conditional_reverse(x)`. + +``` +template +EndianReversible little_to_native(EndianReversible x) noexcept; +``` +[horizontal] +Returns:: `conditional_reverse(x)`. + +``` +template +EndianReversible native_to_little(EndianReversible x) noexcept; +``` +[horizontal] +Returns:: `conditional_reverse(x)`. + +``` +template +EndianReversible conditional_reverse(EndianReversible x) noexcept; +``` +[horizontal] +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; +``` +[horizontal] +Returns:: `order1 == order2 ? x : endian_reverse(x)`. + +``` +template +void endian_reverse_inplace(EndianReversible& x) noexcept; +``` +[horizontal] +Effects:: `x` `= endian_reverse(x)`. + +``` +template +void big_to_native_inplace(EndianReversibleInplace& x) noexcept; +``` +[horizontal] +Effects:: `conditional_reverse_inplace(x)`. + +``` +template +void native_to_big_inplace(EndianReversibleInplace& x) noexcept; +``` +[horizontal] +Effects:: `conditional_reverse_inplace(x)`. + +``` +template +void little_to_native_inplace(EndianReversibleInplace& x) noexcept; +``` +[horizontal] +Effects:: `conditional_reverse_inplace(x)`. + +``` +template +void native_to_little_inplace(EndianReversibleInplace& x) noexcept; +``` +[horizontal] +Effects:: `conditional_reverse_inplace(x)`. + +``` +template +void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept; +``` +[horizontal] +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; +``` +[horizontal] +Effects:: If `order1 == order2` then `endian_reverse_inplace(x)`. + +## 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 are exact-length 8, 16, 32, and 64-bit integers supported rather than the +built-in char, short, int, long, long long, etc?* + +* The primary use case, portable file or network data, needs these de facto +standard sizes. Using types that vary with the platform would greatly limit +portability for both programs and data. + +*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.