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[#conversion]
9# Endian Conversion Functions
10:idprefix: conversion_
11
12## Introduction
13
14Header `boost/endian/conversion.hpp` provides byte order reversal and conversion
15functions that convert objects of the built-in integer types between native,
16big, or little endian byte ordering. User defined types are also supported.
17
18## Reference
19
20Functions are implemented `inline` if appropriate. For {cpp}03 compilers,
21`noexcept` is elided. Boost scoped enum emulation is used so that the library
22still works for compilers that do not support scoped enums.
23
24### Definitions
25
26*Endianness* refers to the ordering of bytes within internal or external
27integers and other arithmetic data. Most-significant byte first is called
28*big endian* ordering. Least-significant byte first is called
29*little endian* ordering. Other orderings are possible and some CPU
30architectures support both big and little ordering.
31
32NOTE: The names are derived from
33http://en.wikipedia.org/wiki/Jonathan_Swift[Jonathan Swift]'s satirical novel
34_http://en.wikipedia.org/wiki/Gulliver's_Travels[Gulliver's Travels]_, where
35rival kingdoms opened their soft-boiled eggs at different ends. Wikipedia has an
36extensive description of https://en.wikipedia.org/wiki/Endianness[Endianness].
37
38The standard integral types ({cpp}std 3.9.1) except `bool` are collectively
39called the *endian types*.
40
41### Header `<boost/endian/conversion.hpp>` Synopsis
42
43[subs=+quotes]
44```
45#define BOOST_ENDIAN_INTRINSIC_MSG \
46   "`message describing presence or absence of intrinsics`"
47
48namespace boost
49{
50namespace endian
51{
52  enum class order
53  {
54    native = `see below`,
55    big    = `see below`,
56    little = `see below`,
57  };
58
59  // Byte reversal functions
60
61  template <class Endian>
62    Endian endian_reverse(Endian x) noexcept;
63
64  template <class EndianReversible>
65    EndianReversible big_to_native(EndianReversible x) noexcept;
66  template <class EndianReversible>
67    EndianReversible native_to_big(EndianReversible x) noexcept;
68  template <class EndianReversible>
69    EndianReversible little_to_native(EndianReversible x) noexcept;
70  template <class EndianReversible>
71    EndianReversible native_to_little(EndianReversible x) noexcept;
72
73  template <order O1, order O2, class EndianReversible>
74    EndianReversible conditional_reverse(EndianReversible x) noexcept;
75  template <class EndianReversible>
76    EndianReversible conditional_reverse(EndianReversible x,
77      order order1, order order2) noexcept;
78
79  // In-place byte reversal functions
80
81  template <class EndianReversible>
82    void endian_reverse_inplace(EndianReversible& x) noexcept;
83
84  template <class EndianReversibleInplace>
85    void big_to_native_inplace(EndianReversibleInplace& x) noexcept;
86  template <class EndianReversibleInplace>
87    void native_to_big_inplace(EndianReversibleInplace& x) noexcept;
88  template <class EndianReversibleInplace>
89    void little_to_native_inplace(EndianReversibleInplace& x) noexcept;
90  template <class EndianReversibleInplace>
91    void native_to_little_inplace(EndianReversibleInplace& x) noexcept;
92
93  template <order O1, order O2, class EndianReversibleInplace>
94    void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept;
95  template <class EndianReversibleInplace>
96   void conditional_reverse_inplace(EndianReversibleInplace& x,
97     order order1, order order2) noexcept;
98
99  // Generic load and store functions
100
101  template<class T, std::size_t N, order Order>
102    T endian_load( unsigned char const * p ) noexcept;
103
104  template<class T, std::size_t N, order Order>
105    void endian_store( unsigned char * p, T const & v ) noexcept;
106
107  // Convenience load functions
108
109  boost::int16_t load_little_s16( unsigned char const * p ) noexcept;
110  boost::uint16_t load_little_u16( unsigned char const * p ) noexcept;
111  boost::int16_t load_big_s16( unsigned char const * p ) noexcept;
112  boost::uint16_t load_big_u16( unsigned char const * p ) noexcept;
113
114  boost::int32_t load_little_s24( unsigned char const * p ) noexcept;
115  boost::uint32_t load_little_u24( unsigned char const * p ) noexcept;
116  boost::int32_t load_big_s24( unsigned char const * p ) noexcept;
117  boost::uint32_t load_big_u24( unsigned char const * p ) noexcept;
118
119  boost::int32_t load_little_s32( unsigned char const * p ) noexcept;
120  boost::uint32_t load_little_u32( unsigned char const * p ) noexcept;
121  boost::int32_t load_big_s32( unsigned char const * p ) noexcept;
122  boost::uint32_t load_big_u32( unsigned char const * p ) noexcept;
123
124  boost::int64_t load_little_s40( unsigned char const * p ) noexcept;
125  boost::uint64_t load_little_u40( unsigned char const * p ) noexcept;
126  boost::int64_t load_big_s40( unsigned char const * p ) noexcept;
127  boost::uint64_t load_big_u40( unsigned char const * p ) noexcept;
128
129  boost::int64_t load_little_s48( unsigned char const * p ) noexcept;
130  boost::uint64_t load_little_u48( unsigned char const * p ) noexcept;
131  boost::int64_t load_big_s48( unsigned char const * p ) noexcept;
132  boost::uint64_t load_big_u48( unsigned char const * p ) noexcept;
133
134  boost::int64_t load_little_s56( unsigned char const * p ) noexcept;
135  boost::uint64_t load_little_u56( unsigned char const * p ) noexcept;
136  boost::int64_t load_big_s56( unsigned char const * p ) noexcept;
137  boost::uint64_t load_big_u56( unsigned char const * p ) noexcept;
138
139  boost::int64_t load_little_s64( unsigned char const * p ) noexcept;
140  boost::uint64_t load_little_u64( unsigned char const * p ) noexcept;
141  boost::int64_t load_big_s64( unsigned char const * p ) noexcept;
142  boost::uint64_t load_big_u64( unsigned char const * p ) noexcept;
143
144  // Convenience store functions
145
146  void store_little_s16( unsigned char * p, boost::int16_t v ) noexcept;
147  void store_little_u16( unsigned char * p, boost::uint16_t v ) noexcept;
148  void store_big_s16( unsigned char * p, boost::int16_t v ) noexcept;
149  void store_big_u16( unsigned char * p, boost::uint16_t v ) noexcept;
150
151  void store_little_s24( unsigned char * p, boost::int32_t v ) noexcept;
152  void store_little_u24( unsigned char * p, boost::uint32_t v ) noexcept;
153  void store_big_s24( unsigned char * p, boost::int32_t v ) noexcept;
154  void store_big_u24( unsigned char * p, boost::uint32_t v ) noexcept;
155
156  void store_little_s32( unsigned char * p, boost::int32_t v ) noexcept;
157  void store_little_u32( unsigned char * p, boost::uint32_t v ) noexcept;
158  void store_big_s32( unsigned char * p, boost::int32_t v ) noexcept;
159  void store_big_u32( unsigned char * p, boost::uint32_t v ) noexcept;
160
161  void store_little_s40( unsigned char * p, boost::int64_t v ) noexcept;
162  void store_little_u40( unsigned char * p, boost::uint64_t v ) noexcept;
163  void store_big_s40( unsigned char * p, boost::int64_t v ) noexcept;
164  void store_big_u40( unsigned char * p, boost::uint64_t v ) noexcept;
165
166  void store_little_s48( unsigned char * p, boost::int64_t v ) noexcept;
167  void store_little_u48( unsigned char * p, boost::uint64_t v ) noexcept;
168  void store_big_s48( unsigned char * p, boost::int64_t v ) noexcept;
169  void store_big_u48( unsigned char * p, boost::uint64_t v ) noexcept;
170
171  void store_little_s56( unsigned char * p, boost::int64_t v ) noexcept;
172  void store_little_u56( unsigned char * p, boost::uint64_t v ) noexcept;
173  void store_big_s56( unsigned char * p, boost::int64_t v ) noexcept;
174  void store_big_u56( unsigned char * p, boost::uint64_t v ) noexcept;
175
176  void store_little_s64( unsigned char * p, boost::int64_t v ) noexcept;
177  void store_little_u64( unsigned char * p, boost::uint64_t v ) noexcept;
178  void store_big_s64( unsigned char * p, boost::int64_t v ) noexcept;
179  void store_big_u64( unsigned char * p, boost::uint64_t v ) noexcept;
180
181} // namespace endian
182} // namespace boost
183```
184
185The values of `order::little` and `order::big` shall not be equal to one
186another.
187
188The value of `order::native` shall be:
189
190* equal to `order::big` if the execution environment is big endian, otherwise
191* equal to `order::little` if the execution environment is little endian,
192otherwise
193* unequal to both `order::little` and `order::big`.
194
195### Requirements
196
197#### Template argument requirements
198
199The template definitions in the `boost/endian/conversion.hpp` header refer to
200various named requirements whose details are set out in the tables in this
201subsection. In these tables, `T` is an object or reference type to be supplied
202by a {cpp} program instantiating a template; `x` is a value of type (possibly
203`const`) `T`; `mlx` is a modifiable lvalue of type `T`.
204
205[#conversion_endianreversible]
206##### EndianReversible requirements (in addition to `CopyConstructible`)
207
208[%header,cols=3*]
209|===
210|Expression |Return |Requirements
211|`endian_reverse(x)` |`T`
212a|`T` is an endian type or a class type.
213
214If `T` is an endian type, returns the value of `x` with the order of bytes
215reversed.
216
217If `T` is a class type, the function:
218
219* Returns the value of `x` with the order of bytes reversed for all data members
220of types or arrays of types that meet the `EndianReversible` requirements, and;
221* Is a non-member function in the same namespace as `T` that can be found by
222argument dependent lookup (ADL).
223|===
224
225[#conversion_endianreversibleinplace]
226##### EndianReversibleInplace requirements (in addition to `CopyConstructible`)
227
228[%header,cols=2*]
229|===
230|Expression |Requirements
231|`endian_reverse_inplace(mlx)`
232a|`T` is an endian type or a class type.
233
234If `T` is an endian type, reverses the order of bytes in `mlx`.
235
236If `T` is a class type, the function:
237
238* Reverses the order of bytes of all data members of `mlx` that have types or
239arrays of types that meet the `EndianReversible` or `EndianReversibleInplace`
240requirements, and;
241* Is a non-member function in the same namespace as `T` that can be found by
242argument dependent lookup (ADL).
243|===
244
245NOTE: Because there is a function template for `endian_reverse_inplace` that
246calls `endian_reverse`, only `endian_reverse` is required for a user-defined
247type to meet the `EndianReversibleInplace` requirements. Although User-defined
248types are not required to supply an `endian_reverse_inplace` function, doing so
249may improve efficiency.
250
251#### Customization points for user-defined types (UDTs)
252
253This subsection describes requirements on the Endian library's  implementation.
254
255The library's function templates requiring
256`<<conversion_endianreversible,EndianReversible>>` are required to perform
257reversal of endianness if needed by making an unqualified call to
258`endian_reverse()`.
259
260The library's function templates requiring
261`<<conversion_endianreversibleinplace,EndianReversibleInplace>>` are required to
262perform reversal of endianness if needed by making an unqualified call to
263`endian_reverse_inplace()`.
264
265See `example/udt_conversion_example.cpp` for an example user-defined type.
266
267### Byte Reversal Functions
268
269```
270template <class Endian>
271Endian endian_reverse(Endian x) noexcept;
272```
273[none]
274* {blank}
275+
276Requires:: `Endian` must be a standard integral type that is not `bool`.
277Returns:: `x`, with the order of its constituent bytes reversed.
278
279```
280template <class EndianReversible>
281EndianReversible big_to_native(EndianReversible x) noexcept;
282```
283[none]
284* {blank}
285+
286Returns:: `conditional_reverse<order::big, order::native>(x)`.
287
288```
289template <class EndianReversible>
290EndianReversible native_to_big(EndianReversible x) noexcept;
291```
292[none]
293* {blank}
294+
295Returns:: `conditional_reverse<order::native, order::big>(x)`.
296
297```
298template <class EndianReversible>
299EndianReversible little_to_native(EndianReversible x) noexcept;
300```
301[none]
302* {blank}
303+
304Returns:: `conditional_reverse<order::little, order::native>(x)`.
305
306```
307template <class EndianReversible>
308EndianReversible native_to_little(EndianReversible x) noexcept;
309```
310[none]
311* {blank}
312+
313Returns:: `conditional_reverse<order::native, order::little>(x)`.
314
315```
316template <order O1, order O2, class EndianReversible>
317EndianReversible conditional_reverse(EndianReversible x) noexcept;
318```
319[none]
320* {blank}
321+
322Returns:: `x` if `O1 == O2,` otherwise `endian_reverse(x)`.
323Remarks:: Whether `x` or `endian_reverse(x)` is to be returned shall be
324determined at compile time.
325
326```
327template <class EndianReversible>
328EndianReversible conditional_reverse(EndianReversible x,
329     order order1, order order2) noexcept;
330```
331[none]
332* {blank}
333+
334Returns::
335  `order1 == order2? x: endian_reverse(x)`.
336
337### In-place Byte Reversal Functions
338
339```
340template <class EndianReversible>
341void endian_reverse_inplace(EndianReversible& x) noexcept;
342```
343[none]
344* {blank}
345+
346Effects:: `x = endian_reverse(x)`.
347
348```
349template <class EndianReversibleInplace>
350void big_to_native_inplace(EndianReversibleInplace& x) noexcept;
351```
352[none]
353* {blank}
354+
355Effects:: `conditional_reverse_inplace<order::big, order::native>(x)`.
356
357```
358template <class EndianReversibleInplace>
359void native_to_big_inplace(EndianReversibleInplace& x) noexcept;
360```
361[none]
362* {blank}
363+
364Effects:: `conditional_reverse_inplace<order::native, order::big>(x)`.
365
366```
367template <class EndianReversibleInplace>
368void little_to_native_inplace(EndianReversibleInplace& x) noexcept;
369```
370[none]
371* {blank}
372+
373Effects:: `conditional_reverse_inplace<order::little, order::native>(x)`.
374
375```
376template <class EndianReversibleInplace>
377void native_to_little_inplace(EndianReversibleInplace& x) noexcept;
378```
379[none]
380* {blank}
381+
382Effects::  `conditional_reverse_inplace<order::native, order::little>(x)`.
383
384```
385template <order O1, order O2, class EndianReversibleInplace>
386void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept;
387```
388[none]
389* {blank}
390+
391Effects:: None if `O1 == O2,` otherwise `endian_reverse_inplace(x)`.
392Remarks:: Which effect applies shall be determined at compile time.
393
394```
395template <class EndianReversibleInplace>
396void conditional_reverse_inplace(EndianReversibleInplace& x,
397     order order1, order order2) noexcept;
398```
399[none]
400* {blank}
401+
402Effects::
403  If `order1 == order2` then `endian_reverse_inplace(x)`.
404
405### Generic Load and Store Functions
406
407```
408template<class T, std::size_t N, order Order>
409T endian_load( unsigned char const * p ) noexcept;
410```
411[none]
412* {blank}
413+
414Requires:: `sizeof(T)` must be 1, 2, 4, or 8. `N` must be between 1 and
415  `sizeof(T)`, inclusive. `T` must be trivially copyable. If `N` is not
416  equal to `sizeof(T)`, `T` must be integral or `enum`.
417
418Effects:: Reads `N` bytes starting from `p`, in forward or reverse order
419  depending on whether `Order` matches the native endianness or not,
420  interprets the resulting bit pattern as a value of type `T`, and returns it.
421  If `sizeof(T)` is bigger than `N`, zero-extends when `T` is unsigned,
422  sign-extends otherwise.
423
424```
425template<class T, std::size_t N, order Order>
426void endian_store( unsigned char * p, T const & v ) noexcept;
427```
428[none]
429* {blank}
430+
431Requires:: `sizeof(T)` must be 1, 2, 4, or 8. `N` must be between 1 and
432  `sizeof(T)`, inclusive. `T` must be trivially copyable. If `N` is not
433  equal to `sizeof(T)`, `T` must be integral or `enum`.
434
435Effects:: Writes to `p` the `N` least significant bytes from the object
436  representation of `v`, in forward or reverse order depending on whether
437  `Order` matches the native endianness or not.
438
439### Convenience Load Functions
440
441```
442inline boost::intM_t load_little_sN( unsigned char const * p ) noexcept;
443```
444[none]
445* {blank}
446+
447Reads an N-bit signed little-endian integer from `p`.
448+
449Returns:: `endian_load<boost::intM_t, N/8, order::little>( p )`.
450
451```
452inline boost::uintM_t load_little_uN( unsigned char const * p ) noexcept;
453```
454[none]
455* {blank}
456+
457Reads an N-bit unsigned little-endian integer from `p`.
458+
459Returns:: `endian_load<boost::uintM_t, N/8, order::little>( p )`.
460
461```
462inline boost::intM_t load_big_sN( unsigned char const * p ) noexcept;
463```
464[none]
465* {blank}
466+
467Reads an N-bit signed big-endian integer from `p`.
468+
469Returns:: `endian_load<boost::intM_t, N/8, order::big>( p )`.
470
471```
472inline boost::uintM_t load_big_uN( unsigned char const * p ) noexcept;
473```
474[none]
475* {blank}
476+
477Reads an N-bit unsigned big-endian integer from `p`.
478+
479Returns::
480  `endian_load<boost::uintM_t, N/8, order::big>( p )`.
481
482### Convenience Store Functions
483
484```
485inline void store_little_sN( unsigned char * p, boost::intM_t v ) noexcept;
486```
487[none]
488* {blank}
489+
490Writes an N-bit signed little-endian integer to `p`.
491+
492Effects:: `endian_store<boost::intM_t, N/8, order::little>( p, v )`.
493
494```
495inline void store_little_uN( unsigned char * p, boost::uintM_t v ) noexcept;
496```
497[none]
498* {blank}
499+
500Writes an N-bit unsigned little-endian integer to `p`.
501+
502Effects:: `endian_store<boost::uintM_t, N/8, order::little>( p, v )`.
503
504```
505inline void store_big_sN( unsigned char * p, boost::intM_t v ) noexcept;
506```
507[none]
508* {blank}
509+
510Writes an N-bit signed big-endian integer to `p`.
511+
512Effects:: `endian_store<boost::intM_t, N/8, order::big>( p, v )`.
513
514```
515inline void store_big_uN( unsigned char * p, boost::uintM_t v ) noexcept;
516```
517[none]
518* {blank}
519+
520Writes an N-bit unsigned big-endian integer to `p`.
521+
522Effects::
523  `endian_store<boost::uintM_t, N/8, order::big>( p, v )`.
524
525## FAQ
526
527See the <<overview_faq,Overview FAQ>> for a library-wide FAQ.
528
529*Why are both value returning and modify-in-place functions provided?*
530
531* Returning the result by value is the standard C and {cpp} idiom for functions
532that compute a value from an argument. Modify-in-place functions allow cleaner
533code in many real-world endian use cases and are more efficient for user-defined
534types that have members such as string data that do not need to be reversed.
535Thus both forms are provided.
536
537*Why not use the Linux names (htobe16, htole16, be16toh, le16toh, etc.) ?*
538
539* Those names are non-standard and vary even between POSIX-like operating
540systems. A {cpp} library TS was going to use those names, but found they were
541sometimes implemented as macros. Since macros do not respect scoping and
542namespace rules, to use them would be very error prone.
543
544## Acknowledgements
545
546Tomas Puverle was instrumental in identifying and articulating the need to
547support endian conversion as separate from endian integer types. Phil Endecott
548suggested the form of the value returning signatures. Vicente Botet and other
549reviewers suggested supporting  user defined types. General reverse template
550implementation approach using `std::reverse` suggested by Mathias Gaunard.
551Portable implementation approach for 16, 32, and 64-bit integers suggested by
552tymofey, with avoidance of undefined behavior as suggested by Giovanni Piero
553Deretta, and a further refinement suggested by Pyry Jahkola. Intrinsic builtins
554implementation approach for 16, 32, and 64-bit integers suggested by several
555reviewers, and by David Stone, who provided his Boost licensed macro
556implementation that became the starting point for
557`boost/endian/detail/intrinsic.hpp`.  Pierre Talbot provided the
558`int8_t endian_reverse()` and templated `endian_reverse_inplace()`
559implementations.
560