Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / endian / doc / endian / conversion.adoc
1 ////
2 Copyright 2011-2016 Beman Dawes
3
4 Distributed 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
14 Header `boost/endian/conversion.hpp` provides byte order reversal and conversion
15 functions that convert objects of the built-in integer types between native,
16 big, or little endian byte ordering. User defined types are also supported.
17
18 ## Reference
19
20 Functions are implemented `inline` if appropriate. For {cpp}03 compilers,
21 `noexcept` is elided. Boost scoped enum emulation is used so that the library
22 still 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
27 integers 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
30 architectures support both big and little ordering.
31
32 NOTE: The names are derived from
33 http://en.wikipedia.org/wiki/Jonathan_Swift[Jonathan Swift]'s satirical novel
34 _http://en.wikipedia.org/wiki/Gulliver's_Travels[Gulliver's Travels]_, where
35 rival kingdoms opened their soft-boiled eggs at different ends. Wikipedia has an
36 extensive description of https://en.wikipedia.org/wiki/Endianness[Endianness].
37
38 The standard integral types ({cpp}std 3.9.1) except `bool` are collectively
39 called 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
48 namespace boost
49 {
50 namespace 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
185 The values of `order::little` and `order::big` shall not be equal to one
186 another.
187
188 The 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,
192 otherwise
193 * unequal to both `order::little` and `order::big`.
194
195 ### Requirements
196
197 #### Template argument requirements
198
199 The template definitions in the `boost/endian/conversion.hpp` header refer to
200 various named requirements whose details are set out in the tables in this
201 subsection. In these tables, `T` is an object or reference type to be supplied
202 by 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`
212 a|`T` is an endian type or a class type.
213
214 If `T` is an endian type, returns the value of `x` with the order of bytes
215 reversed.
216
217 If `T` is a class type, the function:
218
219 * Returns the value of `x` with the order of bytes reversed for all data members
220 of 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
222 argument 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)`
232 a|`T` is an endian type or a class type.
233
234 If `T` is an endian type, reverses the order of bytes in `mlx`.
235
236 If `T` is a class type, the function:
237
238 * Reverses the order of bytes of all data members of `mlx` that have types or
239 arrays of types that meet the `EndianReversible` or `EndianReversibleInplace`
240 requirements, and;
241 * Is a non-member function in the same namespace as `T` that can be found by
242 argument dependent lookup (ADL).
243 |===
244
245 NOTE: Because there is a function template for `endian_reverse_inplace` that
246 calls `endian_reverse`, only `endian_reverse` is required for a user-defined
247 type to meet the `EndianReversibleInplace` requirements. Although User-defined
248 types are not required to supply an `endian_reverse_inplace` function, doing so
249 may improve efficiency.
250
251 #### Customization points for user-defined types (UDTs)
252
253 This subsection describes requirements on the Endian library's  implementation.
254
255 The library's function templates requiring
256 `<<conversion_endianreversible,EndianReversible>>` are required to perform
257 reversal of endianness if needed by making an unqualified call to
258 `endian_reverse()`.
259
260 The library's function templates requiring
261 `<<conversion_endianreversibleinplace,EndianReversibleInplace>>` are required to
262 perform reversal of endianness if needed by making an unqualified call to
263 `endian_reverse_inplace()`.
264
265 See `example/udt_conversion_example.cpp` for an example user-defined type.
266
267 ### Byte Reversal Functions
268
269 ```
270 template <class Endian>
271 Endian endian_reverse(Endian x) noexcept;
272 ```
273 [none]
274 * {blank}
275 +
276 Requires:: `Endian` must be a standard integral type that is not `bool`.
277 Returns:: `x`, with the order of its constituent bytes reversed.
278
279 ```
280 template <class EndianReversible>
281 EndianReversible big_to_native(EndianReversible x) noexcept;
282 ```
283 [none]
284 * {blank}
285 +
286 Returns:: `conditional_reverse<order::big, order::native>(x)`.
287
288 ```
289 template <class EndianReversible>
290 EndianReversible native_to_big(EndianReversible x) noexcept;
291 ```
292 [none]
293 * {blank}
294 +
295 Returns:: `conditional_reverse<order::native, order::big>(x)`.
296
297 ```
298 template <class EndianReversible>
299 EndianReversible little_to_native(EndianReversible x) noexcept;
300 ```
301 [none]
302 * {blank}
303 +
304 Returns:: `conditional_reverse<order::little, order::native>(x)`.
305
306 ```
307 template <class EndianReversible>
308 EndianReversible native_to_little(EndianReversible x) noexcept;
309 ```
310 [none]
311 * {blank}
312 +
313 Returns:: `conditional_reverse<order::native, order::little>(x)`.
314
315 ```
316 template <order O1, order O2, class EndianReversible>
317 EndianReversible conditional_reverse(EndianReversible x) noexcept;
318 ```
319 [none]
320 * {blank}
321 +
322 Returns:: `x` if `O1 == O2,` otherwise `endian_reverse(x)`.
323 Remarks:: Whether `x` or `endian_reverse(x)` is to be returned shall be
324 determined at compile time.
325
326 ```
327 template <class EndianReversible>
328 EndianReversible conditional_reverse(EndianReversible x,
329      order order1, order order2) noexcept;
330 ```
331 [none]
332 * {blank}
333 +
334 Returns::
335   `order1 == order2? x: endian_reverse(x)`.
336
337 ### In-place Byte Reversal Functions
338
339 ```
340 template <class EndianReversible>
341 void endian_reverse_inplace(EndianReversible& x) noexcept;
342 ```
343 [none]
344 * {blank}
345 +
346 Effects:: `x = endian_reverse(x)`.
347
348 ```
349 template <class EndianReversibleInplace>
350 void big_to_native_inplace(EndianReversibleInplace& x) noexcept;
351 ```
352 [none]
353 * {blank}
354 +
355 Effects:: `conditional_reverse_inplace<order::big, order::native>(x)`.
356
357 ```
358 template <class EndianReversibleInplace>
359 void native_to_big_inplace(EndianReversibleInplace& x) noexcept;
360 ```
361 [none]
362 * {blank}
363 +
364 Effects:: `conditional_reverse_inplace<order::native, order::big>(x)`.
365
366 ```
367 template <class EndianReversibleInplace>
368 void little_to_native_inplace(EndianReversibleInplace& x) noexcept;
369 ```
370 [none]
371 * {blank}
372 +
373 Effects:: `conditional_reverse_inplace<order::little, order::native>(x)`.
374
375 ```
376 template <class EndianReversibleInplace>
377 void native_to_little_inplace(EndianReversibleInplace& x) noexcept;
378 ```
379 [none]
380 * {blank}
381 +
382 Effects::  `conditional_reverse_inplace<order::native, order::little>(x)`.
383
384 ```
385 template <order O1, order O2, class EndianReversibleInplace>
386 void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept;
387 ```
388 [none]
389 * {blank}
390 +
391 Effects:: None if `O1 == O2,` otherwise `endian_reverse_inplace(x)`.
392 Remarks:: Which effect applies shall be determined at compile time.
393
394 ```
395 template <class EndianReversibleInplace>
396 void conditional_reverse_inplace(EndianReversibleInplace& x,
397      order order1, order order2) noexcept;
398 ```
399 [none]
400 * {blank}
401 +
402 Effects::
403   If `order1 == order2` then `endian_reverse_inplace(x)`.
404
405 ### Generic Load and Store Functions
406
407 ```
408 template<class T, std::size_t N, order Order>
409 T endian_load( unsigned char const * p ) noexcept;
410 ```
411 [none]
412 * {blank}
413 +
414 Requires:: `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
418 Effects:: 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 ```
425 template<class T, std::size_t N, order Order>
426 void endian_store( unsigned char * p, T const & v ) noexcept;
427 ```
428 [none]
429 * {blank}
430 +
431 Requires:: `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
435 Effects:: 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 ```
442 inline boost::intM_t load_little_sN( unsigned char const * p ) noexcept;
443 ```
444 [none]
445 * {blank}
446 +
447 Reads an N-bit signed little-endian integer from `p`.
448 +
449 Returns:: `endian_load<boost::intM_t, N/8, order::little>( p )`.
450
451 ```
452 inline boost::uintM_t load_little_uN( unsigned char const * p ) noexcept;
453 ```
454 [none]
455 * {blank}
456 +
457 Reads an N-bit unsigned little-endian integer from `p`.
458 +
459 Returns:: `endian_load<boost::uintM_t, N/8, order::little>( p )`.
460
461 ```
462 inline boost::intM_t load_big_sN( unsigned char const * p ) noexcept;
463 ```
464 [none]
465 * {blank}
466 +
467 Reads an N-bit signed big-endian integer from `p`.
468 +
469 Returns:: `endian_load<boost::intM_t, N/8, order::big>( p )`.
470
471 ```
472 inline boost::uintM_t load_big_uN( unsigned char const * p ) noexcept;
473 ```
474 [none]
475 * {blank}
476 +
477 Reads an N-bit unsigned big-endian integer from `p`.
478 +
479 Returns::
480   `endian_load<boost::uintM_t, N/8, order::big>( p )`.
481
482 ### Convenience Store Functions
483
484 ```
485 inline void store_little_sN( unsigned char * p, boost::intM_t v ) noexcept;
486 ```
487 [none]
488 * {blank}
489 +
490 Writes an N-bit signed little-endian integer to `p`.
491 +
492 Effects:: `endian_store<boost::intM_t, N/8, order::little>( p, v )`.
493
494 ```
495 inline void store_little_uN( unsigned char * p, boost::uintM_t v ) noexcept;
496 ```
497 [none]
498 * {blank}
499 +
500 Writes an N-bit unsigned little-endian integer to `p`.
501 +
502 Effects:: `endian_store<boost::uintM_t, N/8, order::little>( p, v )`.
503
504 ```
505 inline void store_big_sN( unsigned char * p, boost::intM_t v ) noexcept;
506 ```
507 [none]
508 * {blank}
509 +
510 Writes an N-bit signed big-endian integer to `p`.
511 +
512 Effects:: `endian_store<boost::intM_t, N/8, order::big>( p, v )`.
513
514 ```
515 inline void store_big_uN( unsigned char * p, boost::uintM_t v ) noexcept;
516 ```
517 [none]
518 * {blank}
519 +
520 Writes an N-bit unsigned big-endian integer to `p`.
521 +
522 Effects::
523   `endian_store<boost::uintM_t, N/8, order::big>( p, v )`.
524
525 ## FAQ
526
527 See 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
532 that compute a value from an argument. Modify-in-place functions allow cleaner
533 code in many real-world endian use cases and are more efficient for user-defined
534 types that have members such as string data that do not need to be reversed.
535 Thus 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
540 systems. A {cpp} library TS was going to use those names, but found they were
541 sometimes implemented as macros. Since macros do not respect scoping and
542 namespace rules, to use them would be very error prone.
543
544 ## Acknowledgements
545
546 Tomas Puverle was instrumental in identifying and articulating the need to
547 support endian conversion as separate from endian integer types. Phil Endecott
548 suggested the form of the value returning signatures. Vicente Botet and other
549 reviewers suggested supporting  user defined types. General reverse template
550 implementation approach using `std::reverse` suggested by Mathias Gaunard.
551 Portable implementation approach for 16, 32, and 64-bit integers suggested by
552 tymofey, with avoidance of undefined behavior as suggested by Giovanni Piero
553 Deretta, and a further refinement suggested by Pyry Jahkola. Intrinsic builtins
554 implementation approach for 16, 32, and 64-bit integers suggested by several
555 reviewers, and by David Stone, who provided his Boost licensed macro
556 implementation 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()`
559 implementations.