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[#overview] 9# Overview 10:idprefix: overview_ 11 12## Abstract 13 14Boost.Endian provides facilities to manipulate the 15<<overview_endianness,endianness>> of integers and user-defined types. 16 17* Three approaches to endianness are supported. Each has a long history of 18successful use, and each approach has use cases where it is preferred over the 19other approaches. 20* Primary uses: 21** Data portability. The Endian library supports binary data exchange, via 22either external media or network transmission, regardless of platform 23endianness. 24** Program portability. POSIX-based and Windows-based operating systems 25traditionally supply libraries with non-portable functions to perform endian 26conversion. There are at least four incompatible sets of functions in common 27use. The Endian library is portable across all {cpp} platforms. 28* Secondary use: Minimizing data size via sizes and/or alignments not supported 29by the standard {cpp} integer types. 30 31[#overview_endianness] 32## Introduction to endianness 33 34Consider the following code: 35 36``` 37int16_t i = 0x0102; 38FILE * file = fopen("test.bin", "wb"); // binary file! 39fwrite(&i, sizeof(int16_t), 1, file); 40fclose(file); 41``` 42 43On OS X, Linux, or Windows systems with an Intel CPU, a hex dump of the 44"test.bin" output file produces: 45 46``` 470201 48``` 49 50On OS X systems with a PowerPC CPU, or Solaris systems with a SPARC CPU, a hex 51dump of the "test.bin" output file produces: 52 53``` 540102 55``` 56 57What's happening here is that Intel CPUs order the bytes of an integer with the 58least-significant byte first, while SPARC CPUs place the most-significant byte 59first. Some CPUs, such as the PowerPC, allow the operating system to choose 60which ordering applies. 61 62Most-significant-byte-first ordering is traditionally called "big endian" 63ordering and least-significant-byte-first is traditionally called 64"little-endian" ordering. The names are derived from 65http://en.wikipedia.org/wiki/Jonathan_Swift[Jonathan Swift]'s satirical novel 66_http://en.wikipedia.org/wiki/Gulliver's_Travels[Gulliver's Travels]_, where 67rival kingdoms opened their soft-boiled eggs at different ends. 68 69See Wikipedia's http://en.wikipedia.org/wiki/Endianness[Endianness] article for 70an extensive discussion of endianness. 71 72Programmers can usually ignore endianness, except when reading a core dump on 73little-endian systems. But programmers have to deal with endianness when 74exchanging binary integers and binary floating point values between computer 75systems with differing endianness, whether by physical file transfer or over a 76network. And programmers may also want to use the library when minimizing either 77internal or external data sizes is advantageous. 78 79[#overview_introduction] 80## Introduction to the Boost.Endian library 81 82Boost.Endian provides three different approaches to dealing with endianness. All 83three approaches support integers and user-define types (UDTs). 84 85Each approach has a long history of successful use, and each approach has use 86cases where it is preferred to the other approaches. See 87<<choosing,Choosing between Conversion Functions, Buffer Types, and Arithmetic Types>>. 88 89<<conversion,Endian conversion functions>>:: 90The application uses the built-in integer types to hold values, and calls the 91provided conversion functions to convert byte ordering as needed. Both mutating 92and non-mutating conversions are supplied, and each comes in unconditional and 93conditional variants. 94 95<<buffers, Endian buffer types>>:: 96The application uses the provided endian buffer types to hold values, and 97explicitly converts to and from the built-in integer types. Buffer sizes of 8, 9816, 24, 32, 40, 48, 56, and 64 bits (i.e. 1, 2, 3, 4, 5, 6, 7, and 8 bytes) are 99provided. Unaligned integer buffer types are provided for all sizes, and aligned 100buffer types are provided for 16, 32, and 64-bit sizes. The provided specific 101types are typedefs for a generic class template that may be used directly for 102less common use cases. 103 104<<arithmetic, Endian arithmetic types>>:: 105The application uses the provided endian arithmetic types, which supply the same 106operations as the built-in {cpp} arithmetic types. All conversions are implicit. 107Arithmetic sizes of 8, 16, 24, 32, 40, 48, 56, and 64 bits (i.e. 1, 2, 3, 4, 5, 1086, 7, and 8 bytes) are provided. Unaligned integer types are provided for all 109sizes and aligned arithmetic types are provided for 16, 32, and 64-bit sizes. 110The provided specific types are typedefs for a generic class template that may 111be used directly in generic code of for less common use cases. 112 113Boost Endian is a header-only library. {cpp}11 features affecting interfaces, 114such as `noexcept`, are used only if available. See 115<<overview_cpp03_support,{cpp}03 support for {cpp}11 features>> for details. 116 117[#overview_intrinsics] 118## Built-in support for Intrinsics 119 120Most compilers, including GCC, Clang, and Visual {cpp}, supply built-in support 121for byte swapping intrinsics. The Endian library uses these intrinsics when 122available since they may result in smaller and faster generated code, 123particularly for optimized builds. 124 125Defining the macro `BOOST_ENDIAN_NO_INTRINSICS` will suppress use of the 126intrinsics. This is useful when a compiler has no intrinsic support or fails to 127locate the appropriate header, perhaps because it is an older release or has 128very limited supporting libraries. 129 130The macro `BOOST_ENDIAN_INTRINSIC_MSG` is defined as either 131`"no byte swap intrinsics"` or a string describing the particular set of 132intrinsics being used. This is useful for eliminating missing intrinsics as a 133source of performance issues. 134 135## Performance 136 137Consider this problem: 138 139### Example 1 140Add 100 to a big endian value in a file, then write the result to a file 141[%header,cols=2*] 142|=== 143|Endian arithmetic type approach |Endian conversion function approach 144a| 145---- 146big_int32_at x; 147 148... read into x from a file ... 149 150 151x += 100; 152 153 154... write x to a file ... 155---- 156a| 157---- 158int32_t x; 159 160... read into x from a file ... 161 162big_to_native_inplace(x); 163x += 100; 164native_to_big_inplace(x); 165 166... write x to a file ... 167---- 168|=== 169 170*There will be no performance difference between the two approaches in optimized 171builds, regardless of the native endianness of the machine.* That's because 172optimizing compilers will generate exactly the same code for each. That 173conclusion was confirmed by studying the generated assembly code for GCC and 174Visual {cpp}. Furthermore, time spent doing I/O will determine the speed of this 175application. 176 177Now consider a slightly different problem: 178 179### Example 2 180Add a million values to a big endian value in a file, then write the result to a 181file 182[%header,cols=2*] 183|=== 184|Endian arithmetic type approach |Endian conversion function approach 185a| 186---- 187big_int32_at x; 188 189... read into x from a file ... 190 191 192 193for (int32_t i = 0; i < 1000000; ++i) 194 x += i; 195 196 197 198... write x to a file ... 199---- 200a| 201---- 202int32_t x; 203 204... read into x from a file ... 205 206big_to_native_inplace(x); 207 208for (int32_t i = 0; i < 1000000; ++i) 209 x += i; 210 211native_to_big_inplace(x); 212 213... write x to a file ... 214---- 215|=== 216 217With the Endian arithmetic approach, on little endian platforms an implicit 218conversion from and then back to big endian is done inside the loop. With the 219Endian conversion function approach, the user has ensured the conversions are 220done outside the loop, so the code may run more quickly on little endian 221platforms. 222 223### Timings 224 225These tests were run against release builds on a circa 2012 4-core little endian 226X64 Intel Core i5-3570K CPU @ 3.40GHz under Windows 7. 227 228CAUTION: The Windows CPU timer has very high granularity. Repeated runs of the 229same tests often yield considerably different results. 230 231See `test/loop_time_test.cpp` for the actual code and `benchmark/Jamfile.v2` for 232the build setup. 233 234#### GNU C++ version 4.8.2 on Linux virtual machine 235Iterations: 10'000'000'000, Intrinsics: `__builtin_bswap16`, etc. 236[%header,cols=3*] 237|=== 238|Test Case |Endian arithmetic type |Endian conversion function 239|16-bit aligned big endian |8.46 s |5.28 s 240|16-bit aligned little endian |5.28 s |5.22 s 241|32-bit aligned big endian |8.40 s |2.11 s 242|32-bit aligned little endian |2.11 s |2.10 s 243|64-bit aligned big endian |14.02 s |3.10 s 244|64-bit aligned little endian |3.00 s |3.03 s 245|=== 246 247#### Microsoft Visual C++ version 14.0 248Iterations: 10'000'000'000, Intrinsics: `<cstdlib>` `_byteswap_ushort`, etc. 249[%header,cols=3*] 250|=== 251|Test Case |Endian arithmetic type |Endian conversion function 252|16-bit aligned big endian |8.27 s |5.26 s 253|16-bit aligned little endian |5.29 s |5.32 s 254|32-bit aligned big endian |8.36 s |5.24 s 255|32-bit aligned little endian |5.24 s |5.24 s 256|64-bit aligned big endian |13.65 s |3.34 s 257|64-bit aligned little endian |3.35 s |2.73 s 258|=== 259 260[#overview_cpp03_support] 261## {cpp}03 support for {cpp}11 features 262 263[%header,cols=2*] 264|=== 265|{cpp}11 Feature 266|Action with {cpp}03 Compilers 267|Scoped enums 268|Uses header 269http://www.boost.org/libs/core/doc/html/core/scoped_enum.html[boost/core/scoped_enum.hpp] 270to emulate {cpp}11 scoped enums. 271|`noexcept` 272|Uses `BOOST_NOEXCEPT` macro, which is defined as null for compilers not 273supporting this {cpp}11 feature. 274|{cpp}11 PODs 275(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm[N2342]) 276|Takes advantage of {cpp}03 compilers that relax {cpp}03 POD rules, but see 277Limitations <<buffers_limitations,here>> and <<arithmetic_limitations,here>>. 278Also see macros for explicit POD control <<buffers_compilation,here>> and 279<<arithmetic_compilation,here>> 280|=== 281 282[#overview_faq] 283## Overall FAQ 284 285Is the implementation header only?:: 286Yes. 287 288Are {cpp}03 compilers supported?:: 289Yes. 290 291Does the implementation use compiler intrinsic built-in byte swapping?:: 292Yes, if available. See <<overview_intrinsics,Intrinsic built-in support>>. 293 294Why bother with endianness?:: 295Binary data portability is the primary use case. 296 297Does endianness have any uses outside of portable binary file or network I/O formats?:: 298Using the unaligned integer types with a size tailored to the application's 299needs is a minor secondary use that saves internal or external memory space. For 300example, using `big_int40_buf_t` or `big_int40_t` in a large array saves a lot 301of space compared to one of the 64-bit types. 302 303Why bother with binary I/O? Why not just use {cpp} Standard Library stream inserters and extractors?:: 304* Data interchange formats often specify binary integer data. Binary integer 305data is smaller and therefore I/O is faster and file sizes are smaller. Transfer 306between systems is less expensive. 307* Furthermore, binary integer data is of fixed size, and so fixed-size disk 308records are possible without padding, easing sorting and allowing random access. 309* Disadvantages, such as the inability to use text utilities on the resulting 310files, limit usefulness to applications where the binary I/O advantages are 311paramount. 312 313Which is better, big-endian or little-endian?:: 314Big-endian tends to be preferred in a networking environment and is a bit more 315of an industry standard, but little-endian may be preferred for applications 316that run primarily on x86, x86-64, and other little-endian CPU's. The 317http://en.wikipedia.org/wiki/Endian[Wikipedia] article gives more pros and cons. 318 319Why are only big and little native endianness supported?:: 320These are the only endian schemes that have any practical value today. PDP-11 321and the other middle endian approaches are interesting curiosities but have no 322relevance for today's {cpp} developers. The same is true for architectures that 323allow runtime endianness switching. The 324<<conversion_native_order_specification,specification for native ordering>> has 325been carefully crafted to allow support for such orderings in the future, should 326the need arise. Thanks to Howard Hinnant for suggesting this. 327 328Why do both the buffer and arithmetic types exist?:: 329Conversions in the buffer types are explicit. Conversions in the arithmetic 330types are implicit. This fundamental difference is a deliberate design feature 331that would be lost if the inheritance hierarchy were collapsed. 332The original design provided only arithmetic types. Buffer types were requested 333during formal review by those wishing total control over when conversion occurs. 334They also felt that buffer types would be less likely to be misused by 335maintenance programmers not familiar with the implications of performing a lot 336of integer operations on the endian arithmetic integer types. 337 338What is gained by using the buffer types rather than always just using the arithmetic types?:: 339Assurance that hidden conversions are not performed. This is of overriding 340importance to users concerned about achieving the ultimate in terms of speed. 341"Always just using the arithmetic types" is fine for other users. When the 342ultimate in speed needs to be ensured, the arithmetic types can be used in the 343same design patterns or idioms that would be used for buffer types, resulting in 344the same code being generated for either types. 345 346What are the limitations of integer support?:: 347Tests have only been performed on machines that use two's complement 348arithmetic. The Endian conversion functions only support 8, 16, 32, and 64-bit 349aligned integers. The endian types only support 8, 16, 24, 32, 40, 48, 56, and 35064-bit unaligned integers, and 8, 16, 32, and 64-bit aligned integers. 351 352Is there floating point support?:: 353An attempt was made to support four-byte ``float``s and eight-byte 354``double``s, limited to 355http://en.wikipedia.org/wiki/IEEE_floating_point[IEEE 754] (also known as 356ISO/IEC/IEEE 60559) floating point and further limited to systems where floating 357point endianness does not differ from integer endianness. Even with those 358limitations, support for floating point types was not reliable and was removed. 359For example, simply reversing the endianness of a floating point number can 360result in a signaling-NAN. 361+ 362Support for `float` and `double` has since been reinstated for `endian_buffer`, 363`endian_arithmetic` and the conversion functions that reverse endianness in place. 364The conversion functions that take and return by value still do not support floating 365point due to the above issues; reversing the bytes of a floating point number 366does not necessarily produce another valid floating point number. 367