| //// |
| Copyright 2011-2016 Beman Dawes |
| |
| Distributed under the Boost Software License, Version 1.0. |
| (http://www.boost.org/LICENSE_1_0.txt) |
| //// |
| |
| [#arithmetic] |
| # Endian Arithmetic Types |
| :idprefix: arithmetic_ |
| |
| ## Introduction |
| |
| Header `boost/endian/arithmetic.hpp` provides integer binary types with |
| control over byte order, value type, size, and alignment. Typedefs provide |
| easy-to-use names for common configurations. |
| |
| These types provide portable byte-holders for integer data, independent of |
| particular computer architectures. Use cases almost always involve I/O, either |
| via files or network connections. Although data portability is the primary |
| motivation, these 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 |
| http://en.wikipedia.org/wiki/Endian[Wikipedia] for a full exploration of |
| *endianness*, including definitions of *big endian* and *little endian*. |
| |
| Boost endian integers provide the same full set of {cpp} assignment, arithmetic, |
| and relational operators as {cpp} standard integral types, with the standard |
| semantics. |
| |
| Unary arithmetic operators are `+`, `-`, `~`, `!`, plus both prefix and postfix |
| `--` and `++`. Binary arithmetic operators are `+`, `+=`, `-`, `-=`, `\*`, |
| ``*=``, `/`, `/=`, `&`, `&=`, `|`, `|=`, `^`, `^=`, `<<`, `<\<=`, `>>`, and |
| `>>=`. Binary relational operators are `==`, `!=`, `<`, `\<=`, `>`, and `>=`. |
| |
| Implicit conversion to the underlying value type is provided. An implicit |
| constructor converting from the underlying value type is provided. |
| |
| ## 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/arithmetic.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_t file_code; |
| big_int32_t file_length; |
| little_int32_t version; |
| little_int32_t shape_type; |
| }; |
| |
| const char* filename = "test.dat"; |
| } |
| |
| int main(int, char* []) |
| { |
| header h; |
| |
| BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check |
| |
| 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 {cpp}03, `endian_arithmetic` 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 {cpp} |
| Standard does not guarantee memory layout for non-POD types. This has not been a |
| problem in practice since all known {cpp} compilers lay out memory as if |
| `endian` were a POD type. In {cpp}11, it is possible to specify the default |
| constructor as trivial, and private data members and base classes no longer |
| disqualify a type from being a POD type. Thus under {cpp}11, `endian_arithmetic` |
| will no longer be relying on unspecified behavior. |
| |
| ## Feature set |
| |
| * Big endian| little endian | native endian byte ordering. |
| * Signed | unsigned |
| * Unaligned | aligned |
| * 1-8 byte (unaligned) | 1, 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 n_bits, |
| align Align = align::no> |
| class endian_arithmetic; |
| ``` |
| |
| Typedefs, such as `big_int32_t`, provide convenient naming conventions for |
| common use cases: |
| |
| [%header,cols=5*] |
| |=== |
| |Name |Alignment |Endianness |Sign |Sizes in bits (n) |
| |`big_intN_t` |no |big |signed |8,16,24,32,40,48,56,64 |
| |`big_uintN_t` |no |big |unsigned |8,16,24,32,40,48,56,64 |
| |`little_intN_t` |no |little |signed |8,16,24,32,40,48,56,64 |
| |`little_uintN_t` |no |little |unsigned |8,16,24,32,40,48,56,64 |
| |`native_intN_t` |no |native |signed |8,16,24,32,40,48,56,64 |
| |`native_uintN_t` |no |native |unsigned |8,16,24,32,40,48,56,64 |
| |`big_intN_at` |yes |big |signed |8,16,32,64 |
| |`big_uintN_at` |yes |big |unsigned |8,16,32,64 |
| |`little_intN_at` |yes |little |signed |8,16,32,64 |
| |`little_uintN_at` |yes |little |unsigned |8,16,32,64 |
| |=== |
| |
| 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. |
| |
| CAUTION: 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 8, 16, 32, |
| and 64-bit integer types. |
| |
| TIP: Prefer unaligned arithmetic types. |
| |
| TIP: Protect yourself against alignment ills. For example: |
| [none] |
| {blank}:: |
| + |
| ``` |
| static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong"); |
| ``` |
| |
| NOTE: One-byte arithmetic types have identical layout on all platforms, so they |
| never actually reverse endianness. They are provided to enable generic code, |
| and to improve code readability and searchability. |
| |
| ## Class template `endian_arithmetic` |
| |
| `endian_arithmetic` is an integer byte-holder with user-specified endianness, |
| value type, size, and alignment. The usual operations on arithmetic types are |
| supplied. |
| |
| ### Synopsis |
| |
| ``` |
| #include <boost/endian/buffers.hpp> |
| |
| namespace boost |
| { |
| namespace endian |
| { |
| // C++11 features emulated if not available |
| |
| enum class align { no, yes }; |
| |
| template <order Order, class T, std::size_t n_bits, |
| align Align = align::no> |
| class endian_arithmetic |
| { |
| public: |
| |
| typedef T value_type; |
| |
| // if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 PODs are not |
| // available then these two constructors will not be present |
| endian_arithmetic() noexcept = default; |
| endian_arithmetic(T v) noexcept; |
| |
| endian_arithmetic& operator=(T v) noexcept; |
| operator value_type() const noexcept; |
| value_type value() const noexcept; |
| unsigned char* data() noexcept; |
| unsigned char const* data() const noexcept; |
| |
| // arithmetic operations |
| // note that additional operations are provided by the value_type |
| value_type operator+() const noexcept; |
| endian_arithmetic& operator+=(value_type y) noexcept; |
| endian_arithmetic& operator-=(value_type y) noexcept; |
| endian_arithmetic& operator*=(value_type y) noexcept; |
| endian_arithmetic& operator/=(value_type y) noexcept; |
| endian_arithmetic& operator%=(value_type y) noexcept; |
| endian_arithmetic& operator&=(value_type y) noexcept; |
| endian_arithmetic& operator|=(value_type y) noexcept; |
| endian_arithmetic& operator^=(value_type y) noexcept; |
| endian_arithmetic& operator<<=(value_type y) noexcept; |
| endian_arithmetic& operator>>=(value_type y) noexcept; |
| endian_arithmetic& operator++() noexcept; |
| endian_arithmetic& operator--() noexcept; |
| endian_arithmetic operator++(int) noexcept; |
| endian_arithmetic operator--(int) noexcept; |
| |
| // Stream inserter |
| template <class charT, class traits> |
| friend std::basic_ostream<charT, traits>& |
| operator<<(std::basic_ostream<charT, traits>& os, const endian_arithmetic& x); |
| |
| // Stream extractor |
| template <class charT, class traits> |
| friend std::basic_istream<charT, traits>& |
| operator>>(std::basic_istream<charT, traits>& is, endian_arithmetic& x); |
| }; |
| |
| // typedefs |
| |
| // unaligned big endian signed integer types |
| typedef endian_arithmetic<order::big, int_least8_t, 8> big_int8_t; |
| typedef endian_arithmetic<order::big, int_least16_t, 16> big_int16_t; |
| typedef endian_arithmetic<order::big, int_least32_t, 24> big_int24_t; |
| typedef endian_arithmetic<order::big, int_least32_t, 32> big_int32_t; |
| typedef endian_arithmetic<order::big, int_least64_t, 40> big_int40_t; |
| typedef endian_arithmetic<order::big, int_least64_t, 48> big_int48_t; |
| typedef endian_arithmetic<order::big, int_least64_t, 56> big_int56_t; |
| typedef endian_arithmetic<order::big, int_least64_t, 64> big_int64_t; |
| |
| // unaligned big endian unsigned integer types |
| typedef endian_arithmetic<order::big, uint_least8_t, 8> big_uint8_t; |
| typedef endian_arithmetic<order::big, uint_least16_t, 16> big_uint16_t; |
| typedef endian_arithmetic<order::big, uint_least32_t, 24> big_uint24_t; |
| typedef endian_arithmetic<order::big, uint_least32_t, 32> big_uint32_t; |
| typedef endian_arithmetic<order::big, uint_least64_t, 40> big_uint40_t; |
| typedef endian_arithmetic<order::big, uint_least64_t, 48> big_uint48_t; |
| typedef endian_arithmetic<order::big, uint_least64_t, 56> big_uint56_t; |
| typedef endian_arithmetic<order::big, uint_least64_t, 64> big_uint64_t; |
| |
| // unaligned big endian floating point types |
| typedef endian_arithmetic<order::big, float, 32> big_float32_t; |
| typedef endian_arithmetic<order::big, double, 64> big_float64_t; |
| |
| // unaligned little endian signed integer types |
| typedef endian_arithmetic<order::little, int_least8_t, 8> little_int8_t; |
| typedef endian_arithmetic<order::little, int_least16_t, 16> little_int16_t; |
| typedef endian_arithmetic<order::little, int_least32_t, 24> little_int24_t; |
| typedef endian_arithmetic<order::little, int_least32_t, 32> little_int32_t; |
| typedef endian_arithmetic<order::little, int_least64_t, 40> little_int40_t; |
| typedef endian_arithmetic<order::little, int_least64_t, 48> little_int48_t; |
| typedef endian_arithmetic<order::little, int_least64_t, 56> little_int56_t; |
| typedef endian_arithmetic<order::little, int_least64_t, 64> little_int64_t; |
| |
| // unaligned little endian unsigned integer types |
| typedef endian_arithmetic<order::little, uint_least8_t, 8> little_uint8_t; |
| typedef endian_arithmetic<order::little, uint_least16_t, 16> little_uint16_t; |
| typedef endian_arithmetic<order::little, uint_least32_t, 24> little_uint24_t; |
| typedef endian_arithmetic<order::little, uint_least32_t, 32> little_uint32_t; |
| typedef endian_arithmetic<order::little, uint_least64_t, 40> little_uint40_t; |
| typedef endian_arithmetic<order::little, uint_least64_t, 48> little_uint48_t; |
| typedef endian_arithmetic<order::little, uint_least64_t, 56> little_uint56_t; |
| typedef endian_arithmetic<order::little, uint_least64_t, 64> little_uint64_t; |
| |
| // unaligned little endian floating point types |
| typedef endian_arithmetic<order::little, float, 32> little_float32_t; |
| typedef endian_arithmetic<order::little, double, 64> little_float64_t; |
| |
| // unaligned native endian signed integer types |
| typedef endian_arithmetic<order::native, int_least8_t, 8> native_int8_t; |
| typedef endian_arithmetic<order::native, int_least16_t, 16> native_int16_t; |
| typedef endian_arithmetic<order::native, int_least32_t, 24> native_int24_t; |
| typedef endian_arithmetic<order::native, int_least32_t, 32> native_int32_t; |
| typedef endian_arithmetic<order::native, int_least64_t, 40> native_int40_t; |
| typedef endian_arithmetic<order::native, int_least64_t, 48> native_int48_t; |
| typedef endian_arithmetic<order::native, int_least64_t, 56> native_int56_t; |
| typedef endian_arithmetic<order::native, int_least64_t, 64> native_int64_t; |
| |
| // unaligned native endian unsigned integer types |
| typedef endian_arithmetic<order::native, uint_least8_t, 8> native_uint8_t; |
| typedef endian_arithmetic<order::native, uint_least16_t, 16> native_uint16_t; |
| typedef endian_arithmetic<order::native, uint_least32_t, 24> native_uint24_t; |
| typedef endian_arithmetic<order::native, uint_least32_t, 32> native_uint32_t; |
| typedef endian_arithmetic<order::native, uint_least64_t, 40> native_uint40_t; |
| typedef endian_arithmetic<order::native, uint_least64_t, 48> native_uint48_t; |
| typedef endian_arithmetic<order::native, uint_least64_t, 56> native_uint56_t; |
| typedef endian_arithmetic<order::native, uint_least64_t, 64> native_uint64_t; |
| |
| // unaligned native endian floating point types |
| typedef endian_arithmetic<order::native, float, 32> native_float32_t; |
| typedef endian_arithmetic<order::native, double, 64> native_float64_t; |
| |
| // aligned big endian signed integer types |
| typedef endian_arithmetic<order::big, int8_t, 8, align::yes> big_int8_at; |
| typedef endian_arithmetic<order::big, int16_t, 16, align::yes> big_int16_at; |
| typedef endian_arithmetic<order::big, int32_t, 32, align::yes> big_int32_at; |
| typedef endian_arithmetic<order::big, int64_t, 64, align::yes> big_int64_at; |
| |
| // aligned big endian unsigned integer types |
| typedef endian_arithmetic<order::big, uint8_t, 8, align::yes> big_uint8_at; |
| typedef endian_arithmetic<order::big, uint16_t, 16, align::yes> big_uint16_at; |
| typedef endian_arithmetic<order::big, uint32_t, 32, align::yes> big_uint32_at; |
| typedef endian_arithmetic<order::big, uint64_t, 64, align::yes> big_uint64_at; |
| |
| // aligned big endian floating point types |
| typedef endian_arithmetic<order::big, float, 32, align::yes> big_float32_at; |
| typedef endian_arithmetic<order::big, double, 64, align::yes> big_float64_at; |
| |
| // aligned little endian signed integer types |
| typedef endian_arithmetic<order::little, int8_t, 8, align::yes> little_int8_at; |
| typedef endian_arithmetic<order::little, int16_t, 16, align::yes> little_int16_at; |
| typedef endian_arithmetic<order::little, int32_t, 32, align::yes> little_int32_at; |
| typedef endian_arithmetic<order::little, int64_t, 64, align::yes> little_int64_at; |
| |
| // aligned little endian unsigned integer types |
| typedef endian_arithmetic<order::little, uint8_t, 8, align::yes> little_uint8_at; |
| typedef endian_arithmetic<order::little, uint16_t, 16, align::yes> little_uint16_at; |
| typedef endian_arithmetic<order::little, uint32_t, 32, align::yes> little_uint32_at; |
| typedef endian_arithmetic<order::little, uint64_t, 64, align::yes> little_uint64_at; |
| |
| // aligned little endian floating point types |
| typedef endian_arithmetic<order::little, float, 32, align::yes> little_float32_at; |
| typedef endian_arithmetic<order::little, double, 64, align::yes> little_float64_at; |
| |
| // aligned native endian typedefs are not provided because |
| // <cstdint> types are superior for that use case |
| |
| } // namespace endian |
| } // namespace boost |
| ``` |
| |
| The only supported value of `CHAR_BIT` is 8. |
| |
| The valid values of `Nbits` are as follows: |
| |
| * When `sizeof(T)` is 1, `Nbits` shall be 8; |
| * When `sizeof(T)` is 2, `Nbits` shall be 16; |
| * When `sizeof(T)` is 4, `Nbits` shall be 24 or 32; |
| * When `sizeof(T)` is 8, `Nbits` shall be 40, 48, 56, or 64. |
| |
| Other values of `sizeof(T)` are not supported. |
| |
| When `Nbits` is equal to `sizeof(T)*8`, `T` must be a standard arithmetic type. |
| |
| When `Nbits` is less than `sizeof(T)*8`, `T` must be a standard integral type |
| ({cpp}std, [basic.fundamental]) that is not `bool`. |
| |
| ### Members |
| |
| ``` |
| endian_arithmetic() noexcept = default; // C++03: endian(){} |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: Constructs an uninitialized object. |
| |
| ``` |
| endian_arithmetic(T v) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: See `endian_buffer::endian_buffer(T)`. |
| |
| ``` |
| endian_arithmetic& operator=(T v) noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: See `endian_buffer::operator=(T)`. |
| Returns:: `*this`. |
| |
| ``` |
| value_type value() const noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: See `endian_buffer::value()`. |
| |
| ``` |
| unsigned char* data() noexcept; |
| ``` |
| ``` |
| unsigned char const* data() const noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: See `endian_buffer::data()`. |
| |
| ``` |
| operator T() const noexcept; |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: |
| `value()`. |
| |
| ### 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 endian_arithmetic& x); |
| |
| ``` |
| [none] |
| * {blank} |
| + |
| Returns:: `os << +x`. |
| [none] |
| |
| ### Stream extractor |
| |
| ``` |
| template <class charT, class traits> |
| friend std::basic_istream<charT, traits>& |
| operator>>(std::basic_istream<charT, traits>& is, endian_arithmetic& x); |
| ``` |
| [none] |
| * {blank} |
| + |
| Effects:: As if: |
| + |
| ``` |
| T i; |
| if (is >> i) |
| x = i; |
| ``` |
| Returns:: `is`. |
| |
| ## FAQ |
| |
| See the <<overview_faq,Overview 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 PODs?:: |
| Yes for {cpp}11. No for {cpp}03, although several |
| <<arithmetic_compilation,macros>> are available to force PODness in all cases. |
| |
| What are the implications of endian integer types not being PODs with {cpp}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, will 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 types |
| |
| * 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. |
| |
| ## Experience |
| |
| Classes with similar functionality have been independently developed by |
| several Boost programmers and used very successful in high-value, high-use |
| applications for many years. These independently developed endian libraries |
| often evolved from C libraries that were also widely used. Endian types have |
| proven widely useful across a wide range of computer architectures and |
| applications. |
| |
| ## Motivating use cases |
| |
| Neil Mayhew writes: "I can also provide a meaningful use-case for this |
| library: reading TrueType font files from disk and processing the contents. The |
| data format has fixed endianness (big) and has unaligned values in various |
| places. Using Boost.Endian simplifies and cleans the code wonderfully." |
| |
| ## {cpp}11 |
| |
| The availability of the {cpp}11 |
| http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted |
| Functions] feature is detected automatically, and will be used if present to |
| ensure that objects of `class endian_arithmetic` are trivial, and thus PODs. |
| |
| ## 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_arithmetic` to have no |
| constructors. The intended use is for compiling user code that must be portable |
| between compilers regardless of {cpp}11 |
| http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[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 {cpp}11 |
| http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted |
| Functions]. This is ensures that objects of `class endian_arithmetic` are PODs, |
| and so can be used in {cpp}03 unions. In {cpp}11, `class endian_arithmetic` |
| objects are PODs, even though they have constructors, so can always be used in |
| unions. |
| |
| ## Acknowledgements |
| |
| Original design developed by Darin Adler based on classes developed by Mark |
| Borgerding. Four original class templates combined into a single |
| `endian_arithmetic` class template by Beman Dawes, who put the library together, |
| provided documentation, added the typedefs, and also added the |
| `unrolled_byte_loops` sign partial specialization to correctly extend the sign |
| when cover integer size differs from endian representation size. |