1////
2Copyright 2011-2016 Beman Dawes
3
4Distributed under the Boost Software License, Version 1.0.
5(http://www.boost.org/LICENSE_1_0.txt)
6////
7
8[#arithmetic]
9# Endian Arithmetic Types
10:idprefix: arithmetic_
11
12## Introduction
13
14Header `boost/endian/arithmetic.hpp` provides integer binary types with
15control over byte order, value type, size, and alignment. Typedefs provide
16easy-to-use names for common configurations.
17
18These types provide portable byte-holders for integer data, independent of
19particular computer architectures. Use cases almost always involve I/O, either
20via files or network connections. Although data portability is the primary
21motivation, these integer byte-holders may also be used to reduce memory use,
22file size, or network activity since they provide binary integer sizes not
23otherwise available.
24
25Such integer byte-holder types are traditionally called *endian* types. See the
26http://en.wikipedia.org/wiki/Endian[Wikipedia] for a full exploration of
27*endianness*, including definitions of *big endian* and *little endian*.
28
29Boost endian integers provide the same full set of {cpp} assignment, arithmetic,
30and relational operators as {cpp} standard integral types, with the standard
31semantics.
32
33Unary arithmetic operators are `+`, `-`,  `~`, `!`, plus both prefix and postfix
34`--` and `++`. Binary arithmetic operators are `+`, `+=`, `-`, `-=`, `\*`,
35``*=``, `/`, `/=`, `&`, `&=`, `|`, `|=`, `^`, `^=`, `<<`, `<\<=`, `>>`, and
36`>>=`. Binary relational operators are `==`, `!=`, `<`, `\<=`, `>`, and `>=`.
37
38Implicit conversion to the underlying value type is provided. An implicit
39constructor converting from the underlying value type is provided.
40
41## Example
42
43The `endian_example.cpp` program writes a binary file containing four-byte,
44big-endian and little-endian integers:
45
46```
47#include <iostream>
48#include <cstdio>
49#include <boost/endian/arithmetic.hpp>
50#include <boost/static_assert.hpp>
51
52using namespace boost::endian;
53
54namespace
55{
56  //  This is an extract from a very widely used GIS file format.
57  //  Why the designer decided to mix big and little endians in
58  //  the same file is not known. But this is a real-world format
59  //  and users wishing to write low level code manipulating these
60  //  files have to deal with the mixed endianness.
61
62  struct header
63  {
64    big_int32_t     file_code;
65    big_int32_t     file_length;
66    little_int32_t  version;
67    little_int32_t  shape_type;
68  };
69
70  const char* filename = "test.dat";
71}
72
73int main(int, char* [])
74{
75  header h;
76
77  BOOST_STATIC_ASSERT(sizeof(h) == 16U);  // reality check
78
79  h.file_code   = 0x01020304;
80  h.file_length = sizeof(header);
81  h.version     = 1;
82  h.shape_type  = 0x01020304;
83
84  //  Low-level I/O such as POSIX read/write or <cstdio>
85  //  fread/fwrite is sometimes used for binary file operations
86  //  when ultimate efficiency is important. Such I/O is often
87  //  performed in some C++ wrapper class, but to drive home the
88  //  point that endian integers are often used in fairly
89  //  low-level code that does bulk I/O operations, <cstdio>
90  //  fopen/fwrite is used for I/O in this example.
91
92  std::FILE* fi = std::fopen(filename, "wb");  // MUST BE BINARY
93
94  if (!fi)
95  {
96    std::cout << "could not open " << filename << '\n';
97    return 1;
98  }
99
100  if (std::fwrite(&h, sizeof(header), 1, fi) != 1)
101  {
102    std::cout << "write failure for " << filename << '\n';
103    return 1;
104  }
105
106  std::fclose(fi);
107
108  std::cout << "created file " << filename << '\n';
109
110  return 0;
111}
112```
113
114After compiling and executing `endian_example.cpp`, a hex dump of `test.dat`
115shows:
116
117```
11801020304 00000010 01000000 04030201
119```
120
121Notice that the first two 32-bit integers are big endian while the second two
122are little endian, even though the machine this was compiled and run on was
123little endian.
124
125## Limitations
126
127Requires `<climits>`, `CHAR_BIT == 8`. If `CHAR_BIT` is some other value,
128compilation will result in an `#error`. This restriction is in place because the
129design, implementation, testing, and documentation has only considered issues
130related to 8-bit bytes, and there have been no real-world use cases presented
131for other sizes.
132
133In {cpp}03, `endian_arithmetic` does not meet the requirements for POD types
134because it has constructors, private data members, and a base class. This means
135that common use cases are relying on unspecified behavior in that the {cpp}
136Standard does not guarantee memory layout for non-POD types. This has not been a
137problem in practice since all known {cpp} compilers  lay out memory as if
138`endian` were a POD type. In {cpp}11, it is possible to specify the default
139constructor as trivial, and private data members and base classes  no longer
140disqualify a type from being a POD type. Thus under {cpp}11, `endian_arithmetic`
141will no longer be relying on unspecified behavior.
142
143## Feature set
144
145* Big endian| little endian | native endian byte ordering.
146* Signed | unsigned
147* Unaligned | aligned
148* 1-8 byte (unaligned) | 1, 2, 4, 8 byte (aligned)
149* Choice of value type
150
151## Enums and typedefs
152
153Two scoped enums are provided:
154
155```
156enum class order { big, little, native };
157
158enum class align { no, yes };
159```
160
161One class template is provided:
162
163```
164template <order Order, typename T, std::size_t n_bits,
165  align Align = align::no>
166class endian_arithmetic;
167```
168
169Typedefs, such as `big_int32_t`, provide convenient naming conventions for
170common use cases:
171
172[%header,cols=5*]
173|===
174|Name              |Alignment  |Endianness  |Sign      |Sizes in bits (n)
175|`big_intN_t`      |no         |big         |signed    |8,16,24,32,40,48,56,64
176|`big_uintN_t`     |no         |big         |unsigned  |8,16,24,32,40,48,56,64
177|`little_intN_t`   |no         |little      |signed    |8,16,24,32,40,48,56,64
178|`little_uintN_t`  |no         |little      |unsigned  |8,16,24,32,40,48,56,64
179|`native_intN_t`   |no         |native      |signed    |8,16,24,32,40,48,56,64
180|`native_uintN_t`  |no         |native      |unsigned  |8,16,24,32,40,48,56,64
181|`big_intN_at`     |yes        |big         |signed    |8,16,32,64
182|`big_uintN_at`    |yes        |big         |unsigned  |8,16,32,64
183|`little_intN_at`  |yes        |little      |signed    |8,16,32,64
184|`little_uintN_at` |yes        |little      |unsigned  |8,16,32,64
185|===
186
187The unaligned types do not cause compilers to insert padding bytes in classes
188and structs. This is an important characteristic that can be exploited to
189minimize wasted space in memory, files, and network transmissions.
190
191CAUTION: Code that uses aligned types is possibly non-portable because
192alignment requirements vary between hardware architectures and because
193alignment may be affected by compiler switches or pragmas. For example,
194alignment of an 64-bit integer may be to a 32-bit boundary on a 32-bit machine.
195Furthermore, aligned types are only available on architectures with 8, 16, 32,
196and 64-bit integer types.
197
198TIP: Prefer unaligned arithmetic types.
199
200TIP: Protect yourself against alignment ills. For example:
201[none]
202{blank}::
203+
204```
205static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong");
206```
207
208NOTE: One-byte arithmetic types have identical layout on all platforms, so they
209never actually reverse endianness. They are provided to enable generic code,
210and to improve code readability and searchability.
211
212## Class template `endian_arithmetic`
213
214`endian_arithmetic` is an integer byte-holder with user-specified endianness,
215value type, size, and alignment. The usual operations on arithmetic types are
216supplied.
217
218### Synopsis
219
220```
221#include <boost/endian/buffers.hpp>
222
223namespace boost
224{
225  namespace endian
226  {
227    //  C++11 features emulated if not available
228
229    enum class align { no, yes };
230
231    template <order Order, class T, std::size_t n_bits,
232      align Align = align::no>
233    class endian_arithmetic
234    {
235    public:
236
237      typedef T value_type;
238
239      // if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 PODs are not
240      // available then these two constructors will not be present
241      endian_arithmetic() noexcept = default;
242      endian_arithmetic(T v) noexcept;
243
244      endian_arithmetic& operator=(T v) noexcept;
245      operator value_type() const noexcept;
246      value_type value() const noexcept;
247      unsigned char* data() noexcept;
248      unsigned char const* data() const noexcept;
249
250      // arithmetic operations
251      //   note that additional operations are provided by the value_type
252      value_type operator+() const noexcept;
253      endian_arithmetic& operator+=(value_type y) noexcept;
254      endian_arithmetic& operator-=(value_type y) noexcept;
255      endian_arithmetic& operator*=(value_type y) noexcept;
256      endian_arithmetic& operator/=(value_type y) noexcept;
257      endian_arithmetic& operator%=(value_type y) noexcept;
258      endian_arithmetic& operator&=(value_type y) noexcept;
259      endian_arithmetic& operator|=(value_type y) noexcept;
260      endian_arithmetic& operator^=(value_type y) noexcept;
261      endian_arithmetic& operator<<=(value_type y) noexcept;
262      endian_arithmetic& operator>>=(value_type y) noexcept;
263      endian_arithmetic& operator++() noexcept;
264      endian_arithmetic& operator--() noexcept;
265      endian_arithmetic operator++(int) noexcept;
266      endian_arithmetic operator--(int) noexcept;
267
268      // Stream inserter
269      template <class charT, class traits>
270      friend std::basic_ostream<charT, traits>&
271        operator<<(std::basic_ostream<charT, traits>& os, const endian_arithmetic& x);
272
273      // Stream extractor
274      template <class charT, class traits>
275      friend std::basic_istream<charT, traits>&
276        operator>>(std::basic_istream<charT, traits>& is, endian_arithmetic& x);
277    };
278
279    // typedefs
280
281    // unaligned big endian signed integer types
282    typedef endian_arithmetic<order::big, int_least8_t, 8>        big_int8_t;
283    typedef endian_arithmetic<order::big, int_least16_t, 16>      big_int16_t;
284    typedef endian_arithmetic<order::big, int_least32_t, 24>      big_int24_t;
285    typedef endian_arithmetic<order::big, int_least32_t, 32>      big_int32_t;
286    typedef endian_arithmetic<order::big, int_least64_t, 40>      big_int40_t;
287    typedef endian_arithmetic<order::big, int_least64_t, 48>      big_int48_t;
288    typedef endian_arithmetic<order::big, int_least64_t, 56>      big_int56_t;
289    typedef endian_arithmetic<order::big, int_least64_t, 64>      big_int64_t;
290
291    // unaligned big endian unsigned integer types
292    typedef endian_arithmetic<order::big, uint_least8_t, 8>       big_uint8_t;
293    typedef endian_arithmetic<order::big, uint_least16_t, 16>     big_uint16_t;
294    typedef endian_arithmetic<order::big, uint_least32_t, 24>     big_uint24_t;
295    typedef endian_arithmetic<order::big, uint_least32_t, 32>     big_uint32_t;
296    typedef endian_arithmetic<order::big, uint_least64_t, 40>     big_uint40_t;
297    typedef endian_arithmetic<order::big, uint_least64_t, 48>     big_uint48_t;
298    typedef endian_arithmetic<order::big, uint_least64_t, 56>     big_uint56_t;
299    typedef endian_arithmetic<order::big, uint_least64_t, 64>     big_uint64_t;
300
301    // unaligned big endian floating point types
302    typedef endian_arithmetic<order::big, float, 32>              big_float32_t;
303    typedef endian_arithmetic<order::big, double, 64>             big_float64_t;
304
305    // unaligned little endian signed integer types
306    typedef endian_arithmetic<order::little, int_least8_t, 8>     little_int8_t;
307    typedef endian_arithmetic<order::little, int_least16_t, 16>   little_int16_t;
308    typedef endian_arithmetic<order::little, int_least32_t, 24>   little_int24_t;
309    typedef endian_arithmetic<order::little, int_least32_t, 32>   little_int32_t;
310    typedef endian_arithmetic<order::little, int_least64_t, 40>   little_int40_t;
311    typedef endian_arithmetic<order::little, int_least64_t, 48>   little_int48_t;
312    typedef endian_arithmetic<order::little, int_least64_t, 56>   little_int56_t;
313    typedef endian_arithmetic<order::little, int_least64_t, 64>   little_int64_t;
314
315    // unaligned little endian unsigned integer types
316    typedef endian_arithmetic<order::little, uint_least8_t, 8>    little_uint8_t;
317    typedef endian_arithmetic<order::little, uint_least16_t, 16>  little_uint16_t;
318    typedef endian_arithmetic<order::little, uint_least32_t, 24>  little_uint24_t;
319    typedef endian_arithmetic<order::little, uint_least32_t, 32>  little_uint32_t;
320    typedef endian_arithmetic<order::little, uint_least64_t, 40>  little_uint40_t;
321    typedef endian_arithmetic<order::little, uint_least64_t, 48>  little_uint48_t;
322    typedef endian_arithmetic<order::little, uint_least64_t, 56>  little_uint56_t;
323    typedef endian_arithmetic<order::little, uint_least64_t, 64>  little_uint64_t;
324
325    // unaligned little endian floating point types
326    typedef endian_arithmetic<order::little, float, 32>           little_float32_t;
327    typedef endian_arithmetic<order::little, double, 64>          little_float64_t;
328
329    // unaligned native endian signed integer types
330    typedef endian_arithmetic<order::native, int_least8_t, 8>     native_int8_t;
331    typedef endian_arithmetic<order::native, int_least16_t, 16>   native_int16_t;
332    typedef endian_arithmetic<order::native, int_least32_t, 24>   native_int24_t;
333    typedef endian_arithmetic<order::native, int_least32_t, 32>   native_int32_t;
334    typedef endian_arithmetic<order::native, int_least64_t, 40>   native_int40_t;
335    typedef endian_arithmetic<order::native, int_least64_t, 48>   native_int48_t;
336    typedef endian_arithmetic<order::native, int_least64_t, 56>   native_int56_t;
337    typedef endian_arithmetic<order::native, int_least64_t, 64>   native_int64_t;
338
339    // unaligned native endian unsigned integer types
340    typedef endian_arithmetic<order::native, uint_least8_t, 8>    native_uint8_t;
341    typedef endian_arithmetic<order::native, uint_least16_t, 16>  native_uint16_t;
342    typedef endian_arithmetic<order::native, uint_least32_t, 24>  native_uint24_t;
343    typedef endian_arithmetic<order::native, uint_least32_t, 32>  native_uint32_t;
344    typedef endian_arithmetic<order::native, uint_least64_t, 40>  native_uint40_t;
345    typedef endian_arithmetic<order::native, uint_least64_t, 48>  native_uint48_t;
346    typedef endian_arithmetic<order::native, uint_least64_t, 56>  native_uint56_t;
347    typedef endian_arithmetic<order::native, uint_least64_t, 64>  native_uint64_t;
348
349    // unaligned native endian floating point types
350    typedef endian_arithmetic<order::native, float, 32>           native_float32_t;
351    typedef endian_arithmetic<order::native, double, 64>          native_float64_t;
352
353    // aligned big endian signed integer types
354    typedef endian_arithmetic<order::big, int8_t, 8, align::yes>       big_int8_at;
355    typedef endian_arithmetic<order::big, int16_t, 16, align::yes>     big_int16_at;
356    typedef endian_arithmetic<order::big, int32_t, 32, align::yes>     big_int32_at;
357    typedef endian_arithmetic<order::big, int64_t, 64, align::yes>     big_int64_at;
358
359    // aligned big endian unsigned integer types
360    typedef endian_arithmetic<order::big, uint8_t, 8, align::yes>      big_uint8_at;
361    typedef endian_arithmetic<order::big, uint16_t, 16, align::yes>    big_uint16_at;
362    typedef endian_arithmetic<order::big, uint32_t, 32, align::yes>    big_uint32_at;
363    typedef endian_arithmetic<order::big, uint64_t, 64, align::yes>    big_uint64_at;
364
365    // aligned big endian floating point types
366    typedef endian_arithmetic<order::big, float, 32, align::yes>       big_float32_at;
367    typedef endian_arithmetic<order::big, double, 64, align::yes>      big_float64_at;
368
369    // aligned little endian signed integer types
370    typedef endian_arithmetic<order::little, int8_t, 8, align::yes>    little_int8_at;
371    typedef endian_arithmetic<order::little, int16_t, 16, align::yes>  little_int16_at;
372    typedef endian_arithmetic<order::little, int32_t, 32, align::yes>  little_int32_at;
373    typedef endian_arithmetic<order::little, int64_t, 64, align::yes>  little_int64_at;
374
375    // aligned little endian unsigned integer types
376    typedef endian_arithmetic<order::little, uint8_t, 8, align::yes>   little_uint8_at;
377    typedef endian_arithmetic<order::little, uint16_t, 16, align::yes> little_uint16_at;
378    typedef endian_arithmetic<order::little, uint32_t, 32, align::yes> little_uint32_at;
379    typedef endian_arithmetic<order::little, uint64_t, 64, align::yes> little_uint64_at;
380
381    // aligned little endian floating point types
382    typedef endian_arithmetic<order::little, float, 32, align::yes>    little_float32_at;
383    typedef endian_arithmetic<order::little, double, 64, align::yes>   little_float64_at;
384
385    // aligned native endian typedefs are not provided because
386    // <cstdint> types are superior for that use case
387
388  } // namespace endian
389} // namespace boost
390```
391
392The only supported value of `CHAR_BIT` is 8.
393
394The valid values of `Nbits` are as follows:
395
396* When `sizeof(T)` is 1, `Nbits` shall be 8;
397* When `sizeof(T)` is 2, `Nbits` shall be 16;
398* When `sizeof(T)` is 4, `Nbits` shall be 24 or 32;
399* When `sizeof(T)` is 8, `Nbits` shall be 40, 48, 56, or 64.
400
401Other values of `sizeof(T)` are not supported.
402
403When `Nbits` is equal to `sizeof(T)*8`, `T` must be a standard arithmetic type.
404
405When `Nbits` is less than `sizeof(T)*8`, `T` must be a standard integral type
406({cpp}std, [basic.fundamental]) that is not `bool`.
407
408### Members
409
410```
411endian_arithmetic() noexcept = default;  // C++03: endian(){}
412```
413[none]
414* {blank}
415+
416Effects:: Constructs an uninitialized object.
417
418```
419endian_arithmetic(T v) noexcept;
420```
421[none]
422* {blank}
423+
424Effects:: See `endian_buffer::endian_buffer(T)`.
425
426```
427endian_arithmetic& operator=(T v) noexcept;
428```
429[none]
430* {blank}
431+
432Effects:: See `endian_buffer::operator=(T)`.
433Returns:: `*this`.
434
435```
436value_type value() const noexcept;
437```
438[none]
439* {blank}
440+
441Returns:: See `endian_buffer::value()`.
442
443```
444unsigned char* data() noexcept;
445```
446```
447unsigned char const* data() const noexcept;
448```
449[none]
450* {blank}
451+
452Returns:: See `endian_buffer::data()`.
453
454```
455operator T() const noexcept;
456```
457[none]
458* {blank}
459+
460Returns::
461  `value()`.
462
463### Other operators
464
465Other operators on endian objects are forwarded to the equivalent operator on
466`value_type`.
467
468### Stream inserter
469
470```
471template <class charT, class traits>
472friend std::basic_ostream<charT, traits>&
473  operator<<(std::basic_ostream<charT, traits>& os, const endian_arithmetic& x);
474
475```
476[none]
477* {blank}
478+
479Returns:: `os << +x`.
480[none]
481
482### Stream extractor
483
484```
485template <class charT, class traits>
486friend std::basic_istream<charT, traits>&
487  operator>>(std::basic_istream<charT, traits>& is, endian_arithmetic& x);
488```
489[none]
490* {blank}
491+
492Effects:: As if:
493+
494```
495T i;
496if (is >> i)
497  x = i;
498```
499Returns:: `is`.
500
501## FAQ
502
503See the <<overview_faq,Overview FAQ>> for a library-wide FAQ.
504
505Why not just use Boost.Serialization?::
506Serialization involves a conversion for every object involved in I/O. Endian
507integers require no conversion or copying. They are already in the desired
508format for binary I/O. Thus they can be read or written in bulk.
509
510Are endian types PODs?::
511Yes for {cpp}11. No for {cpp}03, although several
512<<arithmetic_compilation,macros>> are available to force PODness in all cases.
513
514What are the implications of endian integer types not being PODs with {cpp}03 compilers?::
515They can't be used in unions. Also, compilers aren't required to align or lay
516out storage in portable ways, although this potential problem hasn't prevented
517use of Boost.Endian with real compilers.
518
519What good is native endianness?::
520It  provides alignment and size guarantees not available from the built-in
521types. It eases generic programming.
522
523Why bother with the aligned endian types?::
524Aligned integer operations may be faster (as much as 10 to 20 times faster)
525if the endianness and alignment of the type matches the endianness and
526alignment requirements of the machine. The code, however, will be somewhat less
527portable than with the unaligned types.
528
529Why provide the arithmetic operations?::
530Providing a full set of operations reduces program clutter and makes code
531both easier to write and to read. Consider incrementing a variable in a record.
532It is very convenient to write:
533+
534```
535++record.foo;
536```
537+
538Rather than:
539+
540```
541int temp(record.foo);
542++temp;
543record.foo = temp;
544```
545
546## Design considerations for Boost.Endian types
547
548* Must be suitable for I/O - in other words, must be memcpyable.
549* Must provide exactly the size and internal byte ordering specified.
550* Must work correctly when the internal integer representation has more bits
551that the sum of the bits in the external byte representation. Sign extension
552must work correctly when the internal integer representation type has more
553bits than the sum of the bits in the external bytes. For example, using
554a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
555both positive and negative values.
556* Must work correctly (including using the same defined external
557representation) regardless of whether a compiler treats char as signed or
558unsigned.
559* Unaligned types must not cause compilers to insert padding bytes.
560* The implementation should supply optimizations with great care. Experience
561has shown that optimizations of endian integers often become pessimizations
562when changing machines or compilers. Pessimizations can also happen when
563changing compiler switches, compiler versions, or CPU models of the same
564architecture.
565
566## Experience
567
568Classes with similar functionality have been independently developed by
569several Boost programmers and used very successful in high-value, high-use
570applications for many years. These independently developed endian libraries
571often evolved from C libraries that were also widely used. Endian types have
572proven widely useful across a wide range of computer architectures and
573applications.
574
575## Motivating use cases
576
577Neil Mayhew writes: "I can also provide a meaningful use-case for this
578library: reading TrueType font files from disk and processing the contents. The
579data format has fixed endianness (big) and has unaligned values in various
580places. Using Boost.Endian simplifies and cleans the code wonderfully."
581
582## {cpp}11
583
584The availability of the {cpp}11
585http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
586Functions] feature is detected automatically, and will be used if present to
587ensure that objects of `class endian_arithmetic` are trivial, and thus PODs.
588
589## Compilation
590
591Boost.Endian is implemented entirely within headers, with no need to link to any
592Boost object libraries.
593
594Several macros allow user control over features:
595
596* BOOST_ENDIAN_NO_CTORS causes `class endian_arithmetic` to have no
597constructors. The intended use is for compiling user code that must be portable
598between compilers regardless of {cpp}11
599http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
600Functions] support. Use of constructors will always fail,
601* BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if
602the compiler does not support {cpp}11
603http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
604Functions]. This is ensures that objects of `class endian_arithmetic` are PODs,
605and so can be used in {cpp}03 unions. In {cpp}11, `class endian_arithmetic`
606objects are PODs, even though they have constructors, so can always be used in
607unions.
608
609## Acknowledgements
610
611Original design developed by Darin Adler based on classes developed by Mark
612Borgerding. Four original class templates combined into a single
613`endian_arithmetic` class template by Beman Dawes, who put the library together,
614provided documentation,  added the typedefs, and also added the
615`unrolled_byte_loops` sign partial specialization to correctly extend the sign
616when cover integer size differs from endian representation size.
617