diff --git a/types.html b/arithmetic.html similarity index 82% rename from types.html rename to arithmetic.html index 3fb31ef..be79f3c 100644 --- a/types.html +++ b/arithmetic.html @@ -5,25 +5,22 @@ -
+ |
-![]() |
-
- Endian Types
+![]() |
+ + + Endian Arithmetic Types |
Header boost/endian/types.hpp +
Header boost/endian/arithmetic.hpp provides integer and floating point binary types with control over byte order, value type, size, and alignment. Typedefs provide easy-to-use names for common configurations.
@@ -86,7 +87,8 @@ integer byte-holders may also be used to reduce memory use, file size, or network activity since they provide binary integer sizes not otherwise available.Such integer byte-holder types are traditionally called -endian types. See the Wikipedia for +endian types. See the +Wikipedia for a full exploration of endianness, including definitions of big endian and little endian.
@@ -101,7 +103,7 @@ arithmetic operators are+
, +=
, -
,
^
, ^=
, <<
, <<=
, >>
,
>>=
. Binary relational operators are ==
, !=
,
<
, <=
, >
, >=
.
-Automatic implicit conversion to the underlying value type is provided. An
+
Automatic implicit conversion to the underlying value type is provided. A
conversion constructor from the underlying value type is provided.
Example
The endian_example.cpp program writes a
@@ -109,17 +111,17 @@ binary file containing four byte big-endian and little-endian integers:
#include <iostream>
#include <cstdio>
-#include <boost/endian/types.hpp>
+#include <boost/endian/arithmetic.hpp>
#include <boost/static_assert.hpp>
using namespace boost::endian;
namespace
{
- // This is an extract from a very widely used GIS file format. Who knows
- // why a designer would mix big and little endians in the same file - but
- // this is a real-world format and users wishing to write low level code
- // manipulating these files have to deal with the mixed endianness.
+ // This is an extract from a very widely used GIS file format. It seems odd
+ // to mix big and little endians in the same file - but this is a real-world
+ // format and users wishing to write low level code manipulating these files
+ // must deal with the mixed endianness.
struct header
{
@@ -144,10 +146,10 @@ int main(int, char* [])
h.shape_type = 0x01020304;
// Low-level I/O such as POSIX read/write or <cstdio> fread/fwrite is sometimes
- // used for binary file operations when ultimate efficiency is important.
- // Such I/O is often performed in some C++ wrapper class, but to drive home the
- // point that endian integers are often used in fairly low-level code that
- // does bulk I/O operations, <cstdio> fopen/fwrite is used for I/O in this example.
+ // used for binary file operations when ultimate efficiency is important. Such
+ // I/O is often performed in some C++ wrapper class, but to drive home the
+ // point that endian integers are often used in fairly low-level code that does
+ // bulk I/O operations, <cstdio> fopen/fwrite is used for I/O in this example.
std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
@@ -213,7 +215,7 @@ enum class align {no, yes};
One class template is provided:
template <order Order, typename T, std::size_t n_bits, align A = align::no>
- class endian;
+ class endian_arithmetic;
Typedefs, such as big_int32_t
, provide convenient naming
@@ -223,108 +225,122 @@ conventions for common use cases:
Name
Endianness
+ Alignment
Sign
Sizes in bits (n)
- Alignment
- big_align_int
n_t
+ big_int
n_t
big
+ yes
signed
16,32,64
- yes
- big_align_uint
n_t
+ big_uint
n_t
big
+ yes
unsigned
16,32,64
- yes
-
-
- big_align_float
n_t
- big
- signed
- 32,64
- yes
-
-
- little_align_int
n_t
- little
- signed
- 16,32,64
- yes
-
-
- little_align_uint
n_t
- little
- unsigned
- 16,32,64
- yes
-
-
- little_align_float
n_t
- little
- signed
- 32,64
- yes
-
-
- big_int
n_t
- big
- signed
- 8,16,24,32,40,48,56,64
- no
-
-
- big_uint
n_
t
- big
- unsigned
- 8,16,24,32,40,48,56,64
- no
big_float
n_t
big
+ yes
signed
32,64
- no
- little_int
n_
t
- little
+ big_int
n_ut
+ big
+ no
signed
8,16,24,32,40,48,56,64
- no
-
+
- little_uint
n_
t
- little
+ big_uint
n_ut
+ big
+ no
unsigned
8,16,24,32,40,48,56,64
+
+
+ big_float
n_ut
+ big
no
+ signed
+ 32,64
+
+
+ little_int
n_t
+ little
+ yes
+ signed
+ 16,32,64
+
+
+ little_uint
n_t
+ little
+ yes
+ unsigned
+ 16,32,64
little_float
n_t
little
+ yes
signed
32,64
- no
- native_int
n_
t
- native
+ little_int
n_ut
+ little
+ no
signed
8,16,24,32,40,48,56,64
- no
- native_uint
n_
t
- native
+ little_uint
n_ut
+ little
+ no
unsigned
8,16,24,32,40,48,56,64
- no
+
+ little_float
n_ut
+ little
+ no
+ signed
+ 32,64
+
+
+ native_float
n_t
+ native
+ yes
+ signed
+ 32,64
+
+
+ native_int
n_ut
+ native
+ no
+ signed
+ 8,16,24,32,40,48,56,64
+
+
+ native_uint
n_ut
+ native
+ no
+ unsigned
+ 8,16,24,32,40,48,56,64
+
+
+ native_float
n_ut
+ native
+ no
+ signed
+ 32,64
+
The unaligned types do not cause compilers to insert padding bytes in classes
@@ -339,7 +355,7 @@ are only available on architectures with 16, 32, and 64-bit integer types.
Note: One-byte types
have identical
functionality. They are provided to improve code readability and searchability.
-Class template endian
+Class template endian
_arithmetic
An endian is an integer byte-holder with user-specified
endianness, value type, size, and alignment. The
usual operations on integers are supplied.
@@ -359,20 +375,22 @@ usual operations on integers are supplied.
enum class align {no, yes};
- template <order Order, typename T, std::size_t n_bits, align A = align::no>
- class endian
+ template <order Order, class T, std::size_t n_bits, align A = align::no>
+ class endian_arithmetic
+ : public endian_buffer<Order, T, n_bits, A>
{
public:
- typedef T value_type;
+ typedef T value_type;
// if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 POD's are not
// available then these two constructors will not be present
- endian() noexcept = default;
- endian(T v) noexcept;
+ endian_arithmetic() noexcept = default;
+ endian_arithmetic(T v) noexcept;
- endian& operator=(T v) noexcept;
- operator T() const noexcept;
- const char* data() const noexcept;
+ endian_arithmetic& operator=(T v) noexcept;
+ operator value_type() const noexcept;
+ value_type value() const noexcept; // exposition only; see endian_buffer
+ const char* data() const noexcept; // exposition only; see endian_buffer
// arithmetic operations
// note that additional operations are provided by the value_type
@@ -393,15 +411,27 @@ usual operations on integers are supplied.
endian& operator--(endian& x) noexcept;
endian operator++(endian& x, int) noexcept;
endian operator--(endian& x, int) noexcept;
+
+ // Stream inserter
+ template <class charT, class traits>
+ friend std::basic_ostream<charT, traits>&
+ operator<<(std::basic_ostream<charT, traits>& os, const T& x);
+
+ // Stream extractor
+ template <class charT, class traits>
+ friend std::basic_istream<charT, traits>&
+ operator>>(std::basic_istream<charT, traits>& is, T& x);
};
+ // typedefs
+
// aligned big endian floating point types
- typedef endian<order::big, float, 32, align::yes> big_align_float32_t;
- typedef endian<order::big, double, 64, align::yes> big_align_float64_t;
+ typedef endian<order::big, float, 32, align::yes> big_float32_t;
+ typedef endian<order::big, double, 64, align::yes> big_float64_t;
// aligned little endian floating point types
- typedef endian<order::little, float, 32, align::yes> little_align_float32_t;
- typedef endian<order::little, double, 64, align::yes> little_align_float64_t;
+ typedef endian<order::little, float, 32, align::yes> little_float32_t;
+ typedef endian<order::little, double, 64, align::yes> little_float64_t;
// unaligned big endian floating point types
typedef endian<order::big, float, 32, align::no> big_float32un_t;
@@ -412,87 +442,87 @@ usual operations on integers are supplied.
typedef endian<order::little, double, 64, align::no> little_float64un_t;
// aligned big endian signed integer types
- typedef endian<order::big, int16_t, 16, align::yes> big_align_int16_t;
- typedef endian<order::big, int32_t, 32, align::yes> big_align_int32_t;
- typedef endian<order::big, int64_t, 64, align::yes> big_align_int64_t;
+ typedef endian<order::big, int16_t, 16, align::yes> big_int16_t;
+ typedef endian<order::big, int32_t, 32, align::yes> big_int32_t;
+ typedef endian<order::big, int64_t, 64, align::yes> big_int64_t;
// aligned big endian unsigned integer types
- typedef endian<order::big, uint16_t, 16, align::yes> big_align_uint16_t;
- typedef endian<order::big, uint32_t, 32, align::yes> big_align_uint32_t;
- typedef endian<order::big, uint64_t, 64, align::yes> big_align_uint64_t;
+ typedef endian<order::big, uint16_t, 16, align::yes> big_uint16_t;
+ typedef endian<order::big, uint32_t, 32, align::yes> big_uint32_t;
+ typedef endian<order::big, uint64_t, 64, align::yes> big_uint64_t;
// aligned little endian signed integer types
- typedef endian<order::little, int16_t, 16, align::yes> little_align_int16_t;
- typedef endian<order::little, int32_t, 32, align::yes> little_align_int32_t;
- typedef endian<order::little, int64_t, 64, align::yes> little_align_int64_t;
+ typedef endian<order::little, int16_t, 16, align::yes> little_int16_t;
+ typedef endian<order::little, int32_t, 32, align::yes> little_int32_t;
+ typedef endian<order::little, int64_t, 64, align::yes> little_int64_t;
// aligned little endian unsigned integer types
- typedef endian<order::little, uint16_t, 16, align::yes> little_align_uint16_t;
- typedef endian<order::little, uint32_t, 32, align::yes> little_align_uint32_t;
- typedef endian<order::little, uint64_t, 64, align::yes> little_align_uint64_t;
+ typedef endian<order::little, uint16_t, 16, align::yes> little_uint16_t;
+ typedef endian<order::little, uint32_t, 32, align::yes> little_uint32_t;
+ typedef endian<order::little, uint64_t, 64, align::yes> little_uint64_t;
// aligned native endian typedefs are not provided because
// <cstdint> types are superior for that use case
// unaligned big endian signed integer types
- typedef endian<order::big, int_least8_t, 8> big_int8_t;
- typedef endian<order::big, int_least16_t, 16> big_int16_t;
- typedef endian<order::big, int_least32_t, 24> big_int24_t;
- typedef endian<order::big, int_least32_t, 32> big_int32_t;
- typedef endian<order::big, int_least64_t, 40> big_int40_t;
- typedef endian<order::big, int_least64_t, 48> big_int48_t;
- typedef endian<order::big, int_least64_t, 56> big_int56_t;
- typedef endian<order::big, int_least64_t, 64> big_int64_t;
+ typedef endian<order::big, int_least8_t, 8> big_int8_ut;
+ typedef endian<order::big, int_least16_t, 16> big_int16_ut;
+ typedef endian<order::big, int_least32_t, 24> big_int24_ut;
+ typedef endian<order::big, int_least32_t, 32> big_int32_ut;
+ typedef endian<order::big, int_least64_t, 40> big_int40_ut;
+ typedef endian<order::big, int_least64_t, 48> big_int48_ut;
+ typedef endian<order::big, int_least64_t, 56> big_int56_ut;
+ typedef endian<order::big, int_least64_t, 64> big_int64_ut;
// unaligned big endian unsigned integer types
- typedef endian<order::big, uint_least8_t, 8> big_uint8_t;
- typedef endian<order::big, uint_least16_t, 16> big_uint16_t;
- typedef endian<order::big, uint_least32_t, 24> big_uint24_t;
- typedef endian<order::big, uint_least32_t, 32> big_uint32_t;
- typedef endian<order::big, uint_least64_t, 40> big_uint40_t;
- typedef endian<order::big, uint_least64_t, 48> big_uint48_t;
- typedef endian<order::big, uint_least64_t, 56> big_uint56_t;
- typedef endian<order::big, uint_least64_t, 64> big_uint64_t;
+ typedef endian<order::big, uint_least8_t, 8> big_uint8_ut;
+ typedef endian<order::big, uint_least16_t, 16> big_uint16_ut;
+ typedef endian<order::big, uint_least32_t, 24> big_uint24_ut;
+ typedef endian<order::big, uint_least32_t, 32> big_uint32_ut;
+ typedef endian<order::big, uint_least64_t, 40> big_uint40_ut;
+ typedef endian<order::big, uint_least64_t, 48> big_uint48_ut;
+ typedef endian<order::big, uint_least64_t, 56> big_uint56_ut;
+ typedef endian<order::big, uint_least64_t, 64> big_uint64_ut;
// unaligned little endian signed integer types
- typedef endian<order::little, int_least8_t, 8> little_int8_t;
- typedef endian<order::little, int_least16_t, 16> little_int16_t;
- typedef endian<order::little, int_least32_t, 24> little_int24_t;
- typedef endian<order::little, int_least32_t, 32> little_int32_t;
- typedef endian<order::little, int_least64_t, 40> little_int40_t;
- typedef endian<order::little, int_least64_t, 48> little_int48_t;
- typedef endian<order::little, int_least64_t, 56> little_int56_t;
- typedef endian<order::little, int_least64_t, 64> little_int64_t;
+ typedef endian<order::little, int_least8_t, 8> little_int8_ut;
+ typedef endian<order::little, int_least16_t, 16> little_int16_ut;
+ typedef endian<order::little, int_least32_t, 24> little_int24_ut;
+ typedef endian<order::little, int_least32_t, 32> little_int32_ut;
+ typedef endian<order::little, int_least64_t, 40> little_int40_ut;
+ typedef endian<order::little, int_least64_t, 48> little_int48_ut;
+ typedef endian<order::little, int_least64_t, 56> little_int56_ut;
+ typedef endian<order::little, int_least64_t, 64> little_int64_ut;
// unaligned little endian unsigned integer types
- typedef endian<order::little, uint_least8_t, 8> little_uint8_t;
- typedef endian<order::little, uint_least16_t, 16> little_uint16_t;
- typedef endian<order::little, uint_least32_t, 24> little_uint24_t;
- typedef endian<order::little, uint_least32_t, 32> little_uint32_t;
- typedef endian<order::little, uint_least64_t, 40> little_uint40_t;
- typedef endian<order::little, uint_least64_t, 48> little_uint48_t;
- typedef endian<order::little, uint_least64_t, 56> little_uint56_t;
- typedef endian<order::little, uint_least64_t, 64> little_uint64_t;
+ typedef endian<order::little, uint_least8_t, 8> little_uint8_ut;
+ typedef endian<order::little, uint_least16_t, 16> little_uint16_ut;
+ typedef endian<order::little, uint_least32_t, 24> little_uint24_ut;
+ typedef endian<order::little, uint_least32_t, 32> little_uint32_ut;
+ typedef endian<order::little, uint_least64_t, 40> little_uint40_ut;
+ typedef endian<order::little, uint_least64_t, 48> little_uint48_ut;
+ typedef endian<order::little, uint_least64_t, 56> little_uint56_ut;
+ typedef endian<order::little, uint_least64_t, 64> little_uint64_ut;
// unaligned native endian signed integer types
- typedef implementation-defined_int8_t native_int8_t;
- typedef implementation-defined_int16_t native_int16_t;
- typedef implementation-defined_int24_t native_int24_t;
- typedef implementation-defined_int32_t native_int32_t;
- typedef implementation-defined_int40_t native_int40_t;
- typedef implementation-defined_int48_t native_int48_t;
- typedef implementation-defined_int56_t native_int56_t;
- typedef implementation-defined_int64_t native_int64_t;
+ typedef implementation-defined_int8_t native_int8_ut;
+ typedef implementation-defined_int16_t native_int16_ut;
+ typedef implementation-defined_int24_t native_int24_ut;
+ typedef implementation-defined_int32_t native_int32_ut;
+ typedef implementation-defined_int40_t native_int40_ut;
+ typedef implementation-defined_int48_t native_int48_ut;
+ typedef implementation-defined_int56_t native_int56_ut;
+ typedef implementation-defined_int64_t native_int64_ut;
// unaligned native endian unsigned integer types
- typedef implementation-defined_uint8_t native_uint8_t;
- typedef implementation-defined_uint16_t native_uint16_t;
- typedef implementation-defined_uint24_t native_uint24_t;
- typedef implementation-defined_uint32_t native_uint32_t;
- typedef implementation-defined_uint40_t native_uint40_t;
- typedef implementation-defined_uint48_t native_uint48_t;
- typedef implementation-defined_uint56_t native_uint56_t;
- typedef implementation-defined_uint64_t native_uint64_t;
+ typedef implementation-defined_uint8_t native_uint8_ut;
+ typedef implementation-defined_uint16_t native_uint16_ut;
+ typedef implementation-defined_uint24_t native_uint24_ut;
+ typedef implementation-defined_uint32_t native_uint32_ut;
+ typedef implementation-defined_uint40_t native_uint40_ut;
+ typedef implementation-defined_uint48_t native_uint48_ut;
+ typedef implementation-defined_uint56_t native_uint56_ut;
+ typedef implementation-defined_uint64_t native_uint64_ut;
} // namespace endian
} // namespace boost
@@ -531,6 +561,29 @@ in *this
.
Other operators
Other operators on endian objects are forwarded to the equivalent
operator on value_type
.
+Stream inserter
+template <class charT, class traits>
+friend std::basic_ostream<charT, traits>&
+ operator<<(std::basic_ostream<charT, traits>& os, const T& x);
+
+
+Returns: os << +x
.
+
+Stream extractor
+template <class charT, class traits>
+friend std::basic_istream<charT, traits>&
+ operator>>(std::basic_istream<charT, traits>& is, T& x);
+
+
+Effects: As if:
+
+ T i;
+if (is >> i)
+ x = i;
+
+
+ Returns: is
.
+
FAQ
See the Endian home page FAQ for a library-wide
@@ -542,7 +595,7 @@ conversion or copying. They are already in the desired format for binary I/O.
Thus they can be read or written in bulk.
Are endian types POD's? Yes for C++11. No for C++03, although several
macros are available to force PODness in all cases.
-What are the implications endian integer types not being POD's with C++03
+
What are the implications of endian integer types not being POD's with C++03
compilers? They
can't be used in unions. Also, compilers aren't required to align or lay
out storage in portable ways, although this potential problem hasn't prevented
@@ -628,7 +681,7 @@ differs from endian representation size. Vicente Botet and other reviewers
suggested supporting floating point types.
Last revised:
-12 August, 2014
+05 December, 2014
© Copyright Beman Dawes, 2006-2009, 2013
Distributed under the Boost Software License, Version 1.0. See
www.boost.org/ LICENSE_1_0.txt
diff --git a/bikeshed.txt b/bikeshed.txt
new file mode 100644
index 0000000..67dbce1
--- /dev/null
+++ b/bikeshed.txt
@@ -0,0 +1,75 @@
+Conversion function naming bikeshed
+
+return-by-value modify-argument
+------------------ ---------------
+
+reverse_endianness reverse_endianness_in_place
+ " reverse_endianness_arg
+endian_reverse endian_reverse_in_place
+ " endian_reverse_inplace
+ " endian_reverse_replace
+ " endian_reverse_in_situ
+ " endian_reverse_here
+ " endian_reverse_this
+ " endian_reverse_self
+ " endian_reverse_arg
+ " endian_reverse_in
+
+reverse reverse_in_place
+reverse_endian reverse_endian_in_place
+
+swap_endianness swap_endianness_in_place
+swap_endian swap_endian_in_place
+endian_swap endian_swap_this
+
+flip_endianness flip_endianness_in_place
+flip_endian flip_endian_in_place
+endian_flip endian_flip_in_place
+
+
+reverse_order reverse_order_in_place
+
+
+Key points:
+
+* The above names are defined in a user namespace as customization points to be found by
+ ADL, and so cannot depend on the enclosing namespace name to signal readers that they
+ are related to endianness.
+* The above functions are rarely called directly by user code, which is more likely to use
+ the various conditional functions instead. So explicitness is more important than
+ brevity.
+
+Conditional names
+
+big_to_native native_to_big little_to_native native_to_little
+
+big_to_host host_to_big
+
+be_to_ne ne_to_be
+
+from_big, to_big
+
+big_to_native big_to_native
+native_to_big native_to_big
+
+conditional_reverse runtime_conditional_reverse
+conditional_reverse conditional_reverse <------
+
+merriam-webster.com/dictionary
+
+reverse [1] (adjective): opposite or contrary to a previous or normal condition
+reverse [2] (verb) : to change (something) to an opposite state or condition
+
+swap (verb) : to give something to someone and receive something in return : to trade or exchange (things)
+
+flip (verb)
+
+: to turn (something) over by throwing it up in the air with a quick movement
+
+: to cause (something) to turn or turn over quickly
+
+: to move (something) with a quick light movement
+
+
+
+
\ No newline at end of file
diff --git a/buffers.html b/buffers.html
new file mode 100644
index 0000000..6007965
--- /dev/null
+++ b/buffers.html
@@ -0,0 +1,627 @@
+
+
+
+
+
+
+
+Endian Buffer Types
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Endian Buffer Types
+
+
+
+
+
+
+ Boost Home
+ Endian Home
+ Conversion Functions
+ Arithmetic Types
+ Buffer Types
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+ Introduction
+ Example
+ Limitations
+ Feature set
+ Enums and typedefs
+ Class template endian_buffer
+
+ Synopsis
+ Members
+ FAQ
+ Design
+ C++11
+ Compilation
+
+
+
+ Headers
+
+
+
+
+ <boost/endian/conversion.hpp>
+ <boost/endian/buffers.hpp>
+ <boost/endian/arithmetic.hpp>
+
+
+Introduction
+The internal byte order of arithmetic types is traditionally called endianness. See the
+Wikipedia for
+a full
+exploration of endianness, including definitions of big
+endian and little endian.
+Header boost/endian/buffers.hpp
+provides endian_buffer
, a portable endian integer and floating-point binary buffer
+class template with control over
+byte order, value type, size, and alignment independent of the platform's native
+endianness. Typedefs provide easy-to-use names
+for common configurations.
+Use cases primarily involve data portability, either via files or network
+connections, but these byte-holders may
+also be used to reduce memory use, file size, or network activity since they
+
+provide binary numeric sizes not otherwise available.
+Class endian_buffer
is aimed at users who wish
+explicit control over when endianness conversions occur. It also serves as the
+base class for the endian_arithmetic
+class template, which is aimed at users who wish fully automatic endianness
+conversion and direct support for all normal arithmetic operations.
+Example
+The endian_example.cpp program writes a
+binary file containing four byte big-endian and little-endian integers:
+
+ #include <iostream>
+#include <cstdio>
+#include <boost/endian/buffers.hpp>
+#include <boost/static_assert.hpp>
+
+using namespace boost::endian;
+
+namespace
+{
+ // This is an extract from a very widely used GIS file format. Why the designer
+ // decided to mix big and little endians in the same file is not known. But
+ // this is a real-world format and users wishing to write low level code
+ // manipulating these files have to deal with the mixed endianness.
+
+ struct header
+ {
+ big_int32_buf_
t file_code;
+ big_int32_buf_
t file_length;
+ little_int32_buf_
t version;
+ little_int32_buf_
t shape_type;
+ };
+
+ const char* filename = "test.dat";
+}
+
+int main(int, char* [])
+{
+ BOOST_STATIC_ASSERT(sizeof(header) == 16U); // reality check
+
+ header h;
+
+ h.file_code = 0x01020304;
+ h.file_length = sizeof(header);
+ h.version = 1;
+ h.shape_type = 0x01020304;
+
+ // Low-level I/O such as POSIX read/write or <cstdio> fread/fwrite is sometimes
+ // used for binary file operations when ultimate efficiency is important. Such
+ // I/O is often performed in some C++ wrapper class, but to drive home the
+ // point that endian integers are often used in fairly low-level code that does
+ // bulk I/O operations, <cstdio> fopen/fwrite is used for I/O in this example.
+
+ std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
+
+ if (!fi)
+ {
+ std::cout << "could not open " << filename << '\n';
+ return 1;
+ }
+
+ if (std::fwrite(&h, sizeof(header), 1, fi)!= 1)
+ {
+ std::cout << "write failure for " << filename << '\n';
+ return 1;
+ }
+
+ std::fclose(fi);
+
+ std::cout << "created file " << filename << '\n';
+
+ return 0;
+}
+
+
+After compiling and executing endian_example.cpp,
+a hex dump of test.dat
shows:
+
+ 01020304 00000010 01000000 04030201
+
+Notice that the first two 32-bit integers are big endian while the second two
+are little endian, even though the machine this was compiled and run on was
+little endian.
+Limitations
+Requires <climits>
CHAR_BIT == 8
. If CHAR_BIT
+is some other value, compilation will result in an #error
. This
+restriction is in place because the design, implementation, testing, and
+documentation has only considered issues related to 8-bit bytes, and there have
+been no real-world use cases presented for other sizes.
+In C++03, endian_buffer
does not meet the requirements for POD types
+because it has constructors, private data members, and a base class. This means
+that common use cases are relying on unspecified behavior in that the C++
+Standard does not guarantee memory layout for non-POD types. This has not been a
+problem in practice since all known C++ compilers do layout memory as if
+endian
were a POD type. In C++11, it is possible to specify the
+default constructor as trivial, and private data members and base classes will
+no longer disqualify a type from being a POD. Thus under C++11, endian_buffer
+will no longer be relying on unspecified behavior.
+Feature set
+
+ - Big endian| little endian | native endian byte ordering.
+ - Signed | unsigned
+ - Unaligned | aligned
+ - Integer | floating point
+ - 1-8 byte (unaligned) | 2, 4, 8 byte (aligned)
+ - Choice of value type
+
+Enums and typedefs
+Two scoped enums are provided:
+
+ enum class order {big, little, native};
+
+enum class align {no, yes};
+
+One class template is provided:
+
+ template <order Order, typename T, std::size_t Nbits, align A = align::no>
+ class endian_buffer;
+
+
+Typedefs, such as big_int32_buf_t
, provide convenient naming
+conventions for common use cases:
+
+
+
+ Name
+ Endianness
+ Sign
+ Sizes in bits (n)
+ Alignment
+
+
+ big_int
n_buf_t
+ big
+ signed
+ 16,32,64
+ yes
+
+
+ big_uint
n_
buf_
t
+ big
+ unsigned
+ 16,32,64
+ yes
+
+
+ big_float
n_
buf_
t
+ big
+ signed
+ 32,64
+ yes
+
+
+ big_int
n_
buf_
ut
+ big
+ signed
+ 8,16,24,32,40,48,56,64
+ no
+
+
+ big_uint
n_
buf_
ut
+ big
+ unsigned
+ 8,16,24,32,40,48,56,64
+ no
+
+
+ big_float
n_
buf_
ut
+ big
+ signed
+ 32,64
+ no
+
+
+ little_int
n_
buf_
t
+ little
+ signed
+ 16,32,64
+ yes
+
+
+ little_uint
n_
buf_
t
+ little
+ unsigned
+ 16,32,64
+ yes
+
+
+ little_float
n_
buf_
t
+ little
+ signed
+ 32,64
+ yes
+
+
+ little_int
n_
buf_
ut
+ little
+ signed
+ 8,16,24,32,40,48,56,64
+ no
+
+
+ little_uint
n_
buf_
ut
+ little
+ unsigned
+ 8,16,24,32,40,48,56,64
+ no
+
+
+ little_float
n_
buf_
ut
+ little
+ signed
+ 32,64
+ no
+
+
+ native_float
n_
buf_
t
+ native
+ signed
+ 32,64
+ yes
+
+
+ native_int
n_
buf_
ut
+ native
+ signed
+ 8,16,24,32,40,48,56,64
+ no
+
+
+ native_uint
n_
buf_
ut
+ native
+ unsigned
+ 8,16,24,32,40,48,56,64
+ no
+
+
+ native_float
n_
buf_
ut
+ native
+ signed
+ 32,64
+ no
+
+
+
+The unaligned types do not cause compilers to insert padding bytes in classes
+and structs. This is an important characteristic that can be exploited to minimize wasted space in
+memory, files, and network transmissions.
+Warning:
+Code that uses aligned types is possibly non-portable because alignment
+requirements vary between hardware architectures and because alignment may be
+affected by compiler switches or pragmas. For example, alignment of an 64-bit
+integer may be to a 32-bit boundary on a 32-bit machine. Furthermore, aligned types
+are only available on architectures with 16, 32, and 64-bit integer types.
+Note: One-byte types
+have identical
+functionality. They are provided to improve code readability and searchability.
+Class template endian
_buffer
+An endian_buffer
is an integer byte-holder with user-specified
+endianness, value type, size, and alignment. The
+usual operations on integers are supplied.
+Synopsis
+namespace boost
+{
+ namespace endian
+ {
+ // C++11 features emulated if not available
+
+ enum class order
+ {
+ big, // big-endian
+ little, // little-endian
+ native = implementation-defined // same as order::big or order::little
+ };
+
+ enum class align {no, yes};
+
+ template <order Order, class T, std::size_t Nbits, align Align = align::no>
+ class endian_buffer
+ {
+ public:
+ typedef T value_type;
+
+ endian_buffer() noexcept = default;
+ explicit endian_buffer(T v) noexcept;
+
+ endian_buffer& operator=(T v) noexcept;
+ value_type value() const noexcept;
+ const char* data() const noexcept;
+ protected:
+ implementaton-defined endian_value; // for exposition only
+ };
+
+ // typedefs
+
+ // aligned big endian floating point buffers
+ typedef endian_buffer<order::big, float, 32, align::yes> big_float32_buf_t;
+ typedef endian_buffer<order::big, double, 64, align::yes> big_float64_buf_t;
+
+ // aligned little endian floating point buffers
+ typedef endian_buffer<order::little, float, 32, align::yes> little_float32_buf_t;
+ typedef endian_buffer<order::little, double, 64, align::yes> little_float64_buf_t;
+
+ // unaligned big endian floating point buffers
+ typedef endian_buffer<order::big, float, 32, align::no> big_float32_buf_ut;
+ typedef endian_buffer<order::big, double, 64, align::no> big_float64_buf_ut;
+
+ // unaligned little endian floating point buffers
+ typedef endian_buffer<order::little, float, 32, align::no> little_float32_buf_ut;
+ typedef endian_buffer<order::little, double, 64, align::no> little_float64_buf_ut;
+
+ // aligned big endian signed integer buffers
+ typedef endian_buffer<order::big, int16_t, 16, align::yes> big_int16_buf_t;
+ typedef endian_buffer<order::big, int32_t, 32, align::yes> big_int32_buf_t;
+ typedef endian_buffer<order::big, int64_t, 64, align::yes> big_int64_buf_t;
+
+ // aligned big endian unsigned integer buffers
+ typedef endian_buffer<order::big, uint16_t, 16, align::yes> big_uint16_buf_t;
+ typedef endian_buffer<order::big, uint32_t, 32, align::yes> big_uint32_buf_t;
+ typedef endian_buffer<order::big, uint64_t, 64, align::yes> big_uint64_buf_t;
+
+ // aligned little endian signed integer buffers
+ typedef endian_buffer<order::little, int16_t, 16, align::yes> little_int16_buf_t;
+ typedef endian_buffer<order::little, int32_t, 32, align::yes> little_int32_buf_t;
+ typedef endian_buffer<order::little, int64_t, 64, align::yes> little_int64_buf_t;
+
+ // aligned little endian unsigned integer buffers
+ typedef endian_buffer<order::little, uint16_t, 16, align::yes> little_uint16_buf_t;
+ typedef endian_buffer<order::little, uint32_t, 32, align::yes> little_uint32_buf_t;
+ typedef endian_buffer<order::little, uint64_t, 64, align::yes> little_uint64_buf_t;
+
+ // aligned native endian typedefs are not provided because
+ // <cstdint> types are superior for this use case
+
+ // unaligned big endian signed integer buffers
+ typedef endian_buffer<order::big, int_least8_t, 8> big_int8_buf_ut;
+ typedef endian_buffer<order::big, int_least16_t, 16> big_int16_buf_ut;
+ typedef endian_buffer<order::big, int_least32_t, 24> big_int24_buf_ut;
+ typedef endian_buffer<order::big, int_least32_t, 32> big_int32_buf_ut;
+ typedef endian_buffer<order::big, int_least64_t, 40> big_int40_buf_ut;
+ typedef endian_buffer<order::big, int_least64_t, 48> big_int48_buf_ut;
+ typedef endian_buffer<order::big, int_least64_t, 56> big_int56_buf_ut;
+ typedef endian_buffer<order::big, int_least64_t, 64> big_int64_buf_ut;
+
+ // unaligned big endian unsigned integer buffers
+ typedef endian_buffer<order::big, uint_least8_t, 8> big_uint8_buf_ut;
+ typedef endian_buffer<order::big, uint_least16_t, 16> big_uint16_buf_ut;
+ typedef endian_buffer<order::big, uint_least32_t, 24> big_uint24_buf_ut;
+ typedef endian_buffer<order::big, uint_least32_t, 32> big_uint32_buf_ut;
+ typedef endian_buffer<order::big, uint_least64_t, 40> big_uint40_buf_ut;
+ typedef endian_buffer<order::big, uint_least64_t, 48> big_uint48_buf_ut;
+ typedef endian_buffer<order::big, uint_least64_t, 56> big_uint56_buf_ut;
+ typedef endian_buffer<order::big, uint_least64_t, 64> big_uint64_buf_ut;
+
+ // unaligned little endian signed integer buffers
+ typedef endian_buffer<order::little, int_least8_t, 8> little_int8_buf_ut;
+ typedef endian_buffer<order::little, int_least16_t, 16> little_int16_buf_ut;
+ typedef endian_buffer<order::little, int_least32_t, 24> little_int24_buf_ut;
+ typedef endian_buffer<order::little, int_least32_t, 32> little_int32_buf_ut;
+ typedef endian_buffer<order::little, int_least64_t, 40> little_int40_buf_ut;
+ typedef endian_buffer<order::little, int_least64_t, 48> little_int48_buf_ut;
+ typedef endian_buffer<order::little, int_least64_t, 56> little_int56_buf_ut;
+ typedef endian_buffer<order::little, int_least64_t, 64> little_int64_buf_ut;
+
+ // unaligned little endian unsigned integer buffers
+ typedef endian_buffer<order::little, uint_least8_t, 8> little_uint8_buf_ut;
+ typedef endian_buffer<order::little, uint_least16_t, 16> little_uint16_buf_ut;
+ typedef endian_buffer<order::little, uint_least32_t, 24> little_uint24_buf_ut;
+ typedef endian_buffer<order::little, uint_least32_t, 32> little_uint32_buf_ut;
+ typedef endian_buffer<order::little, uint_least64_t, 40> little_uint40_buf_ut;
+ typedef endian_buffer<order::little, uint_least64_t, 48> little_uint48_buf_ut;
+ typedef endian_buffer<order::little, uint_least64_t, 56> little_uint56_buf_ut;
+ typedef endian_buffer<order::little, uint_least64_t, 64> little_uint64_buf_ut;
+
+ // unaligned native endian signed integer types
+ typedef implementation-defined_int8_buf_ut native_int8_buf_ut;
+ typedef implementation-defined_int16_buf_ut native_int16_buf_ut;
+ typedef implementation-defined_int24_buf_ut native_int24_buf_ut;
+ typedef implementation-defined_int32_buf_ut native_int32_buf_ut;
+ typedef implementation-defined_int40_buf_ut native_int40_buf_ut;
+ typedef implementation-defined_int48_buf_ut native_int48_buf_ut;
+ typedef implementation-defined_int56_buf_ut native_int56_buf_ut;
+ typedef implementation-defined_int64_buf_ut native_int64_buf_ut;
+
+ // unaligned native endian unsigned integer types
+ typedef implementation-defined_uint8_buf_ut native_uint8_buf_ut;
+ typedef implementation-defined_uint16_buf_ut native_uint16_buf_ut;
+ typedef implementation-defined_uint24_buf_ut native_uint24_buf_ut;
+ typedef implementation-defined_uint32_buf_ut native_uint32_buf_ut;
+ typedef implementation-defined_uint40_buf_ut native_uint40_buf_ut;
+ typedef implementation-defined_uint48_buf_ut native_uint48_buf_ut;
+ typedef implementation-defined_uint56_buf_ut native_uint56_buf_ut;
+ typedef implementation-defined_uint64_buf_ut native_uint64_buf_ut;
+
+
+ } // namespace endian
+} // namespace boost
+The implementation-defined
text in typedefs above is either
+big
or little
according to the native endianness of the
+platform.
+The expository data member endian_value
stores the current value
+of an endian_value
object as a sequence of bytes ordered as
+specified by the Order
template parameter. The
+implementation-defined
type of endian_value
is a
+type such as char[Nbits/CHAR_BIT]
+or T
that meets the
+requirements imposed by the Nbits
and Align
template
+parameters. The CHAR_BIT
+macro is defined in <climits>
.
+The only value of CHAR_BIT
that
+is required to be supported is 8.
+Template parameter T
is
+required to be a standard integer type (C++std, 3.9.1) and
+sizeof(T)*CHAR_BIT
is required to be
+greater or equal to Nbits
.
+Members
+ endian_buffer() noexcept = default;
+
+Effects: Constructs an object of type endian_buffer<Order, T,
+Nbits, Align>
.
+
+explicit endian_buffer(T v) noexcept;
+
+Effects: Constructs an object of type endian_buffer<Order, T,
+Nbits, Align>
.
+Postcondition: value() == v & mask
, where mask
+is a constant of type value_type
with Nbits
low-order
+bits set to one.
+Remarks: If Align
is align::yes
then
+endianness conversion if required is performed by
+boost::endian::endian_reverse
.
+
+endian_buffer& operator=(T v) noexcept;
+
+ Postcondition: value() == v & mask
, where mask
+ is a constant of type value_type
with Nbits
+ low-order bits set to one..
+ Returns: *this
.
+Remarks: If Align
is align::yes
then
+endianness conversion if required is performed by
+boost::endian::endian_reverse
.
+
+value_type value() const noexcept;
+
+Returns: endian_value
, converted to value_type
+if necessary and having the endianness of the native platform.
+Remarks: If Align
is align::yes
then
+endianness conversion if required is performed by
+boost::endian::endian_reverse
.
+
+const char* data() const noexcept;
+
+Returns: A pointer to the first byte of endian_value
.
+
+FAQ
+
+See the Endian home page FAQ for a library-wide
+FAQ.
+
+Why not just use Boost.Serialization? Serialization involves a
+conversion for every object involved in I/O. Endian integers require no
+conversion or copying. They are already in the desired format for binary I/O.
+Thus they can be read or written in bulk.
+Are endian types POD's? Yes for C++11. No for C++03, although several
+macros are available to force PODness in all cases.
+What are the implications of endian integer types not being POD's with C++03
+compilers? They
+can't be used in unions. Also, compilers aren't required to align or lay
+out storage in portable ways, although this potential problem hasn't prevented
+use of Boost.Endian with
+real compilers.
+What good is native endianness? It provides alignment and
+size guarantees not available from the built-in types. It eases generic
+programming.
+Why bother with the aligned endian types? Aligned integer operations
+may be faster (as much as 10 to 20 times faster) if the endianness and alignment of
+the type matches the endianness and alignment requirements of the machine. The code,
+however, is
+likely to be somewhat less portable than with the unaligned types.
+Why provide the arithmetic operations? Providing a full set of operations reduces program
+clutter and makes code both easier to write and to read. Consider
+incrementing a variable in a record. It is very convenient to write:
+ ++record.foo;
+Rather than:
+ int temp(record.foo);
+ ++temp;
+ record.foo = temp;
+Design considerations for Boost.Endian buffers
+
+ - Must be suitable for I/O - in other words, must be memcpyable.
+ - Must provide exactly the size and internal byte ordering specified.
+ - Must work correctly when the internal integer representation has more bits
+ that the sum of the bits in the external byte representation. Sign extension
+ must work correctly when the internal integer representation type has more
+ bits than the sum of the bits in the external bytes. For example, using
+ a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
+ both positive and negative values.
+ - Must work correctly (including using the same defined external
+ representation) regardless of whether a compiler treats char as signed or
+ unsigned.
+ - Unaligned types must not cause compilers to insert padding bytes.
+ - The implementation should supply optimizations with great care. Experience has shown that optimizations of endian
+ integers often become pessimizations when changing
+ machines or compilers. Pessimizations can also happen when changing compiler switches,
+ compiler versions, or CPU models of the same architecture.
+
+C++11
+The availability of the C++11
+
+Defaulted Functions feature is detected automatically, and will be used if
+present to ensure that objects of class endian
are trivial, and
+thus POD's.
+Compilation
+Boost.Endian is implemented entirely within headers, with no need to link to
+any Boost object libraries.
+Several macros allow user control over features:
+
+ - BOOST_ENDIAN_NO_CTORS causes
class endian
to have no
+ constructors. The intended use is for compiling user code that must be
+ portable between compilers regardless of C++11
+
+ Defaulted Functions support. Use of constructors will always fail,
+
+ - BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if
+ the compiler does not support C++11
+
+ Defaulted Functions. This is ensures that , and so can be used in unions.
+ In C++11,
class endian
objects are POD's even though they have
+ constructors.
+
+
+Last revised:
+06 December, 2014
+© Copyright Beman Dawes, 2006-2009, 2013
+Distributed under the Boost Software License, Version 1.0. See
+www.boost.org/ LICENSE_1_0.txt
+
+
+
+
\ No newline at end of file
diff --git a/conversion.html b/conversion.html
index bd5bfc4..9e9e92f 100644
--- a/conversion.html
+++ b/conversion.html
@@ -5,13 +5,8 @@
-Boost Endian Conversion Functions
-
+Endian Conversion Functions
+
@@ -20,10 +15,10 @@
-
+
- Endian Conversion
- Functions
+
+ Endian Conversion Functions
@@ -32,7 +27,8 @@
Boost Home
Endian Home
Conversion Functions
- Endian Types
+ Arithmetic Types
+ Buffer Types
@@ -49,7 +45,10 @@
Reference
Synopsis
Requirements
- Functions
+ EndianReversible
+ Customization for
+ UDTs
+ Functions
FAQ
Acknowledgements
@@ -60,7 +59,8 @@
<boost/endian/conversion.hpp>
- <boost/endian/types.hpp>
+ <boost/endian/buffers.hpp>
+ <boost/endian/arithmetic.hpp>
@@ -68,7 +68,7 @@
Header boost/endian/conversion.hpp
provides byte order reversal and conversion functions that convert objects of
-the multi-byte built-in
+the built-in
integer types, and also types float
and double,
between native, big, or little endian byte
ordering. User defined types are also supported.
@@ -77,9 +77,12 @@ ordering. User defined types are also supported.
Functions are implemented inline
if appropriate. noexcept
is
elided for compilers that do not support it.
-Boost scoped enum emulation is used so that the library still works for compilers that do not support scoped enums.
+Boost scoped enum emulation is used so that the library still works for compilers that do not support scoped enums.
+
+
+Header <boost/endian/conversion.hpp>
Synopsis
#define BOOST_ENDIAN_INTRINSIC_MSG "message describing presence or absence of intrinsics"
@@ -90,255 +93,290 @@ namespace endian
{
enum class order
{
- big, // big-endian
- little, // little-endian
- native = implementation-defined // same as order::big or order::little
+ big, // big endian
+ little, // little endian
+ native = implementation-defined-as-big-or-little
};
- // reverse byte order (i.e. endianness)
- int8_t reverse_value(int8_t x) noexcept;
- int16_t reverse_value(int16_t x) noexcept;
- int32_t reverse_value(int32_t x) noexcept;
- int64_t reverse_value(int64_t x) noexcept;
- uint8_t reverse_value(uint8_t x) noexcept;
- uint16_t reverse_value(uint16_t x) noexcept;
- uint32_t reverse_value(uint32_t x) noexcept;
- uint64_t reverse_value(uint64_t x) noexcept;
- float reverse_value(float x) noexcept;
- double reverse_value(double x) noexcept;
+ 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;
+ float endian_reverse(float x) noexcept;
+ double endian_reverse(double x) noexcept;
- template <class Value>
- void reverse(Value& 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;
+
+ template <class EndianReversible>
+ void endian_reverse_inplace(EndianReversible& x) noexcept;
- // reverse byte order unless native endianness is big
- template <class ReversibleValue >
- ReversibleValue big_endian_value(ReversibleValue x) noexcept;
- template <class Reversible>
- void big_endian(Reversible& x) noexcept;
-
- // reverse byte order unless native endianness is little
- template <class ReversibleValue >
- ReversibleValue little_endian_value(ReversibleValue x) noexcept;
- template <class Reversible>
- void little_endian(Reversible& x) noexcept;
-
- // synonyms, based on names popularized by BSD (e.g. OS X, Linux) endian.h
- // "h" for "host" (i.e. native), "be" for "big endian",
- // "le" for "little endian", "m" for "modify" in place
- template <class T> T bswap(T x) noexcept {return reverse_value(x);}
- template <class T> T htobe(T host) noexcept {return big_endian_value(host);}
- template <class T> T htole(T host) noexcept {return little_endian_value(host);}
- template <class T> T betoh(T big) noexcept {return big_endian_value(big);}
- template <class T> T letoh(T little) noexcept {return little_endian_value(little);}
-
- template <class T> void bswapm(T& x) noexcept {reverse(x);}
- template <class T> void htobem(T& host) noexcept {big_endian(host);}
- template <class T> void htole(mT& host noexcept) {little_endian(host);}
- template <class T> void betohm(T& big) noexcept {big_endian(big);}
- template <class T> void letohm(T& little) noexcept {little_endian(little);}
-
- // generic byte order conversion
- template <order From, order To, class ReversibleValue>
- ReversibleValue convert_value(ReversibleValue from) noexcept;
- template <order From, order To, class Reversible>
- void convert(Reversible& x) noexcept;
-
- // runtime effective byte order determination
- order effective_order(order x) noexcept;
-
- // runtime byte-order conversion
- template <class ReversibleValue>
- ReversibleValue convert_value(ReversibleValue from,
- order from_order, order to_order) noexcept;
- template <class Reversible>
- void convert(Reversible& x,
- order from_order, order to_order) 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;
} // namespace endian
} // namespace boost
-The implementation-defined
text above is either
-big
or little
according to the endianness of the
-platform.
+The implementation is required to define the enum class order
+constant native
as
+big
on big endian platforms and little
on little
+endian platforms.
+Definitions
+The standard integral types (C++std 3.9.1) except bool
,
+and the floating point types float
and double
are
+collectively called the endian types.
Requirements
-The template definitions in this header refer to named
-requirements whose details are set out in this section. User defined types may
-be used in the function templates in this header only if they meet the
-function's template parameter requirements.
-ReversibleValue requirements
-ReversibleValue
is an object type to be
-supplied by a C++ program instantiating a template; x
is a value of
-type (possibly const
) ReversibleValue
.
+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 C++ program instantiating a template; x
+is a value of type (possibly const
) T
; mlx
is a
+modifiable lvalue of type T
.
- Expression
- Return type
- Requirement
+ EndianReversible
+ requirements (in addition to CopyConstructible
)
-
- reverse_value(x)
-
- ReversibleValue
-
- The returned value is the value of x
with the
- order of its constituent bytes reversed.
+ Expression
+ Return
+ type
+ Requirements
+
+
+ endian_reverse(x)
+ T
+ 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 an 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).
+
+
-Reversible requirements
-Reversible
is an object type to be
-supplied by a C++ program instantiating a template; x
is a
-modifiable lvalue of type Reversible
.
+
- Expression
- Post-condition
+ EndianReversibleInplace
+ requirements (in addition to CopyConstructible
)
-
- reverse(x)
-
- The order of the constituent bytes of x
are
- reversed.
+ Expression
+ Requirements
+
+
+ endian_reverse_inplace(mlx)
+ 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 an 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).
+
+
-See
-udt_conversion_example.cpp for an example of a UDT that can used in the
-big_endian
,
-little_endian
, and
-convert
function templates.
+
+ [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 improved efficiency. —end note]
+
+ Customization points for user-defined types (UDTs)
+
+ This subsection describes requirements on the Endian library's implementation.
+
+ The library's function templates requiring
+EndianReversible
are
+required to perform reversal of endianness if needed by making an unqualified
+call to endian_reverse()
.
+
+ The library's function templates requiring
+EndianReversibleInplace
are required to perform reversal of endianness if needed by making an
+unqualified call to endian_reverse_inplace()
.
+
+ See
+udt_conversion_example.cpp for an example user-defined type.
+
Functions
-int8_t reverse_value(int8_t x) noexcept;
-int16_t reverse_value(int16_t x) noexcept;
-int32_t reverse_value(int32_t x) noexcept;
-int64_t reverse_value(int64_t x) noexcept;
-uint8_t reverse_value(uint8_t x) noexcept;
-uint16_t reverse_value(uint16_t x) noexcept;
-uint32_t reverse_value(uint32_t x) noexcept;
-uint64_t reverse_value(uint64_t x) noexcept;
-float reverse_value(float x) noexcept;
-double reverse_value(double x) noexcept;
+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;
+float endian_reverse(float x) noexcept;
+double endian_reverse(double x) noexcept;
- Returns: x
, with the order of its
+
Returns: x
, with the order of its
constituent bytes reversed.
+ Remarks: Meet the EndianReversible
requirements.
+ [Note: The Boost.Endian library does not provide overloads for the C++ standard library
+ supplied types. —end note]
-template <class Value>
- void reverse(Value& x) noexcept;
+
+template <class EndianReversible>
+EndianReversible big_to_native(EndianReversible x) noexcept;
+
+
+ Returns: conditional_reverse<order::big,
+ order::native>(x)
.
+
+template <class EndianReversible>
+EndianReversible native_to_big(EndianReversible x) noexcept;
- Postconditions: The order of the constituent bytes of
- x
are reversed.
+ Returns: conditional_reverse<order::native, order::big>(x)
.
-template <class ReversibleValue >
- ReversibleValue big_endian_value(ReversibleValue x) noexcept;
-template <class Reversible>
- void big_endian(Reversible& x) noexcept;
+template <class EndianReversible>
+EndianReversible little_to_native(EndianReversible x) noexcept;
+
+ Returns: conditional_reverse<order::little, order::native>(x)
.
+
+template <class EndianReversible>
+EndianReversible native_to_little(EndianReversible x) noexcept;
+
+ Returns: conditional_reverse<order::native, order::little>(x)
.
+
+template <order O1, order O2, class EndianReversible>
+EndianReversible conditional_reverse(EndianReversible x) noexcept;
+
+ 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;
+
+ Returns: order1 == order2 ? x : endian_reverse(x)
.
+
+
+template <class EndianReversible>
+void endian_reverse_inplace(EndianReversible& x) noexcept;
+
- Returns (first form): x
if the native byte order is big
- endian, otherwise reverse_value(x)
.
- Effects (second form): None if the native byte order is big
- endian, otherwise reverse(x)
.
- Example:
-
- int32_t x = some-value;
-big_endian(x); // reverses the byte order of x, unless
- // the native byte order is big-endian
-
-
-template <class ReversibleValue >
- ReversibleValue little_endian_value(ReversibleValue x) noexcept;
-template <class Reversible>
- void little_endian(Reversible& x) noexcept;
+ Effects: x
= endian_reverse(x)
.
+
+
+template <class EndianReversibleInplace>
+void big_to_native_inplace(EndianReversibleInplace& x) noexcept;
- Returns (first form): x
if the native byte order is little
- endian, otherwise reverse_value(x)
.
- Effects (second form): None if the native byte order is little
- endian, otherwise reverse(x)
.
- Example:
-
- int32_t x = some-value;
-int32_t y(little_endian(x));
-// y has been set to x; the byte order is reversed unless
-// the native byte order is little-endian.
-
-
-template <order From, order To, class ReversibleValue>
- ReversibleValue convert_value(ReversibleValue from) noexcept;
-template <order From, order To, class Reversible>
- void convert(Reversible& x) noexcept;
-
+
+ Effects: conditional_reverse_inplace<order::big,
+ order::native>(x)
.
+
+template <class EndianReversibleInplace>
+void native_to_big_inplace(EndianReversibleInplace& x) noexcept;
- The effective order of an order template parameter
- is the same as the order template parameter if the parameter is not
- order::native
, otherwise it is the constant order::big
or
- order::little
that represents the actual native byte order.
- Returns (first form): from
if From
- and To
have the same effective order, otherwise
- reverse_value(from)
.
- Effects (second form): None if From
and
- To
have the same effective order, otherwise reverse(x)
.
- Example:
-
- int32_t x;
-... read an external big-endian value into x
-convert<order::big, order::native>(x); // more generic equivalent of big_endian(x);
-
-
-order effective_order(order x) noexcept;
-
+
+ Effects: conditional_reverse_inplace<order::native,
+ order::big>(x)
.
+
+template <class EndianReversibleInplace>
+void little_to_native_inplace(EndianReversibleInplace& x) noexcept;
-Returns: x
if x != order::native
, otherwise the order
constant for the actual native byte order.
Example:
effective_order(order::big); // returns order::big
-effective_order(order::little); // returns order::little
-effective_order(order::native); // returns order::big if the native order
- // is big-endian, otherwise order::little
template <class ReversibleValue>
- ReversibleValue convert_value(ReversibleValue from,
- order from_order, order to_order) noexcept;
-template <class Reversible>
- void convert(Reversible& x,
- order from_order, order to_order) noexcept;
Returns (first form): from
if effect_order(from_order) == effective_order(to_order)
, otherwise reverse_value(from)
.
- Effects (second form): None if effect_order(from_order) == effective_order(to_order)
, otherwise reverse(x)
.
- Example:
-
- int32_t x;
-... read an external value of an endianness know only at runtime into x
-convert(x, some_order, order::native); // convert to native byte order if needed
-
-
+
+ Effects: conditional_reverse_inplace<order::little, order::native>(x)
.
+
+template <class EndianReversibleInplace>
+void native_to_little_inplace(EndianReversibleInplace& x) noexcept;
+
+
+ Effects: conditional_reverse_inplace<order::native,
+ order::little>(x)
.
+
+template <order O1, order O2, class EndianReversibleInplace>
+void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept;
+
+ 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;
+
+
+
+ Effects: If order1 == order2
then endian_reverse_inplace(x)
.
+
+
FAQ
See the Endian home page FAQ for a library-wide
FAQ.
-Why are the template versions of reverse()
and reverse_value()
-in a detail namespace?
-
-
-
-They are unsafe for general use. Consider reversing
-the bytes of a std::pair
as a whole - the bytes from first
-would end up in second
and visa versa, and this is totally
-wrong!
-
-
-
Why are both value returning and modify-in-place functions provided?
Returning the result by value is the standard C and C++ 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
+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.
+
+
+
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 floating point types and 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 reverse_value()
and templated
-reverse()
implementations.
+Pierre Talbot provided the int8_t endian_reverse()
and templated
+endian_reverse_inplace()
implementations.
Last revised:
-12 August, 2014
+16 December, 2014
© Copyright Beman Dawes, 2011, 2013
Distributed under the Boost Software License, Version 1.0. See www.boost.org/ LICENSE_1_0.txt
diff --git a/index.html b/index.html
index 6c6f3c4..4a25bd1 100644
--- a/index.html
+++ b/index.html
@@ -5,24 +5,20 @@
-Boost Endian Library
-
+Endian Library
+
-
+

-
- Endian Library
+
+
+ Endian Library
@@ -31,7 +27,8 @@
Boost Home
Endian Home
Conversion Functions
- Endian Types
+ Arithmetic Types
+ Buffer Types
@@ -61,24 +58,37 @@
<boost/endian/conversion.hpp>
- <boost/endian/types.hpp>
+ <boost/endian/buffers.hpp>
+ <boost/endian/arithmetic.hpp>
Abstract
-Boost.Endian provides facilities to manipulate the endianness of integers,
-floating point, and user defined data.
+Boost.Endian provides facilities to manipulate the
+endianness of integers,
+floating point numbers, and user-defined types.
- - The primary use case is binary I/O for portable data exchange with
- other systems, via either external media or network transmission.
+ - Primary use cases:
+
+ - Data portability. The Endian library supports binary data exchange, via either external media or network transmission,
+ regardless of platform endianness.
- - A second use case is minimizing storage size via sizes and/or
- alignments not supported by the built-in types.
+ - Program portability. POSIX-based and
+ Windows-based operating systems traditionally supply libraries with
+ non-portable functions to perform endian conversion. There are at least four
+ non-compatible sets of functions in common use. The Endian library is
+ portable across all C++ platforms.
- - Two distinct approaches to dealing with endianness are provided. Each approach has a
+
+
+
+ - Secondary use case: Minimizing storage size via sizes and/or alignments not supported by the
+ standard C++ arithmetic types.
+
+ - Three approaches to dealing with endianness are provided. Each approach has a
long history of successful use, and each approach has use cases where it is
- superior to the other approach.
+ preferred over the other approaches.
Introduction to endianness
@@ -116,102 +126,199 @@ at different ends.
See the Wikipedia's
Endianness article for an
extensive discussion of endianness.
-Most programmers can ignore endianness, except perhaps for reading a core
-dump on little-endian systems. Programmers have to deal with endianness in their
-code when exchanging binary integers and binary floating point
-values between computer systems with differing endianness, whether by physical file transfer or over a network,
-.
+Programmers can usually ignore endianness, except when reading a core
+dump on little-endian systems. But programmers have to deal with endianness when exchanging binary integers and binary floating point
+values between computer systems with differing endianness, whether by physical file transfer or over a network.
+And programmers may also want to use the library when minimizing either internal or
+external data sizes is advantageous.
Introduction to the Boost.Endian library
-The Boost.Endian library provides two different approaches to dealing with
-integer endianness. Both approaches support integers, floating point types
-except long double
, and user defined types (UDTs).
+The Boost.Endian library provides three different approaches to dealing with
+
+endianness. All three approaches support integers, floating point types
+except long double
, and user-define types (UDTs).
Each approach has a long history of successful use, and each approach has use
-cases where it is superior to the other approach.
+cases where it is preferred to the other approaches.
-Endian types - The application uses the provided endian types
-which mimic the
-built-in integer types. For example, big_int32_t
or little_float64_t
.
-Integer types with lengths of 1 through 8 bytes are supported, rather than just
-2, 4, and 8 byte integers. The types may be aligned or unaligned.
-
Endian conversion functions - The
-application uses the built-in integer and floating point types, and calls the
+application uses the built-in integer and floating point types to hold values, and calls the
provided conversion functions to convert byte ordering as needed. Both mutating
and non-mutating conversions are supplied, and each comes in unconditional and
conditional variants.
+Endian buffer types - The application uses the provided endian
+buffer types
+to hold values, and explicitly converts to and from the built-in integer and
+floating point types to perform arithmetic. Buffer lengths of 1 through 8 bytes
+are supported, rather than just 2, 4, and 8 bytes. The types may be aligned or
+unaligned.
+
+Endian arithmetic types - The application uses the provided endian
+arithmetic types, which supply the same operations as the built-in C++
+arithmetic types. All conversions are implicit. Arithmetic integer types with
+lengths of 1 through 8 bytes are supported, rather than just 2, 4, and 8 byte
+integers. The types may be aligned.
+
Boost Endian is a header-only library.
-Choosing between endian types and endian
-conversion functions
+Choosing between endian conversion functions, endian buffer types,
+and endian arithmetic types
-Which approach is better for dealing with endianness depends on
-application needs.
+The best approach to endianness depends on interaction between
+the approach characteristics and
+the application needs.
-
-
- Needs that favor one approach over the other
-
-
- Endian types may be better for
- these needs
- Endian conversion functions may be
- better for
- these needs
-
-
-
-
- A need to simplify program logic and eliminate logic
- errors. Since the endian types mimic the built-in types, there is no need to reason about the current endianness of variables
- and that can simplify program logic and eliminate logic errors.
- A need to use unusual integer sizes (i.e. 3, 5,
- 6, or 7 bytes) to reduce internal and external space usage and
- save I/O time.
- A need to use unaligned variables. Endian types can eliminate padding bytes in
- structures, reducing internal and external space usage and saving I/O
- time. They can deals with structures defined like this:
+
Approach characteristics
+
+The characteristics that differentiate the approaches are the endianness
+invariants, conversion explicitness, arithmetic operations, sizes available, and
+alignment requirements.
+
+Endianness invariants
+
+
+
+Endian conversion functions use objects of the ordinary C++ arithmetic
+types like int
or unsigned short
to hold values. That
+breaks the implicit invariant that the C++ language rules apply. The usual
+language rules only apply if the endianness of the object is currently set by
+the conversion functions to the native endianness for the platform. That can
+make it very hard to reason about complex logic flow, and result in difficult to
+find bugs.
+
+Endian buffer and arithmetic types hold values internally as arrays of
+characters with an invariant that the endianness of the array never changes.
+That makes these types easy to use and programs easy to maintain.
+
+
+
+Conversion explicitness
+
+
+
+Endian conversion functions and buffer types never perform
+implicit conversions. This gives users explicit control of when conversion
+occurs, and may help avoid unnecessary conversions.
+
+Endian arithmetic types perform conversion implicitly. That makes
+these types very easy to use, but can result in unnecessary conversions. Failure
+to hoist conversions out of inner loops can bring a performance penalty.
+
+
+
+Arithmetic operations
+
+
+
+Endian conversion functions do not supply arithmetic
+operations, but this is not a concern since this approach uses ordinary C++
+arithmetic types to hold values.
+
+Endian buffer types do not supply arithmetic operations. Although this
+approach avoids unnecessary conversions, it can result in the introduction of
+additional variables and confuse maintenance programmers.
+
+Endian arithmetic types do supply arithmetic operations. They
+are very easy to use if lots of arithmetic is involved.
+
+
+
+Sizes available
+
+
+
+Endianness conversion functions only support 1, 2, 4, and 8 byte
+integers. That's sufficient for many applications.
+
+Endian buffer and arithmetic types support 1, 2, 3, 4, 5, 6, 7, and 8
+byte integers. For an application where memory use or I/O speed is the limiting
+factor, using sizes tailored to application needs can be useful.
+
+
+
+Alignments available
+
+
+
+Endianness conversion functions only support aligned integer and
+floating-point types. That's sufficient for most applications.
+
+Endian buffer and arithmetic types support both aligned and unaligned
+integer and floating-point types. Unaligned types are rarely needed, but when
+needed they are often very useful and workarounds are painful. For example,
+
+
+ Non-portable code like this:
+ struct S {
+ uint16_t a; // big endian
+ uint32_t b; // big endian
+ } __attribute__ ((packed));
+
+ Can be replaced with portable code like this:
struct S {
- uint16_t a;
- uint32_t b;
- } __attribute__ ((packed));
-
- -
-
Programmer preference.
-
-
-
-
- A need to leverage knowledge of developers who have been using C byte
- swapping
- functions for years.
- - A need to save CPU time when a variable is used many times
- relative to its I/O.
- -
-
A need to pass structures to third-party libraries expecting a
- specific structure format.
- -
-
Programmer preference.
-
-
-
-
+ big_uint16_ut a;
+ big_uint32_ut b;
+ };
+
+
+
+
+
+An existing large codebase runs on little-endian Linux systems. It already +deals with endianness via +Linux provided +functions. Because of a business merger, the codebase has to be quickly +modified for Windows and possibly other operating systems, while still +supporting Linux. The codebase is reliable and the programmers are all +well-aware of endian issues.
+ +These factors all argue for an endian conversion
+approach that just mechanically changes the calls to htobe32
,
+etc. to boost::endian::native_to_big
, etc. and replaces <endian.h>
+with <boost/endian/conversion.hpp>
.
A new, complex, multi-threaded application is to be developed that must run +on little endian machines, but do big endian network I/O. The developers believe +computational speed for endian variable is critical but have seen numerous bugs +result from inability to reason about endian conversion state. They are also +worried that future maintenance changes could inadvertently introduce a lot of +slow conversions if full-blown endian arithmetic types are used.
+ +The endian buffers approach is made-to-order for +this use case.
+ +A new, complex, multi-threaded application is to be developed that must run +on little endian machines, but do big endian network I/O. The developers believe +computational speed for endian variables is not critical but have seen +numerous bugs result from inability to reason about endian conversion state. +They are also concerned about ease-of-use both during development and long-term +maintenance.
+ +Removing concern about conversion speed and adding concern about ease-of-use +tips the balance strongly in favor the endian +arithmetic approach.
Recent compilers, including GCC, Clang, and Microsoft, supply built-in support for byte swapping -intrinsics. Such support is automatically detected and -used since it may in smaller and faster generated code, particularly for release +
Supply compilers, including GCC, Clang, and Visual C++, supply built-in support for byte swapping intrinsics. +The library uses these intrinsics when available since they may result in smaller and faster generated code, particularly for release builds.
Defining BOOST_ENDIAN_NO_INTRINSICS
will suppress use
-of the intrinsics. Please try defining it if you get compiler errors, such as
-header byteswap.h not being found.
byteswap.h
are not being found on your platform.
The macro BOOST_ENDIAN_INTRINSIC_MSG
is defined as
either "no byte swap intrinsics"
or a string describing the
particular set of intrinsics being used.
Now consider a slightly different problem:
@@ -278,8 +386,8 @@ studying the generated assembly code for GCC and Visual C++. result to a fileWith the Endian type approach, an implicit conversion from and then back to +
With the Endian arithmetic approach, on little endian platforms an implicit conversion from and then back to big endian is done inside the loop. With the Endian conversion function -approach, the conversions are explicit, so only need to be done once, before and -after the loop.
+approach, the user has ensured the conversions are done outside the loop, so the +code may run more quickly on little endian platforms.GNU C++ version 4.7.0 | |||||
Iterations: 1000000000, Intrinsics: __builtin_bswap16, etc. | |||||
Test Case | -Endian type |
-Endian conversion function |
+|||
GNU C++ version 4.7.0 | |||||
Iterations: 1000000000, Intrinsics: __builtin_bswap16, etc. | |||||
Test Case | +Endian arithmetic |
+Endian conversion function |
|||
16-bit aligned big endian | -1.37 s | -0.81 s | |||
16-bit aligned little endian | -0.83 s | -0.81 s | |||
16-bit unaligned big endian | -1.09 s | -0.83 s | |||
16-bit unaligned little endian | -1.09 s | -0.81 s | |||
32-bit aligned big endian | -0.98 s | -0.27 s | |||
32-bit aligned little endian | -0.28 s | -0.27 s | |||
32-bit unaligned big endian | -3.82 s | -0.27 s | |||
32-bit unaligned little endian | -3.82 s | -0.27 s | |||
64-bit aligned big endian | -1.65 s | -0.41 s | |||
64-bit aligned little endian | -0.41 s | -0.41 s | |||
64-bit unaligned big endian | -17.53 s | -0.41 s | |||
64-bit unaligned little endian | -17.52 s | -0.41 s | |||
16-bit aligned big endian | +1.37 s | +0.81 s | |||
16-bit aligned little endian | +0.83 s | +0.81 s | |||
16-bit unaligned big endian | +1.09 s | +0.83 s | |||
16-bit unaligned little endian | +1.09 s | +0.81 s | |||
32-bit aligned big endian | +0.98 s | +0.27 s | |||
32-bit aligned little endian | +0.28 s | +0.27 s | |||
32-bit unaligned big endian | +3.82 s | +0.27 s | |||
32-bit unaligned little endian | +3.82 s | +0.27 s | |||
64-bit aligned big endian | +1.65 s | +0.41 s | |||
64-bit aligned little endian | +0.41 s | +0.41 s | |||
64-bit unaligned big endian | +17.53 s | +0.41 s | |||
64-bit unaligned little endian | +17.52 s | +0.41 s | |||
Iterations: 1000000000, Intrinsics: no byte swap intrinsics | |||||
Test Case | -Endian type |
-Endian conversion function |
+|||
Iterations: 1000000000, Intrinsics: no byte swap intrinsics | |||||
Test Case | +Endian arithmetic |
+Endian conversion function |
|||
16-bit aligned big endian | -1.95 s | -0.81 s | |||
16-bit aligned little endian | -0.83 s | -0.81 s | |||
16-bit unaligned big endian | -1.19 s | -0.81 s | |||
16-bit unaligned little endian | -1.20 s | -0.81 s | |||
32-bit aligned big endian | -0.97 s | -0.28 s | |||
32-bit aligned little endian | -0.27 s | -0.28 s | |||
32-bit unaligned big endian | -4.10 s | -0.27 s | |||
32-bit unaligned little endian | -4.10 s | -0.27 s | |||
64-bit aligned big endian | -1.64 s | -0.42 s | |||
64-bit aligned little endian | -0.41 s | -0.41 s | |||
64-bit unaligned big endian | -17.52 s | -0.42 s | |||
64-bit unaligned little endian | -17.52 s | -0.41 s | |||
16-bit aligned big endian | +1.95 s | +0.81 s | |||
16-bit aligned little endian | +0.83 s | +0.81 s | |||
16-bit unaligned big endian | +1.19 s | +0.81 s | |||
16-bit unaligned little endian | +1.20 s | +0.81 s | |||
32-bit aligned big endian | +0.97 s | +0.28 s | |||
32-bit aligned little endian | +0.27 s | +0.28 s | |||
32-bit unaligned big endian | +4.10 s | +0.27 s | |||
32-bit unaligned little endian | +4.10 s | +0.27 s | |||
64-bit aligned big endian | +1.64 s | +0.42 s | |||
64-bit aligned little endian | +0.41 s | +0.41 s | |||
64-bit unaligned big endian | +17.52 s | +0.42 s | |||
64-bit unaligned little endian | +17.52 s | +0.41 s |
Comment: Note that the 32-bit aligned big endian +timings are the same with or without intrinsics turned on. Presumably the +optimizer is recognizing the byte swapping and applying the intrinsics itself.
-Microsoft Visual C++ version 11.0 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Iterations: 1000000000, Intrinsics: cstdlib _byteswap_ushort, etc. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Test Case | -Endian type |
-Endian conversion function |
+
Microsoft Visual C++ version 11.0 | |||||
Iterations: 1000000000, Intrinsics: cstdlib _byteswap_ushort, etc. | |||||
Test Case | +Endian type |
+Endian conversion function |
|||
16-bit aligned big endian | -0.83 s | -0.51 s | |||
16-bit aligned little endian | -0.51 s | -0.50 s | |||
16-bit unaligned big endian | -1.37 s | -0.51 s | |||
16-bit unaligned little endian | -1.37 s | -0.50 s | |||
32-bit aligned big endian | -0.81 s | -0.50 s | |||
32-bit aligned little endian | -0.51 s | -0.51 s | |||
32-bit unaligned big endian | -2.98 s | -0.53 s | |||
32-bit unaligned little endian | -3.00 s | -0.51 s | |||
64-bit aligned big endian | -1.33 s | -0.33 s | |||
64-bit aligned little endian | -0.34 s | -0.27 s | |||
64-bit unaligned big endian | -7.05 s | -0.33 s | |||
64-bit unaligned little endian | -7.11 s | -0.31 s | |||
16-bit aligned big endian | +0.83 s | +0.51 s | |||
16-bit aligned little endian | +0.51 s | +0.50 s | |||
16-bit unaligned big endian | +1.37 s | +0.51 s | |||
16-bit unaligned little endian | +1.37 s | +0.50 s | |||
32-bit aligned big endian | +0.81 s | +0.50 s | |||
32-bit aligned little endian | +0.51 s | +0.51 s | |||
32-bit unaligned big endian | +2.98 s | +0.53 s | |||
32-bit unaligned little endian | +3.00 s | +0.51 s | |||
64-bit aligned big endian | +1.33 s | +0.33 s | |||
64-bit aligned little endian | +0.34 s | +0.27 s | |||
64-bit unaligned big endian | +7.05 s | +0.33 s | |||
64-bit unaligned little endian | +7.11 s | +0.31 s | |||
Iterations: 1000000000, Intrinsics: no byte swap intrinsics | |||||
Test Case | -Endian type |
-Endian conversion function |
+|||
Iterations: 1000000000, Intrinsics: no byte swap intrinsics | |||||
Test Case | +Endian type |
+Endian conversion function |
|||
16-bit aligned big endian | -0.83 s | -0.51 s | |||
16-bit aligned little endian | -0.51 s | -0.51 s | |||
16-bit unaligned big endian | -1.36 s | -0.51 s | |||
16-bit unaligned little endian | -1.37 s | -0.51 s | |||
32-bit aligned big endian | -3.42 s | -0.50 s | |||
32-bit aligned little endian | -0.51 s | -0.51 s | |||
32-bit unaligned big endian | -2.93 s | -0.50 s | |||
32-bit unaligned little endian | -2.95 s | -0.50 s | |||
64-bit aligned big endian | -5.99 s | -0.33 s | |||
64-bit aligned little endian | -0.33 s | -0.33 s | |||
64-bit unaligned big endian | -7.02 s | -0.27 s | |||
64-bit unaligned little endian | -7.02 s | -0.27 s | |||
16-bit aligned big endian | +0.83 s | +0.51 s | |||
16-bit aligned little endian | +0.51 s | +0.51 s | |||
16-bit unaligned big endian | +1.36 s | +0.51 s | |||
16-bit unaligned little endian | +1.37 s | +0.51 s | |||
32-bit aligned big endian | +3.42 s | +0.50 s | |||
32-bit aligned little endian | +0.51 s | +0.51 s | |||
32-bit unaligned big endian | +2.93 s | +0.50 s | |||
32-bit unaligned little endian | +2.95 s | +0.50 s | |||
64-bit aligned big endian | +5.99 s | +0.33 s | |||
64-bit aligned little endian | +0.33 s | +0.33 s | |||
64-bit unaligned big endian | +7.02 s | +0.27 s | |||
64-bit unaligned little endian | +7.02 s | +0.27 s |
When program logic dictates many more conversions for the Endian integer +
When program logic dictates many more conversions for the Endian arithmetic approach than the Endian conversion function approach (example 2):
There may be a considerable performance difference. If machine endianness differs from the -desired endianness, the Endian type approach must do the byte reversal many +desired endianness, the Endian arithmetic approach must do the byte reversal many times while the Endian conversion approach only does the reversal once. But if the endianness is the same, there is no conversion with either approach and no conversion code is generated for typical release builds.
Whether or not compiler byte swap intrinsics are explicitly available has little -impact as tested. Byte swap intrinsics are not available on some older -compilers and on some machine architectures, such as pre-486 X86 CPUs.
+impact on GCC but a lot of impact on Visual C++, for the tested compiler +versions. Yet another example of why actual timing tests are needed to +determine if some coding technique has significant impact on performance.Unaligned types are much slower that aligned types, regardless of endianness considerations. Instead of single instruction register loads and @@ -565,9 +676,9 @@ memory space is a minor secondary use case.
Why bother with binary I/O? Why not just use C++ Standard Library stream inserters and extractors?
+-Data interchange formats often specify binary arithmetic data.
Binary arithmetic data is smaller and therefore I/O is faster and file sizes -are smaller. Transfer between systems is less expensive. Standard interchange -formats often specify binary arithmetic data.
+are smaller. Transfer between systems is less expensive.Furthermore, binary arithmetic data is of fixed size, and so fixed-size disk records are possible without padding, easing sorting and allowing direct access. Disadvantages, such as the inability to use text utilities on the resulting @@ -584,7 +695,7 @@ CPU's. The Wikipedia article gives more pros and cons.
Why is only big, little, and native endianness supported?
+Why are only big, little, and native endianness supported?
These are the only endian schemes that have any practical value today. PDP-11 and the other middle endian approaches are interesting historical curiosities @@ -595,10 +706,10 @@ but have no relevance to today's C++ developers.
-@@ -618,21 +729,28 @@ and 16, 32, and 64-bit aligned integers.The only supported types are four byte
float
and eight byte +The only supported types are four-byte
float
and eight-bytedouble
. Even after endianness has been accounted for, floating point values will not be portable between systems that use different floating -point formats. Systems where the integer endianness differs from floating point +point formats. Systems where integer endianness differs from floating point endianness are not supported.Release history
Changes since formal review
-
- Headers have been renamed to endian/types.hpp and endian/conversion.hpp. +
- +
+The endian types have been decomposed into endian buffer types + and endian arithmetic types, as requested. The arithmetic types derive from + the buffer types.
- +
-Headers have been renamed to
endian/arithmetic.hpp
and +endian/conversion.hpp
.endian/buffers.hpp
has been + added. Infrastructure file names were changed accordingly.- The endian types and endian conversion functions now support 32-bit (
float)
and +- +
+The endian buffer and arithmetic types and endian conversion functions now support 32-bit (
float)
and 64-bit(double)
floating point, as requested.- The endian types now have stream inserter and extractor templates, as + requested.
- Both the endian types and endian conversion functions now support UDTs, as requested.
- The endian type aliases have been renamed, - using a naming pattern that is consistent for both integer and floating point.
+ using a naming pattern that is consistent for both integer and floating point, .- The conversion functions have been much revised, refactored, and otherwise improved based on review comments.
- Functions have been renamed to clarify their functionality.
- Both return-by-value and modify-in-place interfaces are provided, as requested.
-- Synonyms for the BSD byte swapping function names popularized by OS X - and Linux are provided, so that that developers already used to these names - can continue to use them if they wish.
- In addition to the named-endianness functions, functions that perform compile-time (via template) and run-time (via function argument) dispatch are now provided, as requested.
@@ -646,10 +764,10 @@ and 16, 32, and 64-bit aligned integers.- -
order::native
is now a synonym fororder::big
ororder::little
according to the endianness of the platform, as requested. This reduces the number of template specializations required.reverse_value()
overloads forint8_t
and+
- -
endian_reverse()
overloads forint8_t
anduint8_t
have been added for improved generality. (Pierre Talbot)- Overloads of
+reverse()
have been replaced with a single- reverse()
template. (Pierre Talbot)- Overloads of
endian_reverse_inplace()
have been replaced with a single+ endian_reverse_inplace()
template. (Pierre Talbot)- C++11 features such as
noexcept
are now used, while still supporting C++03 compilers.- Headers have been reorganized to make them easier to read, @@ -670,13 +788,11 @@ Blechmann, Tim Moore, tymofey, Tomas Puverle, Vincente Botet, Yuval Ronen and Vitaly Budovski,.
Last revised: -12 August, 2014
+16 December, 2014© Copyright Beman Dawes, 2011, 2013
Distributed under the Boost Software License, Version 1.0. See www.boost.org/ LICENSE_1_0.txt
--