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