590 lines
20 KiB
Plaintext
590 lines
20 KiB
Plaintext
|
|
////
|
||
|
|
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.
|