forked from boostorg/endian
Merge branch 'develop' into feature/endian-load-store
This commit is contained in:
14
appveyor.yml
14
appveyor.yml
@ -14,28 +14,28 @@ branches:
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0,msvc-12.0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
TOOLSET: msvc-14.0
|
||||
TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
TOOLSET: msvc-12.0,msvc-14.0
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc-14.1
|
||||
CXXSTD: 14,17
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 03,11,14,1z
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 03,11,14,1z
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
ADDPATH: C:\mingw\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 03,11,14,1z
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 03,11,14,1z
|
||||
|
2
doc/.gitignore
vendored
Normal file
2
doc/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/html/
|
||||
/pdf/
|
27
doc/Jamfile
Normal file
27
doc/Jamfile
Normal file
@ -0,0 +1,27 @@
|
||||
# Copyright 2019 Glen Joseph Fernandes
|
||||
# (glenjofe@gmail.com)
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import asciidoctor ;
|
||||
|
||||
html endian.html : endian.adoc ;
|
||||
|
||||
install html_ : endian.html : <location>html ;
|
||||
|
||||
pdf endian.pdf : endian.adoc ;
|
||||
|
||||
explicit endian.pdf ;
|
||||
|
||||
install pdf_ : endian.pdf : <location>pdf ;
|
||||
|
||||
explicit pdf_ ;
|
||||
|
||||
alias boostdoc ;
|
||||
|
||||
explicit boostdoc ;
|
||||
|
||||
alias boostrelease : html_ ;
|
||||
|
||||
explicit boostrelease ;
|
@ -1,639 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Endian Arithmetic Types</title>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="../../../index.html">
|
||||
<img src="../../../boost.png" alt="Boost logo" align="middle" border="0" width="277" height="86"></a></td>
|
||||
<td align="middle">
|
||||
<b>
|
||||
<font size="6">Endian Arithmetic Types</font> </b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
||||
<tr>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p></p>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" align="right">
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#D7EEFF" align="center">
|
||||
<i><b>Contents</b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#E8F5FF">
|
||||
<a href="#Introduction">Introduction</a><br>
|
||||
<a href="#Example">Example</a><br>
|
||||
<a href="#Limitations">Limitations</a><br>
|
||||
<a href="#Feature-set">Feature set</a><br>
|
||||
<a href="#Types">Enums and typedefs</a><br>
|
||||
<a href="#Class_template_endian">Class template <code>endian</code></a><br>
|
||||
|
||||
<a href="#Synopsis">Synopsis</a><br>
|
||||
<a href="#Members">Members</a><br>
|
||||
<a href="#Stream-inserter">Stream inserter</a><br>
|
||||
<a href="#Stream-extractor">Stream extractor</a><br>
|
||||
<a href="#FAQ">FAQ</a><br>
|
||||
<a href="#Design">Design</a><br>
|
||||
<a href="#Experience">Experience</a><br>
|
||||
<a href="#Motivating-use-cases">Motivating use cases</a><br>
|
||||
<a href="#C++0x">C++11</a><br>
|
||||
<a href="#Compilation">Compilation</a><br>
|
||||
<a href="#Acknowledgements">Acknowledgements</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
<p>Header <a href="arithmetic.html">boost/endian/arithmetic.hpp</a>
|
||||
provides integer binary types with control over
|
||||
byte order, value type, size, and alignment. Typedefs provide easy-to-use names
|
||||
for common configurations.</p>
|
||||
<p>These types provide portable byte-holders for integer data, independent of
|
||||
particular computer architectures. Use cases almost always involve I/O, either via files or
|
||||
network connections. Although data portability is the primary motivation, these
|
||||
integer byte-holders may
|
||||
also be used to reduce memory use, file size, or network activity since they
|
||||
provide binary integer sizes not otherwise available.</p>
|
||||
<p>Such integer byte-holder types are traditionally called <b><i>
|
||||
endian</i></b> types. See the
|
||||
<a href="http://en.wikipedia.org/wiki/Endian" name="endianness">Wikipedia</a> for
|
||||
a full
|
||||
exploration of <b><i>endianness</i></b>, including definitions of <i><b>big
|
||||
endian</b></i> and <i><b>little endian</b></i>.</p>
|
||||
<p>Boost endian integers provide the same full set of C++ assignment,
|
||||
arithmetic, and relational operators as C++ standard integral types, with
|
||||
the standard semantics.</p>
|
||||
<p>Unary arithmetic operators are <b> <code><font face="Courier New">+</font></code></b>,
|
||||
<b> <code>-</code></b>, <b> <code>~</code></b>, <b>
|
||||
<code>!</code></b>, plus both prefix and postfix <b> <code>--</code></b> and <b> <code>++</code></b>. Binary
|
||||
arithmetic operators are <b> <code>+</code></b>, <b> <code>+=</code></b>, <b> <code>-</code></b>,
|
||||
<b> <code>
|
||||
-=</code></b>, <b> <code>*</code></b>, <b> <code>*=</code></b>, <b> <code>/</code></b>,
|
||||
<b> <code>/=</code></b>, <b> <code>&</code></b>, <b> <code>&=</code></b>,
|
||||
<b> <code>|</code></b>, <b> <code>|=</code></b>, <b>
|
||||
<code>^</code></b>, <b> <code>^=</code></b>, <b> <code><<</code></b>, <b> <code><<=</code></b>, <code>
|
||||
<b>>></b></code>, and <b>
|
||||
<code>>>=</code></b>. Binary relational operators are <b> <code>==</code></b>,
|
||||
<b> <code>!=</code></b>, <b>
|
||||
<code><</code></b>, <b> <code><=</code></b>, <b> <code>></code></b>,
|
||||
and <b> <code>>=</code></b>.</p>
|
||||
<p>Implicit conversion to the underlying value type is provided. An implicit
|
||||
constructor converting from the underlying value type is provided. </p>
|
||||
<h2><a name="Example">Example</a></h2>
|
||||
<p>The <a href="../example/endian_example.cpp">endian_example.cpp</a> program writes a
|
||||
binary file containing four-byte, big-endian and little-endian integers:</p>
|
||||
<blockquote>
|
||||
<pre>#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <boost/endian/arithmetic.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
using namespace boost::endian;
|
||||
|
||||
namespace
|
||||
{
|
||||
// This is an extract from a very widely used GIS file format.
|
||||
// Why the designer decided to mix big and little endians in
|
||||
// the same file is not known. But this is a real-world format
|
||||
// and users wishing to write low level code manipulating these
|
||||
// files have to deal with the mixed endianness.
|
||||
|
||||
struct header
|
||||
{
|
||||
big_int32_t file_code;
|
||||
big_int32_t file_length;
|
||||
little_int32_t version;
|
||||
little_int32_t shape_type;
|
||||
};
|
||||
|
||||
const char* filename = "test.dat";
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
header h;
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check
|
||||
|
||||
h.file_code = 0x01020304;
|
||||
h.file_length = sizeof(header);
|
||||
h.version = 1;
|
||||
h.shape_type = 0x01020304;
|
||||
|
||||
// Low-level I/O such as POSIX read/write or <cstdio>
|
||||
// fread/fwrite is sometimes used for binary file operations
|
||||
// when ultimate efficiency is important. Such I/O is often
|
||||
// performed in some C++ wrapper class, but to drive home the
|
||||
// point that endian integers are often used in fairly
|
||||
// low-level code that does bulk I/O operations, <cstdio>
|
||||
// fopen/fwrite is used for I/O in this example.
|
||||
|
||||
std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
|
||||
|
||||
if (!fi)
|
||||
{
|
||||
std::cout << "could not open " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (std::fwrite(&h, sizeof(header), 1, fi)!= 1)
|
||||
{
|
||||
std::cout << "write failure for " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::fclose(fi);
|
||||
|
||||
std::cout << "created file " << filename << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>After compiling and executing <a href="../example/endian_example.cpp">endian_example.cpp</a>,
|
||||
a hex dump of <code>test.dat</code> shows:</p>
|
||||
<blockquote>
|
||||
<pre>01020304 00000010 01000000 04030201</pre>
|
||||
</blockquote>
|
||||
<p>Notice that the first two 32-bit integers are big endian while the second two
|
||||
are little endian, even though the machine this was compiled and run on was
|
||||
little endian.</p>
|
||||
<h2><a name="Limitations">Limitations</a></h2>
|
||||
<p>Requires <code><climits></code> <code>CHAR_BIT == 8</code>. If <code>CHAR_BIT</code>
|
||||
is some other value, compilation will result in an <code>#error</code>. This
|
||||
restriction is in place because the design, implementation, testing, and
|
||||
documentation has only considered issues related to 8-bit bytes, and there have
|
||||
been no real-world use cases presented for other sizes.</p>
|
||||
<p>In C++03, <code>endian_arithmetic</code> does not meet the requirements for POD types
|
||||
because it has constructors, private data members, and a base class. This means
|
||||
that common use cases are relying on unspecified behavior in that the C++
|
||||
Standard does not guarantee memory layout for non-POD types. This has not been a
|
||||
problem in practice since all known C++ compilers lay out memory as if <code>
|
||||
endian</code> were a POD type. In C++11, it is possible to specify the
|
||||
default constructor as trivial, and private data members and base classes no longer disqualify a type from being a POD
|
||||
type. Thus under C++11, <code>endian_arithmetic</code>
|
||||
will no longer be relying on unspecified behavior.</p>
|
||||
<h2><a name="Feature-set">Feature set</a></h2>
|
||||
<ul>
|
||||
<li>Big endian| little endian | native endian byte ordering.</li>
|
||||
<li>Signed | unsigned</li>
|
||||
<li>Unaligned | aligned</li>
|
||||
<li>1-8 byte (unaligned) | 1, 2, 4, 8 byte (aligned)</li>
|
||||
<li>Choice of value type</li>
|
||||
</ul>
|
||||
<h2>Enums and t<a name="Types">ypedefs</a></h2>
|
||||
<p>Two scoped enums are provided:</p>
|
||||
<blockquote>
|
||||
<pre>enum class order {big, little, native};
|
||||
|
||||
enum class align {no, yes}; </pre>
|
||||
</blockquote>
|
||||
<p>One class template is provided:</p>
|
||||
<blockquote>
|
||||
<pre>template <order Order, typename T, std::size_t n_bits,
|
||||
align Align = align::no>
|
||||
class endian_arithmetic;
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>Typedefs, such as <code>big_int32_t</code>, provide convenient naming
|
||||
conventions for common use cases:</p>
|
||||
<blockquote>
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="49%">
|
||||
<tr>
|
||||
<td width="18%" align="center"><b><i>Name</i></b></td>
|
||||
<td width="49%" align="center"><b><i>Alignment</i></b></td>
|
||||
<td width="10%" align="center"><b><i>Endianness</i></b></td>
|
||||
<td width="10%" align="center"><b><i>Sign</i></b></td>
|
||||
<td width="15%" align="center"><b><i>Sizes in bits (n)</i></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>big_int</code><b><i>n</i></b><code>_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>big</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>big_uint</code><i><b>n</b></i><code>_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>big</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>little_int</code><i><b>n</b></i><code>_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>little</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>little_uint</code><i><b>n</b></i><code>_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>little</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>native_int</code><i><b>n</b></i><code>_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>native</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>native_uint</code><i><b>n</b></i><code>_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>native</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>big_int</code><i><b>n</b></i><code>_at</code></td>
|
||||
<td width="49%" align="center"><code>yes</code></td>
|
||||
<td width="10%" align="center"><code>big</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,32,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>big_uint</code><i><b>n</b></i><code>_at</code></td>
|
||||
<td width="49%" align="center"><code>yes</code></td>
|
||||
<td width="10%" align="center"><code>big</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,32,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%" dir="ltr"><code>little_int</code><i><b>n</b></i><code>_at</code></td>
|
||||
<td width="49%" align="center" dir="ltr"><code>yes</code></td>
|
||||
<td width="10%" align="center" dir="ltr"><code>little</code></td>
|
||||
<td width="10%" align="center" dir="ltr">signed</td>
|
||||
<td width="15%" dir="ltr">8,16,32,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%" dir="ltr"><code>little_uint</code><i><b>n</b></i><code>_at</code></td>
|
||||
<td width="49%" align="center" dir="ltr"><code>yes</code></td>
|
||||
<td width="10%" align="center" dir="ltr"><code>little</code></td>
|
||||
<td width="10%" align="center" dir="ltr">unsigned</td>
|
||||
<td width="15%" dir="ltr">8,16,32,64</td>
|
||||
</tr>
|
||||
</table>
|
||||
</blockquote>
|
||||
<p>The unaligned types do not cause compilers to insert padding bytes in classes
|
||||
and structs. This is an important characteristic that can be exploited to minimize wasted space in
|
||||
memory, files, and network transmissions. </p>
|
||||
<p><font color="#FF0000"><b><i><span style="background-color: #FFFFFF">Warning:</span></i></b></font><span style="background-color: #FFFFFF">
|
||||
Code that uses a</span>ligned types is possibly non-portable because alignment
|
||||
requirements vary between hardware architectures and because alignment may be
|
||||
affected by compiler switches or pragmas. For example, alignment of an 64-bit
|
||||
integer may be to a 32-bit boundary on a 32-bit machine. Furthermore, aligned types
|
||||
are only available on architectures with 8, 16, 32, and 64-bit integer types.</p>
|
||||
<p><i><b>Recommendation:</b></i> Prefer unaligned arithmetic types.</p>
|
||||
<p><i><b>Recommendation:</b></i> Protect yourself against alignment ills. For
|
||||
example:</p>
|
||||
<blockquote>
|
||||
<pre>static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong"); </pre>
|
||||
</blockquote>
|
||||
<p><b><i>Note:</i></b> <b><i>Note:</i></b> One-byte arithmetic types
|
||||
have identical layout on all platforms, so they never actually reverse endianness. They are provided to enable generic code, and
|
||||
to improve code readability and searchability.</p>
|
||||
<h2><a name="Class_template_endian">Class template <code>endian</code></a><code>_arithmetic</code></h2>
|
||||
<p>An <code>endian_integer</code> is an integer byte-holder with user-specified <a href="#endianness">
|
||||
endianness</a>, value type, size, and <a href="#alignment">alignment</a>. The
|
||||
usual operations on arithmetic types are supplied.</p>
|
||||
<h3><a name="Synopsis">Synopsis</a></h3>
|
||||
<pre>#include <boost/endian/conversion.hpp>
|
||||
#include <boost/endian/buffers.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace endian
|
||||
{
|
||||
// C++11 features emulated if not available
|
||||
|
||||
enum class <a name="alignment">align</a> {no, yes};
|
||||
|
||||
template <order Order, class T, std::size_t n_bits,
|
||||
align Align = align::no>
|
||||
class endian_arithmetic
|
||||
: public endian_buffer<Order, T, n_bits, Align>
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
// if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 PODs are not
|
||||
// available then these two constructors will not be present
|
||||
<a href="#endian">endian_arithmetic</a>() noexcept = default;
|
||||
<a href="#explicit-endian">endian_arithmetic</a>(T v) noexcept;
|
||||
|
||||
endian_arithmetic& <a href="#operator-eq">operator=</a>(T v) noexcept;
|
||||
<a href="#operator-T">operator value_type</a>() const noexcept;
|
||||
value_type value() const noexcept; // for exposition; see endian_buffer
|
||||
const char* <a href="#data">data</a>() const noexcept; // for exposition; see endian_buffer
|
||||
|
||||
// arithmetic operations
|
||||
// note that additional operations are provided by the value_type
|
||||
value_type operator+(const endian& x) noexcept;
|
||||
endian& operator+=(endian& x, value_type y) noexcept;
|
||||
endian& operator-=(endian& x, value_type y) noexcept;
|
||||
endian& operator*=(endian& x, value_type y) noexcept;
|
||||
endian& operator/=(endian& x, value_type y) noexcept;
|
||||
endian& operator%=(endian& x, value_type y) noexcept;
|
||||
endian& operator&=(endian& x, value_type y) noexcept;
|
||||
endian& operator|=(endian& x, value_type y) noexcept;
|
||||
endian& operator^=(endian& x, value_type y) noexcept;
|
||||
endian& operator<<=(endian& x, value_type y) noexcept;
|
||||
endian& operator>>=(endian& x, value_type y noexcept;
|
||||
value_type operator<<(const endian& x, value_type y) noexcept;
|
||||
value_type operator>>(const endian& x, value_type y) noexcept;
|
||||
endian& operator++(endian& x) noexcept;
|
||||
endian& operator--(endian& x) noexcept;
|
||||
endian operator++(endian& x, int) noexcept;
|
||||
endian operator--(endian& x, int) noexcept;
|
||||
|
||||
// Stream inserter
|
||||
template <class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const T& x);
|
||||
|
||||
// Stream extractor
|
||||
template <class charT, class traits>
|
||||
friend std::basic_istream<charT, traits>&
|
||||
operator>>(std::basic_istream<charT, traits>& is, T& x);
|
||||
};
|
||||
|
||||
// typedefs
|
||||
|
||||
// unaligned big endian signed integer types
|
||||
typedef endian<order::big, int_least8_t, 8> big_int8_t;
|
||||
typedef endian<order::big, int_least16_t, 16> big_int16_t;
|
||||
typedef endian<order::big, int_least32_t, 24> big_int24_t;
|
||||
typedef endian<order::big, int_least32_t, 32> big_int32_t;
|
||||
typedef endian<order::big, int_least64_t, 40> big_int40_t;
|
||||
typedef endian<order::big, int_least64_t, 48> big_int48_t;
|
||||
typedef endian<order::big, int_least64_t, 56> big_int56_t;
|
||||
typedef endian<order::big, int_least64_t, 64> big_int64_t;
|
||||
|
||||
// unaligned big endian unsigned integer types
|
||||
typedef endian<order::big, uint_least8_t, 8> big_uint8_t;
|
||||
typedef endian<order::big, uint_least16_t, 16> big_uint16_t;
|
||||
typedef endian<order::big, uint_least32_t, 24> big_uint24_t;
|
||||
typedef endian<order::big, uint_least32_t, 32> big_uint32_t;
|
||||
typedef endian<order::big, uint_least64_t, 40> big_uint40_t;
|
||||
typedef endian<order::big, uint_least64_t, 48> big_uint48_t;
|
||||
typedef endian<order::big, uint_least64_t, 56> big_uint56_t;
|
||||
typedef endian<order::big, uint_least64_t, 64> big_uint64_t;
|
||||
|
||||
// unaligned little endian signed integer types
|
||||
typedef endian<order::little, int_least8_t, 8> little_int8_t;
|
||||
typedef endian<order::little, int_least16_t, 16> little_int16_t;
|
||||
typedef endian<order::little, int_least32_t, 24> little_int24_t;
|
||||
typedef endian<order::little, int_least32_t, 32> little_int32_t;
|
||||
typedef endian<order::little, int_least64_t, 40> little_int40_t;
|
||||
typedef endian<order::little, int_least64_t, 48> little_int48_t;
|
||||
typedef endian<order::little, int_least64_t, 56> little_int56_t;
|
||||
typedef endian<order::little, int_least64_t, 64> little_int64_t;
|
||||
|
||||
// unaligned little endian unsigned integer types
|
||||
typedef endian<order::little, uint_least8_t, 8> little_uint8_t;
|
||||
typedef endian<order::little, uint_least16_t, 16> little_uint16_t;
|
||||
typedef endian<order::little, uint_least32_t, 24> little_uint24_t;
|
||||
typedef endian<order::little, uint_least32_t, 32> little_uint32_t;
|
||||
typedef endian<order::little, uint_least64_t, 40> little_uint40_t;
|
||||
typedef endian<order::little, uint_least64_t, 48> little_uint48_t;
|
||||
typedef endian<order::little, uint_least64_t, 56> little_uint56_t;
|
||||
typedef endian<order::little, uint_least64_t, 64> little_uint64_t;
|
||||
|
||||
// unaligned native endian signed integer types
|
||||
typedef <b><i>implementation-defined</i></b>_int8_t native_int8_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int16_t native_int16_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int24_t native_int24_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int32_t native_int32_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int40_t native_int40_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int48_t native_int48_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int56_t native_int56_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int64_t native_int64_t;
|
||||
|
||||
// unaligned native endian unsigned integer types
|
||||
typedef <b><i>implementation-defined</i></b>_uint8_t native_uint8_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint16_t native_uint16_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint24_t native_uint24_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint32_t native_uint32_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint40_t native_uint40_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint48_t native_uint48_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint56_t native_uint56_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint64_t native_uint64_t;
|
||||
|
||||
// aligned big endian signed integer types
|
||||
typedef endian<order::big, int8_t, 8, align::yes> big_int8_at;
|
||||
typedef endian<order::big, int16_t, 16, align::yes> big_int16_at;
|
||||
typedef endian<order::big, int32_t, 32, align::yes> big_int32_at;
|
||||
typedef endian<order::big, int64_t, 64, align::yes> big_int64_at;
|
||||
|
||||
// aligned big endian unsigned integer types
|
||||
typedef endian<order::big, uint8_t, 8, align::yes> big_uint8_at;
|
||||
typedef endian<order::big, uint16_t, 16, align::yes> big_uint16_at;
|
||||
typedef endian<order::big, uint32_t, 32, align::yes> big_uint32_at;
|
||||
typedef endian<order::big, uint64_t, 64, align::yes> big_uint64_at;
|
||||
|
||||
// aligned little endian signed integer types
|
||||
typedef endian<order::little, int8_t, 8, align::yes> little_int8_at;
|
||||
typedef endian<order::little, int16_t, 16, align::yes> little_int16_at;
|
||||
typedef endian<order::little, int32_t, 32, align::yes> little_int32_at;
|
||||
typedef endian<order::little, int64_t, 64, align::yes> little_int64_at;
|
||||
|
||||
// aligned little endian unsigned integer types
|
||||
typedef endian<order::little, uint8_t, 8, align::yes> little_uint8_at;
|
||||
typedef endian<order::little, uint16_t, 16, align::yes> little_uint16_at;
|
||||
typedef endian<order::little, uint32_t, 32, align::yes> little_uint32_at;
|
||||
typedef endian<order::little, uint64_t, 64, align::yes> little_uint64_at;
|
||||
|
||||
// aligned native endian typedefs are not provided because
|
||||
// <cstdint> types are superior for that use case
|
||||
|
||||
} // namespace endian
|
||||
} // namespace boost</pre>
|
||||
<p>The <i><b><code>implementation-defined</code></b></i> text above is either
|
||||
<code>big</code> or <code>little</code> according to the endianness of the
|
||||
platform.</p>
|
||||
<h3><a name="Members">Members</a></h3>
|
||||
<div dir="ltr">
|
||||
<pre><code><a name="endian">endian</a>() = default; // C++03: endian(){}</code></pre>
|
||||
</div>
|
||||
<blockquote>
|
||||
<p><i>Effects:</i> Constructs an uninitialized object of type <code>endian_arithmetic<E, T, n_bits, A></code>.</p>
|
||||
</blockquote>
|
||||
<pre><code><a name="explicit-endian">endian</a>(T v);</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Effects:</i> Constructs an object of type <code>endian_arithmetic<E, T, n_bits, A></code>.</p>
|
||||
<p><i>Postcondition:</i> <code>x == v,</code> where <code>x</code> is the
|
||||
constructed object.</p>
|
||||
</blockquote>
|
||||
<pre><code>endian& <a name="operator-eq">operator=</a>(T v);</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Postcondition:</i> <code>x == v,</code> where <code>x</code> is the
|
||||
constructed object.</p>
|
||||
<p><i>Returns:</i> <code>*this</code>.</p>
|
||||
</blockquote>
|
||||
<pre><code><a name="operator-T">operator T</a>() const;</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> The current value stored in <code>*this</code>, converted to
|
||||
<code>value_type</code>.</p>
|
||||
</blockquote>
|
||||
<pre><code>const char* <a name="data">data</a>() const;</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> A pointer to the first byte of the endian binary value stored
|
||||
in <code>*this</code>.</p>
|
||||
</blockquote>
|
||||
<h3>Other operators</h3>
|
||||
<p>Other operators on endian objects are forwarded to the equivalent
|
||||
operator on <code>value_type</code>.</p>
|
||||
<h3><a name="Stream-inserter">Stream inserter</a></h3>
|
||||
<pre>template <class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const T& x);
|
||||
</pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>os << +x</code>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="Stream-extractor">Stream extractor</a></h3>
|
||||
<pre>template <class charT, class traits>
|
||||
friend std::basic_istream<charT, traits>&
|
||||
operator>>(std::basic_istream<charT, traits>& is, T& x);
|
||||
</pre>
|
||||
<blockquote>
|
||||
<p><i>Effects: </i>As if:</p>
|
||||
<blockquote>
|
||||
<pre>T i;
|
||||
if (is >> i)
|
||||
x = i;
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p><i>Returns: </i><code>is</code><i>.</i></p>
|
||||
</blockquote>
|
||||
<h2><a name="FAQ">FAQ</a></h2>
|
||||
|
||||
<p>See the <a href="index.html#FAQ">Endian home page</a> FAQ for a library-wide
|
||||
FAQ.</p>
|
||||
|
||||
<p><b>Why not just use Boost.Serialization?</b> Serialization involves a
|
||||
conversion for every object involved in I/O. Endian integers require no
|
||||
conversion or copying. They are already in the desired format for binary I/O.
|
||||
Thus they can be read or written in bulk.</p>
|
||||
<p><b>Are endian types PODs?</b> Yes for C++11. No for C++03, although several
|
||||
<a href="#Compilation">macros</a> are available to force PODness in all cases.</p>
|
||||
<p><b>What are the implications of endian integer types not being PODs with C++03
|
||||
compilers?</b> They
|
||||
can't be used in unions. Also, compilers aren't required to align or lay
|
||||
out storage in portable ways, although this potential problem hasn't prevented
|
||||
use of Boost.Endian with
|
||||
real compilers.</p>
|
||||
<p><b>What good is <i>native </i>endianness?</b> It provides alignment and
|
||||
size guarantees not available from the built-in types. It eases generic
|
||||
programming.</p>
|
||||
<p><b>Why bother with the aligned endian types?</b> Aligned integer operations
|
||||
may be faster (as much as 10 to 20 times faster) if the endianness and alignment of
|
||||
the type matches the endianness and alignment requirements of the machine. The code,
|
||||
however, will be somewhat less portable than with the unaligned types.</p>
|
||||
<p><b>Why provide the arithmetic operations?</b> Providing a full set of operations reduces program
|
||||
clutter and makes code both easier to write and to read. Consider
|
||||
incrementing a variable in a record. It is very convenient to write:</p>
|
||||
<pre wrap> ++record.foo;</pre>
|
||||
<p wrap>Rather than:</p>
|
||||
<pre wrap> int temp(record.foo);
|
||||
++temp;
|
||||
record.foo = temp;</pre>
|
||||
<h2><a name="Design">Design</a> considerations for Boost.Endian types</h2>
|
||||
<ul>
|
||||
<li>Must be suitable for I/O - in other words, must be memcpyable.</li>
|
||||
<li>Must provide exactly the size and internal byte ordering specified.</li>
|
||||
<li>Must work correctly when the internal integer representation has more bits
|
||||
that the sum of the bits in the external byte representation. Sign extension
|
||||
must work correctly when the internal integer representation type has more
|
||||
bits than the sum of the bits in the external bytes. For example, using
|
||||
a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
|
||||
both positive and negative values.</li>
|
||||
<li>Must work correctly (including using the same defined external
|
||||
representation) regardless of whether a compiler treats char as signed or
|
||||
unsigned.</li>
|
||||
<li>Unaligned types must not cause compilers to insert padding bytes.</li>
|
||||
<li>The implementation should supply optimizations with great care. Experience has shown that optimizations of endian
|
||||
integers often become pessimizations when changing
|
||||
machines or compilers. Pessimizations can also happen when changing compiler switches,
|
||||
compiler versions, or CPU models of the same architecture.</li>
|
||||
</ul>
|
||||
<h2><a name="Experience">Experience</a></h2>
|
||||
<p>Classes with similar functionality have been independently developed by
|
||||
several Boost programmers and used very successful in high-value, high-use
|
||||
applications for many years. These independently developed endian libraries
|
||||
often evolved from C libraries that were also widely used. Endian types have proven widely useful across a wide
|
||||
range of computer architectures and applications.</p>
|
||||
<h2><a name="Motivating-use-cases">Motivating use cases</a></h2>
|
||||
<p>Neil Mayhew writes: "I can also provide a meaningful use-case for this
|
||||
library: reading TrueType font files from disk and processing the contents. The
|
||||
data format has fixed endianness (big) and has unaligned values in various
|
||||
places. Using Boost.Endian simplifies and cleans the code wonderfully."</p>
|
||||
<h2><a name="C++0x">C++11</a></h2>
|
||||
<p>The availability of the C++11
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
||||
Defaulted Functions</a> feature is detected automatically, and will be used if
|
||||
present to ensure that objects of <code>class endian_arithmetic</code> are trivial, and
|
||||
thus PODs.</p>
|
||||
<h2><a name="Compilation">Compilation</a></h2>
|
||||
<p>Boost.Endian is implemented entirely within headers, with no need to link to
|
||||
any Boost object libraries.</p>
|
||||
<p>Several macros allow user control over features:</p>
|
||||
<ul>
|
||||
<li>BOOST_ENDIAN_NO_CTORS causes <code>class endian_arithmetic</code> to have no
|
||||
constructors. The intended use is for compiling user code that must be
|
||||
portable between compilers regardless of C++11
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
||||
Defaulted Functions</a> support. Use of constructors will always fail, <br>
|
||||
</li>
|
||||
<li>BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if
|
||||
the compiler does not support C++11
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
||||
Defaulted Functions</a>. This is ensures that objects of <code>class endian_arithmetic</code>
|
||||
are PODs, and so can be used in C++03 unions.
|
||||
In C++11, <code>class endian_arithmetic</code> objects are PODs, even though they have
|
||||
constructors, so can always be used in unions.</li>
|
||||
</ul>
|
||||
<h2><a name="Acknowledgements">Acknowledgements</a></h2>
|
||||
<p>Original design developed by Darin Adler based on classes developed by Mark
|
||||
Borgerding. Four original class templates combined into a single <code>endian_arithmetic</code>
|
||||
class template by Beman Dawes, who put the library together, provided
|
||||
documentation, added the typedefs, and also added the <code>unrolled_byte_loops</code>
|
||||
sign partial specialization to correctly extend the sign when cover integer size
|
||||
differs from endian representation size.</p>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->14 October, 2015<!--webbot bot="Timestamp" endspan i-checksum="38874" --></p>
|
||||
<p>© Copyright Beman Dawes, 2006-2009, 2013</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See
|
||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,79 +0,0 @@
|
||||
Conversion function naming bikeshed
|
||||
|
||||
return-by-value modify-argument
|
||||
------------------ ---------------
|
||||
|
||||
reverse_endianness reverse_endianness_in_place
|
||||
" reverse_endianness_arg
|
||||
endian_reverse endian_reverse_in_place
|
||||
" endian_reverse_inplace
|
||||
" endian_reverse_replace
|
||||
" endian_reverse_in_situ
|
||||
" endian_reverse_here
|
||||
" endian_reverse_this
|
||||
" endian_reverse_self
|
||||
" endian_reverse_arg
|
||||
" endian_reverse_in
|
||||
|
||||
reverse reverse_in_place
|
||||
reverse_endian reverse_endian_in_place
|
||||
|
||||
swap_endianness swap_endianness_in_place
|
||||
swap_endian swap_endian_in_place
|
||||
endian_swap endian_swap_this
|
||||
|
||||
flip_endianness flip_endianness_in_place
|
||||
flip_endian flip_endian_in_place
|
||||
endian_flip endian_flip_in_place
|
||||
|
||||
|
||||
reverse_order reverse_order_in_place
|
||||
|
||||
|
||||
Key points:
|
||||
|
||||
* The above names are defined in a user namespace as customization points to be found by
|
||||
ADL, and so cannot depend on the enclosing namespace name to signal readers that they
|
||||
are related to endianness.
|
||||
* The above functions are rarely called directly by user code, which is more likely to use
|
||||
the various conditional functions instead. So explicitness is more important than
|
||||
brevity.
|
||||
|
||||
Conditional names
|
||||
|
||||
big_to_native native_to_big little_to_native native_to_little
|
||||
|
||||
big_to_host host_to_big
|
||||
|
||||
be_to_ne ne_to_be
|
||||
|
||||
from_big, to_big
|
||||
|
||||
big_to_native big_to_native
|
||||
native_to_big native_to_big
|
||||
|
||||
conditional_reverse runtime_conditional_reverse
|
||||
conditional_reverse conditional_reverse <------
|
||||
|
||||
merriam-webster.com/dictionary
|
||||
|
||||
reverse [1] (adjective): opposite or contrary to a previous or normal condition <reverse order>
|
||||
reverse [2] (verb) : to change (something) to an opposite state or condition
|
||||
|
||||
swap (verb) : to give something to someone and receive something in return : to trade or exchange (things)
|
||||
|
||||
flip (verb)
|
||||
|
||||
: to turn (something) over by throwing it up in the air with a quick movement
|
||||
|
||||
: to cause (something) to turn or turn over quickly
|
||||
|
||||
: to move (something) with a quick light movement
|
||||
|
||||
--------------------------------------------------
|
||||
|
||||
Copyright Beman Dawes, 2014
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
See www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
|
600
doc/buffers.html
600
doc/buffers.html
@ -1,600 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Endian Buffer Types</title>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="../../../index.html">
|
||||
<img src="../../../boost.png" alt="Boost logo" align="middle" border="0" width="277" height="86"></a></td>
|
||||
<td align="middle">
|
||||
<b>
|
||||
<font size="6">Endian Buffer Types</font> </b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
||||
<tr>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p></p>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" align="right">
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#D7EEFF" align="center">
|
||||
<i><b>Contents</b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#E8F5FF">
|
||||
<a href="#Introduction">Introduction</a><br>
|
||||
<a href="#Example">Example</a><br>
|
||||
<a href="#Limitations">Limitations</a><br>
|
||||
<a href="#Feature-set">Feature set</a><br>
|
||||
<a href="#Types">Enums and typedefs</a><br>
|
||||
<a href="#Class_template_endian">Class template <code>endian_buffer</code></a><br>
|
||||
|
||||
<a href="#Synopsis">Synopsis</a><br>
|
||||
<a href="#Members">Members</a><br>
|
||||
<a href="#Non-member-functions">Non-Members</a><br>
|
||||
<a href="#FAQ">FAQ</a><br>
|
||||
<a href="#Design">Design</a><br>
|
||||
<a href="#C++0x">C++11</a><br>
|
||||
<a href="#Compilation">Compilation</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
<p>The internal byte order of arithmetic types is traditionally called <b><i>endianness</i></b>. See
|
||||
the
|
||||
<a href="http://en.wikipedia.org/wiki/Endian" name="endianness">Wikipedia</a> for
|
||||
a full
|
||||
exploration of <b><i>endianness</i></b>, including definitions of <i><b>big
|
||||
endian</b></i> and <i><b>little endian</b></i>.</p>
|
||||
<p>Header <b><code>boost/endian/buffers.hpp</code></b>
|
||||
provides <code>endian_buffer</code>, a portable endian integer binary buffer
|
||||
class template with control over
|
||||
byte order, value type, size, and alignment independent of the platform's native
|
||||
endianness. Typedefs provide easy-to-use names
|
||||
for common configurations.</p>
|
||||
<p>Use cases primarily involve data portability, either via files or network
|
||||
connections, but these byte-holders may
|
||||
also be used to reduce memory use, file size, or network activity since they
|
||||
|
||||
provide binary numeric sizes not otherwise available.</p>
|
||||
<p dir="ltr">Class <code>endian_buffer</code> is aimed at users who wish
|
||||
explicit control over when endianness conversions occur. It also serves as the
|
||||
base class for the <code><a href="arithmetic.html">endian_arithmetic</a></code>
|
||||
class template, which is aimed at users who wish fully automatic endianness
|
||||
conversion and direct support for all normal arithmetic operations.</p>
|
||||
<h2><a name="Example">Example</a></h2>
|
||||
<p>The <b><code>example/endian_example.cpp</code></b> program writes a
|
||||
binary file containing four-byte, big-endian and little-endian integers:</p>
|
||||
<blockquote>
|
||||
<pre>#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <boost/endian/buffers.hpp> // see <a href="#Synopsis">Synopsis</a> below
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
using namespace boost::endian;
|
||||
|
||||
namespace
|
||||
{
|
||||
// This is an extract from a very widely used GIS file format.
|
||||
// Why the designer decided to mix big and little endians in
|
||||
// the same file is not known. But this is a real-world format
|
||||
// and users wishing to write low level code manipulating these
|
||||
// files have to deal with the mixed endianness.
|
||||
|
||||
struct header
|
||||
{
|
||||
big_int32_<code>buf_</code>t file_code;
|
||||
big_int32_<code>buf_</code>t file_length;
|
||||
little_int32_<code>buf_</code>t version;
|
||||
little_int32_<code>buf_</code>t shape_type;
|
||||
};
|
||||
|
||||
const char* filename = "test.dat";
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
header h;
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check
|
||||
|
||||
h.file_code = 0x01020304;
|
||||
h.file_length = sizeof(header);
|
||||
h.version = 1;
|
||||
h.shape_type = 0x01020304;
|
||||
|
||||
// Low-level I/O such as POSIX read/write or <cstdio>
|
||||
// fread/fwrite is sometimes used for binary file operations
|
||||
// when ultimate efficiency is important. Such I/O is often
|
||||
// performed in some C++ wrapper class, but to drive home the
|
||||
// point that endian integers are often used in fairly
|
||||
// low-level code that does bulk I/O operations, <cstdio>
|
||||
// fopen/fwrite is used for I/O in this example.
|
||||
|
||||
std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
|
||||
|
||||
if (!fi)
|
||||
{
|
||||
std::cout << "could not open " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (std::fwrite(&h, sizeof(header), 1, fi)!= 1)
|
||||
{
|
||||
std::cout << "write failure for " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::fclose(fi);
|
||||
|
||||
std::cout << "created file " << filename << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>After compiling and executing <b><code>example/endian_example.cpp</code></b>,
|
||||
a hex dump of <code>test.dat</code> shows:</p>
|
||||
<blockquote>
|
||||
<pre>01020304 00000010 01000000 04030201</pre>
|
||||
</blockquote>
|
||||
<p>Notice that the first two 32-bit integers are big endian while the second two
|
||||
are little endian, even though the machine this was compiled and run on was
|
||||
little endian.</p>
|
||||
<h2><a name="Limitations">Limitations</a></h2>
|
||||
<p>Requires <code><climits></code> <code>CHAR_BIT == 8</code>. If <code>CHAR_BIT</code>
|
||||
is some other value, compilation will result in an <code>#error</code>. This
|
||||
restriction is in place because the design, implementation, testing, and
|
||||
documentation has only considered issues related to 8-bit bytes, and there have
|
||||
been no real-world use cases presented for other sizes.</p>
|
||||
<p>In C++03, <code>endian_buffer</code> does not meet the requirements for POD types
|
||||
because it has constructors, private data members, and a base class. This means
|
||||
that common use cases are relying on unspecified behavior in that the C++
|
||||
Standard does not guarantee memory layout for non-POD types. This has not been a
|
||||
problem in practice since all known C++ compilers lay out memory as if <code>
|
||||
endian</code> were a POD type. In C++11, it is possible to specify the
|
||||
default constructor as trivial, and private data members and base classes no longer disqualify a type from being a POD
|
||||
type. Thus under C++11, <code>endian_buffer</code>
|
||||
will no longer be relying on unspecified behavior.</p>
|
||||
<h2><a name="Feature-set">Feature set</a></h2>
|
||||
<ul>
|
||||
<li>Big endian| little endian | native endian byte ordering.</li>
|
||||
<li>Signed | unsigned</li>
|
||||
<li>Unaligned | aligned</li>
|
||||
<li>1-8 byte (unaligned) | 1, 2, 4, 8 byte (aligned)</li>
|
||||
<li>Choice of value type</li>
|
||||
</ul>
|
||||
<h2>Enums and t<a name="Types">ypedefs</a></h2>
|
||||
<p>Two scoped enums are provided:</p>
|
||||
<blockquote>
|
||||
<pre>enum class order {big, little, native};
|
||||
|
||||
enum class align {no, yes}; </pre>
|
||||
</blockquote>
|
||||
<p>One class template is provided:</p>
|
||||
<blockquote>
|
||||
<pre>template <order Order, typename T, std::size_t Nbits,
|
||||
align Align = align::no>
|
||||
class endian_buffer;
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>Typedefs, such as <code>big_int32_buf_t</code>, provide convenient naming
|
||||
conventions for common use cases:</p>
|
||||
<blockquote>
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="49%">
|
||||
<tr>
|
||||
<td width="18%" align="center"><b><i>Name</i></b></td>
|
||||
<td width="49%" align="center"><b><i>Alignment</i></b></td>
|
||||
<td width="10%" align="center"><b><i>Endianness</i></b></td>
|
||||
<td width="10%" align="center"><b><i>Sign</i></b></td>
|
||||
<td width="15%" align="center"><b><i>Sizes in bits (n)</i></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%" dir="ltr"><code>big_int</code><b><i>n</i></b><code>_buf_t</code></td>
|
||||
<td width="49%" align="center" dir="ltr"><code>no</code></td>
|
||||
<td width="10%" align="center" dir="ltr"><code>big</code></td>
|
||||
<td width="10%" align="center" dir="ltr">signed</td>
|
||||
<td width="15%" dir="ltr">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%" dir="ltr"><code>big_uint</code><i><b>n</b></i><code>_buf_t</code></td>
|
||||
<td width="49%" align="center" dir="ltr"><code>no</code></td>
|
||||
<td width="10%" align="center" dir="ltr"><code>big</code></td>
|
||||
<td width="10%" align="center" dir="ltr">unsigned</td>
|
||||
<td width="15%" dir="ltr">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>little_int</code><i><b>n</b></i><code>_buf_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>little</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>little_uint</code><i><b>n</b></i><code>_buf_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>little</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>native_int</code><i><b>n</b></i><code>_buf_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>native</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>native_uint</code><i><b>n</b></i><code>_buf_t</code></td>
|
||||
<td width="49%" align="center"><code>no</code></td>
|
||||
<td width="10%" align="center"><code>native</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,24,32,40,48,56,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>big_int</code><i><b>n</b></i><code>_buf_at</code></td>
|
||||
<td width="49%" align="center"><code>yes</code></td>
|
||||
<td width="10%" align="center"><code>big</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,32,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>big_uint</code><i><b>n</b></i><code>_</code><code>buf_at</code></td>
|
||||
<td width="49%" align="center"><code>yes</code></td>
|
||||
<td width="10%" align="center"><code>big</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,32,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>little_int</code><i><b>n</b></i><code>_</code><code>buf_at</code></td>
|
||||
<td width="49%" align="center"><code>yes</code></td>
|
||||
<td width="10%" align="center"><code>little</code></td>
|
||||
<td width="10%" align="center">signed</td>
|
||||
<td width="15%">8,16,32,64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="18%"><code>little_uint</code><i><b>n</b></i><code>_</code><code>buf_at</code></td>
|
||||
<td width="49%" align="center"><code>yes</code></td>
|
||||
<td width="10%" align="center"><code>little</code></td>
|
||||
<td width="10%" align="center">unsigned</td>
|
||||
<td width="15%">8,16,32,64</td>
|
||||
</tr>
|
||||
</table>
|
||||
</blockquote>
|
||||
<p>The unaligned types do not cause compilers to insert padding bytes in classes
|
||||
and structs. This is an important characteristic that can be exploited to minimize wasted space in
|
||||
memory, files, and network transmissions. </p>
|
||||
<p><font color="#FF0000"><b><i><span style="background-color: #FFFFFF">Warning:</span></i></b></font><span style="background-color: #FFFFFF">
|
||||
Code that uses a</span>ligned types is possibly non-portable because alignment
|
||||
requirements vary between hardware architectures and because alignment may be
|
||||
affected by compiler switches or pragmas. For example, alignment of an 64-bit
|
||||
integer may be to a 32-bit boundary on a 32-bit machine and to a 64-bit boundary
|
||||
on a 64-bit machine. Furthermore, aligned types
|
||||
are only available on architectures with 8, 16, 32, and 64-bit integer types. </p>
|
||||
<p><i><b>Recommendation:</b></i> Prefer unaligned buffer types.</p>
|
||||
<p><i><b>Recommendation:</b></i> Protect yourself against alignment ills. For
|
||||
example:</p>
|
||||
<blockquote>
|
||||
<pre>static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong"); </pre>
|
||||
</blockquote>
|
||||
<p><b><i>Note:</i></b> One-byte big and little buffer types
|
||||
have identical layout on all platforms, so they never actually reverse endianness. They are provided to enable generic code, and
|
||||
to improve code readability and searchability.</p>
|
||||
<h2><a name="Class_template_endian">Class template <code>endian</code></a><code>_buffer</code></h2>
|
||||
<p>An <code>endian_buffer</code> is a byte-holder for arithmetic types with user-specified <a href="#endianness">
|
||||
endianness</a>, value type, size, and <a href="#alignment">alignment</a>.</p>
|
||||
<h3><a name="Synopsis">Synopsis</a></h3>
|
||||
<pre>#include <boost/endian/conversion.hpp
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace endian
|
||||
{
|
||||
// C++11 features emulated if not available
|
||||
|
||||
enum class <a name="alignment">align</a> {no, yes};
|
||||
|
||||
template <order Order, class T, std::size_t Nbits,
|
||||
align Align = align::no>
|
||||
class endian_buffer
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
<a href="#endian">endian_buffer</a>() noexcept = default;
|
||||
explicit <a href="#explicit-endian">endian_buffer</a>(T v) noexcept;
|
||||
|
||||
endian_buffer& <a href="#operator-eq">operator=</a>(T v) noexcept;
|
||||
value_type <a href="#value">value</a>() const noexcept;
|
||||
const char* <a href="#data">data</a>() const noexcept;
|
||||
protected:
|
||||
<b><i>implementaton-defined</i></b> endian_value; // for exposition only
|
||||
};
|
||||
|
||||
// stream inserter
|
||||
template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align Align>
|
||||
std::basic_ostream<charT, traits>&
|
||||
<a href="#inserter">operator<<</a>(std::basic_ostream<charT, traits>& os,
|
||||
const endian_buffer<Order, T, n_bits, Align>& x);
|
||||
|
||||
// stream extractor
|
||||
template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align A>
|
||||
std::basic_istream<charT, traits>&
|
||||
<a href="#extractor">operator>></a>(std::basic_istream<charT, traits>& is,
|
||||
endian_buffer<Order, T, n_bits, Align>& x);
|
||||
|
||||
// typedefs
|
||||
|
||||
// unaligned big endian signed integer buffers
|
||||
typedef endian_buffer<order::big, int_least8_t, 8> big_int8_buf_t;
|
||||
typedef endian_buffer<order::big, int_least16_t, 16> big_int16_buf_t;
|
||||
typedef endian_buffer<order::big, int_least32_t, 24> big_int24_buf_t;
|
||||
typedef endian_buffer<order::big, int_least32_t, 32> big_int32_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 40> big_int40_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 48> big_int48_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 56> big_int56_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 64> big_int64_buf_t;
|
||||
|
||||
// unaligned big endian unsigned integer buffers
|
||||
typedef endian_buffer<order::big, uint_least8_t, 8> big_uint8_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least16_t, 16> big_uint16_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least32_t, 24> big_uint24_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least32_t, 32> big_uint32_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 40> big_uint40_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 48> big_uint48_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 56> big_uint56_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 64> big_uint64_buf_t;
|
||||
|
||||
// unaligned little endian signed integer buffers
|
||||
typedef endian_buffer<order::little, int_least8_t, 8> little_int8_buf_t;
|
||||
typedef endian_buffer<order::little, int_least16_t, 16> little_int16_buf_t;
|
||||
typedef endian_buffer<order::little, int_least32_t, 24> little_int24_buf_t;
|
||||
typedef endian_buffer<order::little, int_least32_t, 32> little_int32_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 40> little_int40_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 48> little_int48_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 56> little_int56_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 64> little_int64_buf_t;
|
||||
|
||||
// unaligned little endian unsigned integer buffers
|
||||
typedef endian_buffer<order::little, uint_least8_t, 8> little_uint8_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least16_t, 16> little_uint16_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least32_t, 24> little_uint24_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least32_t, 32> little_uint32_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 40> little_uint40_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 48> little_uint48_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 56> little_uint56_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 64> little_uint64_buf_t;
|
||||
|
||||
// unaligned native endian signed integer types
|
||||
typedef <b><i>implementation-defined</i></b>_int8_buf_t native_int8_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int16_buf_t native_int16_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int24_buf_t native_int24_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int32_buf_t native_int32_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int40_buf_t native_int40_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int48_buf_t native_int48_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int56_buf_t native_int56_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_int64_buf_t native_int64_buf_t;
|
||||
|
||||
// unaligned native endian unsigned integer types
|
||||
typedef <b><i>implementation-defined</i></b>_uint8_buf_t native_uint8_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint16_buf_t native_uint16_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint24_buf_t native_uint24_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint32_buf_t native_uint32_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint40_buf_t native_uint40_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint48_buf_t native_uint48_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint56_buf_t native_uint56_buf_t;
|
||||
typedef <b><i>implementation-defined</i></b>_uint64_buf_t native_uint64_buf_t;
|
||||
|
||||
// aligned big endian signed integer buffers
|
||||
typedef endian_buffer<order::big, int8_t, 8, align::yes> big_int8_buf_at;
|
||||
typedef endian_buffer<order::big, int16_t, 16, align::yes> big_int16_buf_at;
|
||||
typedef endian_buffer<order::big, int32_t, 32, align::yes> big_int32_buf_at;
|
||||
typedef endian_buffer<order::big, int64_t, 64, align::yes> big_int64_buf_at;
|
||||
|
||||
// aligned big endian unsigned integer buffers
|
||||
typedef endian_buffer<order::big, uint8_t, 8, align::yes> big_uint8_buf_at;
|
||||
typedef endian_buffer<order::big, uint16_t, 16, align::yes> big_uint16_buf_at;
|
||||
typedef endian_buffer<order::big, uint32_t, 32, align::yes> big_uint32_buf_at;
|
||||
typedef endian_buffer<order::big, uint64_t, 64, align::yes> big_uint64_buf_at;
|
||||
|
||||
// aligned little endian signed integer buffers
|
||||
typedef endian_buffer<order::little, int8_t, 8, align::yes> little_int8_buf_at;
|
||||
typedef endian_buffer<order::little, int16_t, 16, align::yes> little_int16_buf_at;
|
||||
typedef endian_buffer<order::little, int32_t, 32, align::yes> little_int32_buf_at;
|
||||
typedef endian_buffer<order::little, int64_t, 64, align::yes> little_int64_buf_at;
|
||||
|
||||
// aligned little endian unsigned integer buffers
|
||||
typedef endian_buffer<order::little, uint8_t, 8, align::yes> little_uint8_buf_at;
|
||||
typedef endian_buffer<order::little, uint16_t, 16, align::yes> little_uint16_buf_at;
|
||||
typedef endian_buffer<order::little, uint32_t, 32, align::yes> little_uint32_buf_at;
|
||||
typedef endian_buffer<order::little, uint64_t, 64, align::yes> little_uint64_buf_at;
|
||||
|
||||
// aligned native endian typedefs are not provided because
|
||||
// <cstdint> types are superior for this use case
|
||||
|
||||
} // namespace endian
|
||||
} // namespace boost</pre>
|
||||
<p>The <i><b><code>implementation-defined</code></b></i> text in typedefs above is either
|
||||
<code>big</code> or <code>little</code> according to the native endianness of the
|
||||
platform.</p>
|
||||
<p>The expository data member <code>endian_value</code> stores the current value
|
||||
of an <code>endian_value</code> object as a sequence of bytes ordered as
|
||||
specified by the <code>Order</code> template parameter. The <i><b><code>
|
||||
implementation-defined</code></b></i> type of <code>endian_value</code> is a
|
||||
type such as <code><span style="font-size: 85%">char[Nbits/CHAR_BIT]</span></code>
|
||||
or <code><span style="font-size: 85%">T</span></code> that meets the
|
||||
requirements imposed by the <code>Nbits</code> and <code>Align</code> template
|
||||
parameters. The <code><span style="font-size: 85%">CHAR_BIT</span></code>
|
||||
macro is defined in <code><span style="font-size: 85%"><climits></span></code>.
|
||||
The only value of <code><span style="font-size: 85%">CHAR_BIT</span></code> that
|
||||
is required to be supported is 8.</p>
|
||||
<p>Template parameter <code><span style="font-size: 85%">T</span></code> is
|
||||
required to be a standard integer type (C++std, 3.9.1) and <code>
|
||||
<span style="font-size: 85%">sizeof(T)*CHAR_BIT</span></code> is required to be
|
||||
greater or equal to <span style="font-size: 85%"> <code>Nbits</code>.</span></p>
|
||||
<h3><a name="Members">Members</a></h3>
|
||||
<pre><code><a name="endian">endian</a>_buffer() noexcept = default;</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Effects:</i> Constructs an uninitialized object of type <code>endian_buffer<Order, T,
|
||||
Nbits, Align></code>.</p>
|
||||
</blockquote>
|
||||
<pre><code>explicit <a name="explicit-endian">endian</a>_buffer(T v) noexcept;</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Effects:</i> Constructs an object of type <code>endian_buffer<Order, T,
|
||||
Nbits, Align></code>.</p>
|
||||
<p><i>Postcondition:</i> <code>value() == v & mask</code>, where <code>mask</code>
|
||||
is a constant of type <code>value_type</code> with <code>Nbits</code> low-order
|
||||
bits set to one.</p>
|
||||
<p><i>Remarks:</i> If <code>Align</code> is <code>align::yes</code> then
|
||||
endianness conversion, if required, is performed by <code>
|
||||
boost::endian::endian_reverse</code>.</p>
|
||||
</blockquote>
|
||||
<pre><code>endian_buffer& <a name="operator-eq">operator=</a>(T v) noexcept;</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Postcondition:</i> <code>value() == v & mask</code>, where <code>mask</code>
|
||||
is a constant of type <code>value_type</code> with <code>Nbits</code>
|
||||
low-order bits set to one.</p>
|
||||
<p><i>Returns:</i> <code>*this</code>.</p>
|
||||
<p><i>Remarks:</i> If <code>Align</code> is <code>align::yes</code> then
|
||||
endianness conversion, if required, is performed by <code>
|
||||
boost::endian::endian_reverse</code>.</p>
|
||||
</blockquote>
|
||||
<pre>value_type <a name="value">value</a>()<code> const noexcept;</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>endian_value</code>, converted to <code>value_type</code>,
|
||||
if required, and having the endianness of the native platform.</p>
|
||||
<p><i>Remarks:</i> If <code>Align</code> is <code>align::yes</code> then
|
||||
endianness conversion, if required, is performed by <code>
|
||||
boost::endian::endian_reverse</code>.</p>
|
||||
</blockquote>
|
||||
<pre><code>const char* <a name="data">data</a>() const noexcept;</code></pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> A pointer to the first byte of <code>endian_value</code>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="Non-member-functions">Non-member functions</a></h3>
|
||||
<pre>template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align Align>
|
||||
std::basic_ostream<charT, traits>& <a name="inserter">operator<<</a>(std::basic_ostream<charT, traits>& os,
|
||||
const endian_buffer<Order, T, n_bits, Align>& x);
|
||||
</pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>os << x.value()</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align A>
|
||||
std::basic_istream<charT, traits>& <a name="extractor">operator>></a>(std::basic_istream<charT, traits>& is,
|
||||
endian_buffer<Order, T, n_bits, Align>& x);
|
||||
</pre>
|
||||
<blockquote>
|
||||
<p><i>Effects: </i>As if:</p>
|
||||
<blockquote>
|
||||
<pre>T i;
|
||||
if (is >> i)
|
||||
x = i;
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p><i>Returns:</i> <code>is</code>.</p>
|
||||
</blockquote>
|
||||
<h2><a name="FAQ">FAQ</a></h2>
|
||||
|
||||
<p>See the <a href="index.html#FAQ">Endian home page</a> FAQ for a library-wide
|
||||
FAQ.</p>
|
||||
|
||||
<p><b>Why not just use Boost.Serialization?</b> Serialization involves a
|
||||
conversion for every object involved in I/O. Endian integers require no
|
||||
conversion or copying. They are already in the desired format for binary I/O.
|
||||
Thus they can be read or written in bulk.</p>
|
||||
<p><b>Are endian types PODs?</b> Yes for C++11. No for C++03, although several
|
||||
<a href="#Compilation">macros</a> are available to force PODness in all cases.</p>
|
||||
<p><b>What are the implications of endian integer types not being PODs with C++03
|
||||
compilers?</b> They
|
||||
can't be used in unions. Also, compilers aren't required to align or lay
|
||||
out storage in portable ways, although this potential problem hasn't prevented
|
||||
use of Boost.Endian with
|
||||
real compilers.</p>
|
||||
<p><b>What good is <i>native </i>endianness?</b> It provides alignment and
|
||||
size guarantees not available from the built-in types. It eases generic
|
||||
programming.</p>
|
||||
<p><b>Why bother with the aligned endian types?</b> Aligned integer operations
|
||||
may be faster (as much as 10 to 20 times faster) if the endianness and alignment of
|
||||
the type matches the endianness and alignment requirements of the machine. The code,
|
||||
however, is
|
||||
likely to be somewhat less portable than with the unaligned types.</p>
|
||||
<h2><a name="Design">Design</a> considerations for Boost.Endian buffers</h2>
|
||||
<ul>
|
||||
<li>Must be suitable for I/O - in other words, must be memcpyable.</li>
|
||||
<li>Must provide exactly the size and internal byte ordering specified.</li>
|
||||
<li>Must work correctly when the internal integer representation has more bits
|
||||
that the sum of the bits in the external byte representation. Sign extension
|
||||
must work correctly when the internal integer representation type has more
|
||||
bits than the sum of the bits in the external bytes. For example, using
|
||||
a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
|
||||
both positive and negative values.</li>
|
||||
<li>Must work correctly (including using the same defined external
|
||||
representation) regardless of whether a compiler treats char as signed or
|
||||
unsigned.</li>
|
||||
<li>Unaligned types must not cause compilers to insert padding bytes.</li>
|
||||
<li>The implementation should supply optimizations with great care. Experience has shown that optimizations of endian
|
||||
integers often become pessimizations when changing
|
||||
machines or compilers. Pessimizations can also happen when changing compiler switches,
|
||||
compiler versions, or CPU models of the same architecture.</li>
|
||||
</ul>
|
||||
<h2><a name="C++0x">C++11</a></h2>
|
||||
<p>The availability of the C++11
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
||||
Defaulted Functions</a> feature is detected automatically, and will be used if
|
||||
present to ensure that objects of <code>class endian_buffer</code> are trivial, and
|
||||
thus PODs.</p>
|
||||
<h2><a name="Compilation">Compilation</a></h2>
|
||||
<p>Boost.Endian is implemented entirely within headers, with no need to link to
|
||||
any Boost object libraries.</p>
|
||||
<p>Several macros allow user control over features:</p>
|
||||
<ul>
|
||||
<li>BOOST_ENDIAN_NO_CTORS causes <code>class endian_buffer</code> to have no
|
||||
constructors. The intended use is for compiling user code that must be
|
||||
portable between compilers regardless of C++11
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
||||
Defaulted Functions</a> support. Use of constructors will always fail, <br>
|
||||
</li>
|
||||
<li>BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if
|
||||
the compiler does not support C++11
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">
|
||||
Defaulted Functions</a>. This is ensures that objects of <code>class endian_buffer</code>
|
||||
are PODs, and so can be used in C++03 unions.
|
||||
In C++11, <code>class endian_buffer</code> objects are PODs, even though they have
|
||||
constructors, so can always be used in unions.</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->14 October, 2015<!--webbot bot="Timestamp" endspan i-checksum="38874" --></p>
|
||||
<p>© Copyright Beman Dawes, 2006-2009, 2013</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See
|
||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,412 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Choosing Approach</title>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
|
||||
<tr>
|
||||
<td width="339">
|
||||
<a href="../../../index.html">
|
||||
<img src="../../../boost.png" alt="Boost logo" align="middle" border="0" width="277" height="86"></a></td>
|
||||
<td align="middle" width="1253">
|
||||
<font size="6"><b>Choosing the Approach</b></font></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse"
|
||||
bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
||||
<tr>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p></p>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" align="right">
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#D7EEFF" align="center">
|
||||
<i><b>Contents</b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#E8F5FF">
|
||||
<a href="#Introduction">Introduction</a><br>
|
||||
<a href="#Choosing">Choosing between conversion functions,</a><br>
|
||||
<a href="#Choosing">buffer types, and arithmetic types</a><br>
|
||||
<a href="#Characteristics">Characteristics</a><br>
|
||||
<a href="#Endianness-invariants">Endianness invariants</a><br>
|
||||
<a href="#Conversion-explicitness">Conversion explicitness</a><br>
|
||||
<a href="#Arithmetic-operations">Arithmetic operations</a><br>
|
||||
<a href="#Sizes">Sizes</a><br>
|
||||
<a href="#Alignments">Alignments</a><br>
|
||||
<a href="#Design-patterns">Design patterns</a><br>
|
||||
<a href="#As-needed">Convert only as needed (i.e. lazy)</a><br>
|
||||
<a href="#Anticipating-need">Convert in anticipation of need</a><br>
|
||||
<a href="#Convert-generally-as-needed-locally-in-anticipation">Generally
|
||||
as needed, locally in anticipation</a><br>
|
||||
<a href="#Use-cases">Use case examples</a><br>
|
||||
<a href="#Porting-endian-unaware-codebase">Porting endian unaware codebase</a><br>
|
||||
<a href="#Porting-endian-aware-codebase">Porting endian aware codebase</a><br>
|
||||
<a href="#Reliability-arithmetic-speed">Reliability and arithmetic-speed</a><br>
|
||||
<a href="#Reliability-ease-of-use">Reliability and ease-of-use</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>Deciding which is the best endianness approach (conversion functions, buffer
|
||||
types, or arithmetic types) for a particular application involves complex
|
||||
engineering trade-offs. It is hard to assess those trade-offs without some
|
||||
understanding of the different interfaces, so you might want to read the
|
||||
<a href="conversion.html">conversion functions</a>, <a href="buffers.html">
|
||||
buffer types</a>, and <a href="arithmetic.html">arithmetic types</a> pages
|
||||
before diving into this page.</p>
|
||||
|
||||
<h2><a name="Choosing">Choosing</a> between conversion functions, buffer types,
|
||||
and arithmetic types</h2>
|
||||
|
||||
<p>The best approach to endianness for a particular application depends on the interaction between
|
||||
the application's needs and the characteristics of each of the three approaches.</p>
|
||||
|
||||
<p><b>Recommendation:</b> If you are new to endianness, uncertain, or don't want to invest
|
||||
the time to
|
||||
study
|
||||
engineering trade-offs, use <a href="arithmetic.html">endian arithmetic types</a>. They are safe, easy
|
||||
to use, and easy to maintain. Use the
|
||||
<a href="#Anticipating-need"> <i>
|
||||
anticipating need</i></a> design pattern locally around performance hot spots
|
||||
like lengthy loops, if needed.</p>
|
||||
|
||||
<h3><a name="Background">Background</a> </h3>
|
||||
|
||||
<p>A dealing with endianness usually implies a program portability or a data
|
||||
portability requirement, and often both. That means real programs dealing with
|
||||
endianness are usually complex, so the examples shown here would really be
|
||||
written as multiple functions spread across multiple translation units. They
|
||||
would involve interfaces that can not be altered as they are supplied by
|
||||
third-parties or the standard library. </p>
|
||||
|
||||
<h3><a name="Characteristics">Characteristics</a></h3>
|
||||
|
||||
<p>The characteristics that differentiate the three approaches to endianness are the endianness
|
||||
invariants, conversion explicitness, arithmetic operations, sizes available, and
|
||||
alignment requirements.</p>
|
||||
|
||||
<h4><a name="Endianness-invariants">Endianness invariants</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endian conversion functions</b> use objects of the ordinary C++ arithmetic
|
||||
types like <code>int</code> or <code>unsigned short</code> to hold values. That
|
||||
breaks the implicit invariant that the C++ language rules apply. The usual
|
||||
language rules only apply if the endianness of the object is currently set to the native endianness for the platform. That can
|
||||
make it very hard to reason about logic flow, and result in difficult to
|
||||
find bugs.</p>
|
||||
|
||||
<p>For example:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>struct data_t // big endian
|
||||
{
|
||||
int32_t v1; // description ...
|
||||
int32_t v2; // description ...
|
||||
... additional character data members (i.e. non-endian)
|
||||
int32_t v3; // description ...
|
||||
};
|
||||
|
||||
data_t data;
|
||||
|
||||
read(data);
|
||||
big_to_native_inplace(data.v1);
|
||||
big_to_native_inplace(data.v2);
|
||||
|
||||
...
|
||||
|
||||
++v1;
|
||||
third_party::func(data.v2);
|
||||
|
||||
...
|
||||
|
||||
native_to_big_inplace(data.v1);
|
||||
native_to_big_inplace(data.v2);
|
||||
write(data);
|
||||
</pre>
|
||||
<p>The programmer didn't bother to convert <code>data.v3</code> to native
|
||||
endianness because that member isn't used. A later maintainer needs to pass
|
||||
<code>data.v3</code> to the third-party function, so adds <code>third_party::func(data.v3);</code>
|
||||
somewhere deep in the code. This causes a silent failure because the usual
|
||||
invariant that an object of type <code>int32_t</code> holds a value as
|
||||
described by the C++ core language does not apply.</p>
|
||||
</blockquote>
|
||||
<p><b>Endian buffer and arithmetic types</b> hold values internally as arrays of
|
||||
characters with an invariant that the endianness of the array never changes.
|
||||
That makes these types easier to use and programs easier to maintain. </p>
|
||||
<p>Here is the same example, using an endian arithmetic type:</p>
|
||||
<blockquote>
|
||||
<pre>struct data_t
|
||||
{
|
||||
big_int32_t v1; // description ...
|
||||
big_int32_t v2; // description ...
|
||||
... additional character data members (i.e. non-endian)
|
||||
big_int32_t v3; // description ...
|
||||
};
|
||||
|
||||
data_t data;
|
||||
|
||||
read(data);
|
||||
|
||||
...
|
||||
|
||||
++v1;
|
||||
third_party::func(data.v2);
|
||||
|
||||
...
|
||||
|
||||
write(data);
|
||||
</pre>
|
||||
<p>A later maintainer can add <code>third_party::func(data.v3)</code>and it
|
||||
will just-work.</p>
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="Conversion-explicitness">Conversion explicitness</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endian conversion functions</b> and <b>buffer types</b> never perform
|
||||
implicit conversions. This gives users explicit control of when conversion
|
||||
occurs, and may help avoid unnecessary conversions.</p>
|
||||
|
||||
<p><b>Endian arithmetic types</b> perform conversion implicitly. That makes
|
||||
these types very easy to use, but can result in unnecessary conversions. Failure
|
||||
to hoist conversions out of inner loops can bring a performance penalty.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="Arithmetic-operations">Arithmetic operations</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endian conversion functions</b> do not supply arithmetic
|
||||
operations, but this is not a concern since this approach uses ordinary C++
|
||||
arithmetic types to hold values.</p>
|
||||
|
||||
<p><b>Endian buffer types</b> do not supply arithmetic operations. Although this
|
||||
approach avoids unnecessary conversions, it can result in the introduction of
|
||||
additional variables and confuse maintenance programmers.</p>
|
||||
|
||||
<p><b>Endian</b> <b>arithmetic types</b> do supply arithmetic operations. They
|
||||
are very easy to use if lots of arithmetic is involved. </p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="Sizes">Sizes</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endianness conversion functions</b> only support 1, 2, 4, and 8 byte
|
||||
integers. That's sufficient for many applications.</p>
|
||||
|
||||
<p><b>Endian buffer and arithmetic types</b> support 1, 2, 3, 4, 5, 6, 7, and 8
|
||||
byte integers. For an application where memory use or I/O speed is the limiting
|
||||
factor, using sizes tailored to application needs can be useful.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="Alignments">Alignments</a></h4>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b>Endianness conversion functions</b> only support aligned integer and
|
||||
floating-point types. That's sufficient for most applications.</p>
|
||||
|
||||
<p><b>Endian buffer and arithmetic types</b> support both aligned and unaligned
|
||||
integer and floating-point types. Unaligned types are rarely needed, but when
|
||||
needed they are often very useful and workarounds are painful. For example,</p>
|
||||
|
||||
<blockquote>
|
||||
<p>Non-portable code like this:<blockquote>
|
||||
<pre>struct S {
|
||||
uint16_t a; // big endian
|
||||
uint32_t b; // big endian
|
||||
} __attribute__ ((packed));</pre>
|
||||
</blockquote>
|
||||
<p>Can be replaced with portable code like this:</p>
|
||||
<blockquote>
|
||||
<pre>struct S {
|
||||
big_uint16_ut a;
|
||||
big_uint32_ut b;
|
||||
};</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h3><a name="Design-patterns">Design patterns</a></h3>
|
||||
|
||||
<p>Applications often traffic in endian data as records or packets containing
|
||||
multiple endian data elements. For simplicity, we will just call them records.</p>
|
||||
|
||||
<p>If desired endianness differs from native endianness, a conversion has to be
|
||||
performed. When should that conversion occur? Three design patterns have
|
||||
evolved.</p>
|
||||
|
||||
<h4><a name="As-needed">Convert only as needed</a> (i.e. lazy)</h4>
|
||||
|
||||
<p>This pattern defers conversion to the point in the code where the data
|
||||
element is actually used.</p>
|
||||
|
||||
<p>This pattern is appropriate when which endian element is actually used varies
|
||||
greatly according to record content or other circumstances</p>
|
||||
|
||||
<h4><a name="Anticipating-need">Convert in anticipation of need</a></h4>
|
||||
|
||||
<p>This pattern performs conversion to native endianness in anticipation of use,
|
||||
such as immediately after reading records. If needed, conversion to the output
|
||||
endianness is performed after all possible needs have passed, such as just
|
||||
before writing records.</p>
|
||||
|
||||
<p>One implementation of this pattern is to create a proxy record with
|
||||
endianness converted to native in a read function, and expose only that proxy to
|
||||
the rest of the implementation. If a write function, if needed, handles the
|
||||
conversion from native to the desired output endianness.</p>
|
||||
|
||||
<p>This pattern is appropriate when all endian elements in a record are
|
||||
typically used regardless of record content or other circumstances</p>
|
||||
|
||||
<h4><a name="Convert-generally-as-needed-locally-in-anticipation">Convert
|
||||
only as needed, except locally in anticipation of need</a></h4>
|
||||
|
||||
<p>This pattern in general defers conversion but for specific local needs does
|
||||
anticipatory conversion. Although particularly appropriate when coupled with the endian buffer
|
||||
or arithmetic types, it also works well with the conversion functions.</p>
|
||||
|
||||
<p>Example:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>struct data_t
|
||||
{
|
||||
big_int32_t v1;
|
||||
big_int32_t v2;
|
||||
big_int32_t v3;
|
||||
};
|
||||
|
||||
data_t data;
|
||||
|
||||
read(data);
|
||||
|
||||
...
|
||||
++v1;
|
||||
...
|
||||
|
||||
int32_t v3_temp = data.v3; // hoist conversion out of loop
|
||||
|
||||
for (int32_t i = 0; i < <i><b>large-number</b></i>; ++i)
|
||||
{
|
||||
... <i><b>lengthy computation that accesses </b></i>v3_temp<i><b> many times</b></i> ...
|
||||
}
|
||||
data.v3 = v3_temp;
|
||||
|
||||
write(data);
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p dir="ltr">In general the above pseudo-code leaves conversion up to the endian
|
||||
arithmetic type <code>big_int32_t</code>. But to avoid conversion inside the
|
||||
loop, a temporary is created before the loop is entered, and then used to set
|
||||
the new value of <code>data.v3</code> after the loop is complete.</p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p dir="ltr">Question: Won't the compiler's optimizer hoist the conversion out
|
||||
of the loop anyhow?</p>
|
||||
|
||||
<p dir="ltr">Answer: VC++ 2015 Preview, and probably others, does not, even for
|
||||
a toy test program. Although the savings is small (two register <code>
|
||||
<span style="font-size: 85%">bswap</span></code> instructions), the cost might
|
||||
be significant if the loop is repeated enough times. On the other hand, the
|
||||
program may be so dominated by I/O time that even a lengthy loop will be
|
||||
immaterial.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h3><a name="Use-cases">Use case examples</a></h3>
|
||||
|
||||
<h4><a name="Porting-endian-unaware-codebase">Porting endian unaware codebase</a></h4>
|
||||
|
||||
<p>An existing codebase runs on big endian systems. It does not
|
||||
currently deal with endianness. The codebase needs to be modified so it can run
|
||||
on little endian systems under various operating systems. To ease
|
||||
transition and protect value of existing files, external data will continue to
|
||||
be maintained as big endian.</p>
|
||||
|
||||
<p dir="ltr">The <a href="arithmetic.html">endian
|
||||
arithmetic approach</a> is recommended to meet these needs. A relatively small
|
||||
number of header files dealing with binary I/O layouts need to change types. For
|
||||
example,
|
||||
<code>short</code> or <code>int16_t</code> would change to <code>big_int16_t</code>. No
|
||||
changes are required for <code>.cpp</code> files.</p>
|
||||
|
||||
<h4><a name="Porting-endian-aware-codebase">Porting endian aware codebase</a></h4>
|
||||
|
||||
<p>An existing codebase runs on little-endian Linux systems. It already
|
||||
deals with endianness via
|
||||
<a href="http://man7.org/linux/man-pages/man3/endian.3.html">Linux provided
|
||||
functions</a>. Because of a business merger, the codebase has to be quickly
|
||||
modified for Windows and possibly other operating systems, while still
|
||||
supporting Linux. The codebase is reliable and the programmers are all
|
||||
well-aware of endian issues. </p>
|
||||
|
||||
<p dir="ltr">These factors all argue for an <a href="conversion.html">endian conversion
|
||||
approach</a> that just mechanically changes the calls to <code>htobe32</code>,
|
||||
etc. to <code>boost::endian::native_to_big</code>, etc. and replaces <code><endian.h></code>
|
||||
with <code><boost/endian/conversion.hpp></code>.</p>
|
||||
|
||||
<h4><a name="Reliability-arithmetic-speed">Reliability and arithmetic-speed</a></h4>
|
||||
|
||||
<p>A new, complex, multi-threaded application is to be developed that must run
|
||||
on little endian machines, but do big endian network I/O. The developers believe
|
||||
computational speed for endian variable is critical but have seen numerous bugs
|
||||
result from inability to reason about endian conversion state. They are also
|
||||
worried that future maintenance changes could inadvertently introduce a lot of
|
||||
slow conversions if full-blown endian arithmetic types are used.</p>
|
||||
|
||||
<p>The <a href="buffers.html">endian buffers</a> approach is made-to-order for
|
||||
this use case.</p>
|
||||
|
||||
<h4><a name="Reliability-ease-of-use">Reliability and ease-of-use</a></h4>
|
||||
|
||||
<p>A new, complex, multi-threaded application is to be developed that must run
|
||||
on little endian machines, but do big endian network I/O. The developers believe
|
||||
computational speed for endian variables is <b>not critical</b> but have seen
|
||||
numerous bugs result from inability to reason about endian conversion state.
|
||||
They are also concerned about ease-of-use both during development and long-term
|
||||
maintenance.</p>
|
||||
|
||||
<p>Removing concern about conversion speed and adding concern about ease-of-use
|
||||
tips the balance strongly in favor the <a href="arithmetic.html">endian
|
||||
arithmetic approach</a>.</p>
|
||||
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->19 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38903" --></p>
|
||||
<p>© Copyright Beman Dawes, 2011, 2013, 2014</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See
|
||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,405 +0,0 @@
|
||||
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns="http://www.w3.org/TR/REC-html40">
|
||||
|
||||
<head>
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>Endian Conversion Functions</title>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="../../../index.html">
|
||||
<img src="../../../boost.png" alt="Boost logo" align="middle" border="0" width="277" height="86" ></a></td>
|
||||
<td align="middle">
|
||||
<b>
|
||||
<font size="6">Endian Conversion Functions</font></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
||||
<tr>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p></p>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" align="right">
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#D7EEFF" align="center">
|
||||
<i><b>Contents</b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#E8F5FF">
|
||||
<a href="#Introduction">Introduction</a><br>
|
||||
<a href="#Reference">Reference</a><br>
|
||||
<a href="#Synopsis">Synopsis</a><br>
|
||||
<a href="#Requirements">Requirements</a><br>
|
||||
<code><a href="#EndianReversible">EndianReversible</a></code><br>
|
||||
<a href="#Customization-points">Customization for
|
||||
UDTs</a><br>
|
||||
<a href="#Functions">Functions</a><br>
|
||||
<a href="#FAQ">FAQ</a><br>
|
||||
<a href="#Acknowledgements">Acknowledgements</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>Header <a href="../include/boost/endian/conversion.hpp">boost/endian/conversion.hpp</a>
|
||||
provides byte order reversal and conversion functions that convert objects of
|
||||
the built-in
|
||||
integer types
|
||||
between native, big, or little endian byte
|
||||
ordering. User defined types are also supported.</p>
|
||||
|
||||
<h2><a name="Reference">Reference</a></h2>
|
||||
|
||||
<p>Functions are implemented <code>inline</code> if appropriate.<code> </code>
|
||||
For C++03 compilers, <code> noexcept</code> is
|
||||
elided.
|
||||
Boost scoped enum emulation is used so that the library still works for compilers that do not support scoped enums.</p>
|
||||
|
||||
<h3><a name="Definitions">Definitions</a></h3>
|
||||
<p><b><i>Endianness</i></b> refers to the ordering of bytes within internal or
|
||||
external integers and other arithmetic data. Most-significant byte first is
|
||||
called <b><i>big endian</i></b> ordering. Least-significant byte first is called
|
||||
<b><i>little endian</i></b> ordering. Other orderings are possible and some CPU
|
||||
architectures support both big and little ordering.</p>
|
||||
<blockquote>
|
||||
<p>[<i>Note:</i> The names are derived from
|
||||
<a href="http://en.wikipedia.org/wiki/Jonathan_Swift" title="Jonathan Swift">
|
||||
Jonathan Swift</a>'s satirical novel <i>
|
||||
<a href="http://en.wikipedia.org/wiki/Gulliver's_Travels" title="Gulliver's Travels">
|
||||
Gulliver’s Travels</a></i>, where rival kingdoms opened their soft-boiled eggs
|
||||
at different ends. Wikipedia has an extensive description of
|
||||
<a href="https://en.wikipedia.org/wiki/Endianness">Endianness</a>. <i>—end note</i>]</p>
|
||||
</blockquote>
|
||||
<p>The standard integral types (C++std 3.9.1) except <code>bool</code>
|
||||
are collectively called the <b> <i>endian types</i></b>.</p>
|
||||
|
||||
<h3>
|
||||
Header <code><boost/endian/conversion.hpp></code>
|
||||
<a name="Synopsis">Synopsis</a></h3>
|
||||
|
||||
<pre>#define BOOST_ENDIAN_INTRINSIC_MSG \
|
||||
"<b><font face="Arial"><i>message describing presence or absence of intrinsics</i></font></b>"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace endian
|
||||
{
|
||||
enum class <a name="order">order</a>
|
||||
{
|
||||
native = <b><i>see below,
|
||||
</i></b> big = <b><i>see below</i></b>,
|
||||
little = <b><i>see below</i></b>,
|
||||
<b><i> </i></b>};
|
||||
|
||||
int8_t <a href="#endian_reverse">endian_reverse</a>(int8_t x) noexcept;
|
||||
int16_t <a href="#endian_reverse">endian_reverse</a>(int16_t x) noexcept;
|
||||
int32_t <a href="#endian_reverse">endian_reverse</a>(int32_t x) noexcept;
|
||||
int64_t <a href="#endian_reverse">endian_reverse</a>(int64_t x) noexcept;
|
||||
uint8_t <a href="#endian_reverse">endian_reverse</a>(uint8_t x) noexcept;
|
||||
uint16_t <a href="#endian_reverse">endian_reverse</a>(uint16_t x) noexcept;
|
||||
uint32_t <a href="#endian_reverse">endian_reverse</a>(uint32_t x) noexcept;
|
||||
uint64_t <a href="#endian_reverse">endian_reverse</a>(uint64_t x) noexcept;
|
||||
|
||||
template <class EndianReversible>
|
||||
EndianReversible big_to_native(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible native_to_big(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible little_to_native(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible native_to_little(EndianReversible x) noexcept;
|
||||
template <order O1, order O2, class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x,
|
||||
order order1, order order2) noexcept;
|
||||
|
||||
template <class EndianReversible>
|
||||
void endian_reverse_inplace(EndianReversible& x) noexcept;
|
||||
|
||||
template <class EndianReversibleInplace>
|
||||
void big_to_native_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void native_to_big_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void little_to_native_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void native_to_little_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <order O1, order O2, class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x,
|
||||
order order1, order order2) noexcept;
|
||||
|
||||
} // namespace endian
|
||||
} // namespace boost</pre>
|
||||
<p>The values of <code>order::little</code> and <code>order::big</code> shall
|
||||
not be equal to one another. </p>
|
||||
<p><a name="native-order-specification"></a>The value of <code>order::native</code>
|
||||
shall be:</p>
|
||||
<ul>
|
||||
<li>equal to <code>order::big</code> if the execution environment is big
|
||||
endian, otherwise</li>
|
||||
<li>equal to <code>order::little</code> if the execution environment is little
|
||||
endian, otherwise</li>
|
||||
<li>unequal to both <code>order::little</code> and <code>order::big</code>.</li>
|
||||
</ul>
|
||||
<h3><a name="Requirements">Requirements</a></h3>
|
||||
<h4><a name="Template-argument-requirements">Template argument requirements</a></h4>
|
||||
<p>The template definitions in the <code>boost/endian/conversion.hpp</code>
|
||||
header refer to various named requirements whose details are set out in the
|
||||
tables in this subsection. In these tables, <code>T</code> is an object or
|
||||
reference type to be supplied by a C++ program instantiating a template; <code>x</code>
|
||||
is a value of type (possibly <code>const</code>) <code>T</code>; <code>mlx</code> is a
|
||||
modifiable lvalue of type <code>T</code>.</p>
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="3" align="center"><b><code><a name="EndianReversible">EndianReversible</a></code></b>
|
||||
requirements (in addition to <b><code>CopyConstructible</code></b>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Expression</b></td>
|
||||
<td><b>Return<br>
|
||||
type</b></td>
|
||||
<td><b>Requirements</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>endian_reverse(x)</code></td>
|
||||
<td align="center" valign="top"><code>T</code></td>
|
||||
<td> <code>T</code> is an endian type or a class type.<p>If <code>T</code> is
|
||||
an endian type, returns the value of <code>x</code> with the order of bytes
|
||||
reversed.</p>
|
||||
<p>If <code>T</code> is a class type, the function:</p>
|
||||
<ul>
|
||||
<li>Returns the value of <code>x</code>
|
||||
with the order of bytes reversed for all data members of types or arrays of
|
||||
types that meet the <code>EndianReversible</code> requirements, and;</li>
|
||||
<li>Is a non-member function in the same namespace as <code>T</code> that
|
||||
can be found by argument dependent lookup (ADL). </li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p> </p>
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="2" align="center"><b><code><a name="EndianReversibleInplace">EndianReversibleInplace</a></code></b>
|
||||
requirements (in addition to <b><code>CopyConstructible</code></b>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Expression</b></td>
|
||||
<td><b>Requirements</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>endian_reverse_inplace(mlx)</code></td>
|
||||
<td> <code>T</code> is an endian type or a class type.<p>If <code>T</code> is
|
||||
an endian type, reverses the order of bytes in <code>mlx</code>.</p>
|
||||
<p>If <code>T</code> is a class type, the function:</p>
|
||||
<ul>
|
||||
<li>Reverses the order of bytes of all data members of <code>mlx</code>
|
||||
that have types or arrays of
|
||||
types that meet the <code>EndianReversible</code> or <code>EndianReversibleInplace</code>
|
||||
requirements, and;</li>
|
||||
<li>Is a non-member function in the same namespace as <code>T</code> that
|
||||
can be found by argument dependent lookup (ADL). </li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> [<i>Note:</i> Because there is a function template for <code>endian_reverse_inplace</code>
|
||||
that calls <code>endian_reverse</code>, only <code>endian_reverse</code>
|
||||
is required for a user-defined type to meet the <code>EndianReversibleInplace</code>
|
||||
requirements. Although User-defined types are not required to supply an <code>endian_reverse_inplace</code>
|
||||
function, doing so may improve efficiency. <i> —end note</i>]</p>
|
||||
|
||||
<h4> <a name="Customization-points">Customization points</a> for user-defined types (<a name="UDT">UDT</a>s)</h4>
|
||||
|
||||
<p> This subsection describes requirements on the Endian library's implementation.</p>
|
||||
|
||||
<p> The library's function templates requiring <code>
|
||||
<a href="#EndianReversible">EndianReversible</a></code> are
|
||||
required to perform reversal of endianness if needed by making an unqualified
|
||||
call to <code>endian_reverse()</code>.</p>
|
||||
|
||||
<p> The library's function templates requiring <code>
|
||||
<a href="#EndianReversibleInplace">EndianReversibleInplace</a></code> are required to perform reversal of endianness if needed by making an
|
||||
unqualified call to <code>endian_reverse_inplace()</code>.</p>
|
||||
|
||||
<p> See <b><code>example/udt_conversion_example.cpp</code></b> for an example user-defined type.</p>
|
||||
|
||||
<h3><a name="Functions">Functions</a></h3>
|
||||
<pre><a name="endian_reverse"></a>int8_t endian_reverse(int8_t x) noexcept;
|
||||
int16_t endian_reverse(int16_t x) noexcept;
|
||||
int32_t endian_reverse(int32_t x) noexcept;
|
||||
int64_t endian_reverse(int64_t x) noexcept;
|
||||
uint8_t endian_reverse(uint8_t x) noexcept;
|
||||
uint16_t endian_reverse(uint16_t x) noexcept;
|
||||
uint32_t endian_reverse(uint32_t x) noexcept;
|
||||
uint64_t endian_reverse(uint64_t x) noexcept;</pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <i><code>x</code></i>, with the order of its
|
||||
constituent bytes reversed.</p>
|
||||
<p><i>Remarks:</i> The type of <i><code>x</code></i> meets the <code>EndianReversible</code> requirements.</p>
|
||||
<p>[<i>Note:</i> The Boost.Endian library does not provide overloads for the C++ standard library
|
||||
supplied types. <i>—end note</i>]</p>
|
||||
</blockquote>
|
||||
|
||||
<pre>template <class EndianReversible>
|
||||
EndianReversible big_to_native(EndianReversible x) noexcept;</pre>
|
||||
<blockquote>
|
||||
<p>
|
||||
<i>Returns:</i> <code>conditional_reverse<order::big, order::native>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversible>
|
||||
EndianReversible native_to_big(EndianReversible x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>conditional_reverse<order::native, order::big>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversible>
|
||||
EndianReversible little_to_native(EndianReversible x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>conditional_reverse<order::little, order::native>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversible>
|
||||
EndianReversible native_to_little(EndianReversible x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>conditional_reverse<order::native, order::little>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <order O1, order O2, class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>x</code> if <code>O1 == O2,</code> otherwise <code>endian_reverse(x)</code>.</p>
|
||||
<p><i>Remarks: </i>Whether <code>x</code> or <code>endian_reverse(x)</code> is to be returned shall be determined at compile time.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x,
|
||||
order order1, order order2) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p><i>Returns:</i> <code>order1 == order2 ? x : endian_reverse(x)</code>.</p>
|
||||
</blockquote>
|
||||
|
||||
<pre>template <class EndianReversible>
|
||||
void endian_reverse_inplace(EndianReversible& x) noexcept; </pre>
|
||||
|
||||
<blockquote>
|
||||
<p><i>Effects:</i> <code>x</code> <code>= endian_reverse(x)</code>.</p>
|
||||
</blockquote>
|
||||
|
||||
<pre>template <class EndianReversibleInplace>
|
||||
void big_to_native_inplace(EndianReversibleInplace& x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p>
|
||||
<i>Effects:</i> <code>conditional_reverse_inplace<order::big, order::native>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversibleInplace>
|
||||
void native_to_big_inplace(EndianReversibleInplace& x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p>
|
||||
<i>Effects:</i> <code>conditional_reverse_inplace<order::native, order::big>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversibleInplace>
|
||||
void little_to_native_inplace(EndianReversibleInplace& x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p>
|
||||
<i>Effects:</i> <code>conditional_reverse_inplace<order::little, order::native>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversibleInplace>
|
||||
void native_to_little_inplace(EndianReversibleInplace& x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p>
|
||||
<i>Effects:</i> <code>conditional_reverse_inplace<order::native, order::little>(x)</code>.</p>
|
||||
</blockquote>
|
||||
<pre>template <order O1, order O2, class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept; </pre>
|
||||
<blockquote>
|
||||
<p><i>Effects:</i> None if <code>O1 == O2,</code> otherwise <code>endian_reverse_inplace(x)</code>.</p>
|
||||
<p><i>Remarks: </i>Which effect applies shall be determined at compile time.</p>
|
||||
</blockquote>
|
||||
<pre>template <class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x,
|
||||
order order1, order order2) noexcept; </pre>
|
||||
|
||||
|
||||
<blockquote>
|
||||
<p><i>Effects: </i>If <code>order1 == order2</code> then <code>endian_reverse_inplace(x)</code>.</p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
<h2> <a name="FAQ">FAQ</a></h2>
|
||||
|
||||
<p>See the <a href="index.html#FAQ">Endian home page</a> FAQ for a library-wide
|
||||
FAQ.</p>
|
||||
|
||||
<p><b>Why are both value returning and modify-in-place functions provided?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>Returning the result by value is the standard C and C++ idiom for functions that compute a
|
||||
value from an argument. Modify-in-place functions allow cleaner code in many real-world
|
||||
endian use cases and are more efficient for user-defined types that have
|
||||
members such as string data that do not need to be reversed. Thus both forms are
|
||||
provided.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p><b>Why are exact-length 8, 16, 32, and 64-bit integers supported rather than the built-in
|
||||
char, short, int, long, long long, etc?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>The primary use case, portable file or network data, needs these de facto
|
||||
standard sizes. Using types that vary with the platform would greatly limit
|
||||
portability for both programs and data.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p><b>Why not use the Linux names (htobe16, htole16, be16toh, le16toh, etc.) ?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>Those names are non-standard and vary even between POSIX-like operating
|
||||
systems. A C++ library TS was going to use those names, but found they were
|
||||
sometimes implemented as macros. Since macros do not respect scoping and
|
||||
namespace rules, to use them would be very error prone.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h2><a name="Acknowledgements">Acknowledgements</a></h2><p>Tomas Puverle was instrumental
|
||||
in identifying and articulating the need to support endian conversion as separate from
|
||||
endian integer types. Phil Endecott suggested the form of the value returning signatures.
|
||||
Vicente Botet and other reviewers suggested supporting user defined types.
|
||||
General reverse template implementation approach using std::reverse suggested by Mathias Gaunard.
|
||||
Portable implementation approach for 16, 32, and 64-bit integers suggested by tymofey,
|
||||
with avoidance of undefined behavior as suggested by Giovanni Piero Deretta,
|
||||
and a further refinement suggested by Pyry Jahkola.
|
||||
Intrinsic builtins implementation approach for 16, 32, and 64-bit integers suggested by
|
||||
several reviewers, and by David Stone, who provided his Boost licensed macro implementation
|
||||
that became the starting point for <b><code>boost/endian/detail/intrinsic.hpp</code></b>.
|
||||
Pierre Talbot provided the <code>int8_t endian_reverse()</code> and templated
|
||||
<code>endian_reverse_inplace()</code> implementations.</p>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->14 October, 2015<!--webbot bot="Timestamp" endspan i-checksum="38874" --></p>
|
||||
<p>© Copyright Beman Dawes, 2011, 2013</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
4
doc/endian-docinfo-footer.html
Normal file
4
doc/endian-docinfo-footer.html
Normal file
@ -0,0 +1,4 @@
|
||||
<style>
|
||||
*:not(pre)>code { background: none; color: #600000; }
|
||||
table tr.even, table tr.alt, table tr:nth-of-type(even) { background: none; }
|
||||
</style>
|
40
doc/endian.adoc
Normal file
40
doc/endian.adoc
Normal file
@ -0,0 +1,40 @@
|
||||
////
|
||||
Copyright 2019 Glen Joseph Fernandes
|
||||
(glenjofe@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
////
|
||||
|
||||
# Boost.Endian: The Boost Endian Library
|
||||
Beman Dawes
|
||||
:toc: left
|
||||
:toclevels: 2
|
||||
:idprefix:
|
||||
:listing-caption: Code Example
|
||||
:docinfo: private-footer
|
||||
|
||||
:leveloffset: +1
|
||||
|
||||
include::endian/overview.adoc[]
|
||||
|
||||
include::endian/conversion.adoc[]
|
||||
|
||||
include::endian/arithmetic.adoc[]
|
||||
|
||||
include::endian/buffers.adoc[]
|
||||
|
||||
include::endian/choosing_approach.adoc[]
|
||||
|
||||
include::endian/mini_review_topics.adoc[]
|
||||
|
||||
:leveloffset: -1
|
||||
|
||||
[appendix]
|
||||
## Copyright and License
|
||||
|
||||
This documentation is
|
||||
|
||||
* Copyright 2011-2016 Beman Dawes
|
||||
|
||||
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
|
574
doc/endian/arithmetic.adoc
Normal file
574
doc/endian/arithmetic.adoc
Normal file
@ -0,0 +1,574 @@
|
||||
////
|
||||
Copyright 2011-2016 Beman Dawes
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
////
|
||||
|
||||
[#arithmetic]
|
||||
# Endian Arithmetic Types
|
||||
|
||||
## Introduction
|
||||
|
||||
Header `boost/endian/arithmetic.hpp` provides integer binary types with
|
||||
control over byte order, value type, size, and alignment. Typedefs provide
|
||||
easy-to-use names for common configurations.
|
||||
|
||||
These types provide portable byte-holders for integer data, independent of
|
||||
particular computer architectures. Use cases almost always involve I/O, either
|
||||
via files or network connections. Although data portability is the primary
|
||||
motivation, these integer byte-holders may also be used to reduce memory use,
|
||||
file size, or network activity since they provide binary integer sizes not
|
||||
otherwise available.
|
||||
|
||||
Such integer byte-holder types are traditionally called *endian* types. See the
|
||||
http://en.wikipedia.org/wiki/Endian[Wikipedia] for a full exploration of
|
||||
*endianness*, including definitions of *big endian* and *little endian*.
|
||||
|
||||
Boost endian integers provide the same full set of {cpp} assignment, arithmetic,
|
||||
and relational operators as {cpp} standard integral types, with the standard
|
||||
semantics.
|
||||
|
||||
Unary arithmetic operators are `+`, `-`, `~`, `!`, plus both prefix and postfix
|
||||
`--` and `++`. Binary arithmetic operators are `+`, `+=`, `-`, `-=`, `\*`,
|
||||
``*=``, `/`, `/=`, `&`, `&=`, `|`, `|=`, `^`, `^=`, `<<`, `<\<=`, `>>`, and
|
||||
`>>=`. Binary relational operators are `==`, `!=`, `<`, `<=`, `>`, and `>=`.
|
||||
|
||||
Implicit conversion to the underlying value type is provided. An implicit
|
||||
constructor converting from the underlying value type is provided.
|
||||
|
||||
## Example
|
||||
The `endian_example.cpp` program writes a binary file containing four-byte,
|
||||
big-endian and little-endian integers:
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <boost/endian/arithmetic.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
using namespace boost::endian;
|
||||
|
||||
namespace
|
||||
{
|
||||
// This is an extract from a very widely used GIS file format.
|
||||
// Why the designer decided to mix big and little endians in
|
||||
// the same file is not known. But this is a real-world format
|
||||
// and users wishing to write low level code manipulating these
|
||||
// files have to deal with the mixed endianness.
|
||||
|
||||
struct header
|
||||
{
|
||||
big_int32_t file_code;
|
||||
big_int32_t file_length;
|
||||
little_int32_t version;
|
||||
little_int32_t shape_type;
|
||||
};
|
||||
|
||||
const char* filename = "test.dat";
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
header h;
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check
|
||||
|
||||
h.file_code = 0x01020304;
|
||||
h.file_length = sizeof(header);
|
||||
h.version = 1;
|
||||
h.shape_type = 0x01020304;
|
||||
|
||||
// Low-level I/O such as POSIX read/write or <cstdio>
|
||||
// fread/fwrite is sometimes used for binary file operations
|
||||
// when ultimate efficiency is important. Such I/O is often
|
||||
// performed in some C++ wrapper class, but to drive home the
|
||||
// point that endian integers are often used in fairly
|
||||
// low-level code that does bulk I/O operations, <cstdio>
|
||||
// fopen/fwrite is used for I/O in this example.
|
||||
|
||||
std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
|
||||
|
||||
if (!fi)
|
||||
{
|
||||
std::cout << "could not open " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (std::fwrite(&h, sizeof(header), 1, fi)!= 1)
|
||||
{
|
||||
std::cout << "write failure for " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::fclose(fi);
|
||||
|
||||
std::cout << "created file " << filename << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
After compiling and executing `endian_example.cpp`, a hex dump of `test.dat`
|
||||
shows:
|
||||
|
||||
```
|
||||
01020304 00000010 01000000 04030201
|
||||
```
|
||||
|
||||
Notice that the first two 32-bit integers are big endian while the second two
|
||||
are little endian, even though the machine this was compiled and run on was
|
||||
little endian.
|
||||
|
||||
## Limitations
|
||||
|
||||
Requires `<climits>`, `CHAR_BIT == 8`. If `CHAR_BIT` is some other value,
|
||||
compilation will result in an `#error`. This restriction is in place because the
|
||||
design, implementation, testing, and documentation has only considered issues
|
||||
related to 8-bit bytes, and there have been no real-world use cases presented
|
||||
for other sizes.
|
||||
|
||||
In {cpp}03, `endian_arithmetic` does not meet the requirements for POD types
|
||||
because it has constructors, private data members, and a base class. This means
|
||||
that common use cases are relying on unspecified behavior in that the {cpp}
|
||||
Standard does not guarantee memory layout for non-POD types. This has not been a
|
||||
problem in practice since all known {cpp} compilers lay out memory as if
|
||||
`endian` were a POD type. In {cpp}11, it is possible to specify the default
|
||||
constructor as trivial, and private data members and base classes no longer
|
||||
disqualify a type from being a POD type. Thus under {cpp}11, `endian_arithmetic`
|
||||
will no longer be relying on unspecified behavior.
|
||||
|
||||
## Feature set
|
||||
|
||||
* Big endian| little endian | native endian byte ordering.
|
||||
* Signed | unsigned
|
||||
* Unaligned | aligned
|
||||
* 1-8 byte (unaligned) | 1, 2, 4, 8 byte (aligned)
|
||||
* Choice of value type
|
||||
|
||||
## Enums and typedefs
|
||||
|
||||
Two scoped enums are provided:
|
||||
|
||||
```
|
||||
enum class order {big, little, native};
|
||||
|
||||
enum class align {no, yes};
|
||||
```
|
||||
|
||||
One class template is provided:
|
||||
|
||||
```
|
||||
template <order Order, typename T, std::size_t n_bits,
|
||||
align Align = align::no>
|
||||
class endian_arithmetic;
|
||||
```
|
||||
|
||||
Typedefs, such as `big_int32_t`, provide convenient naming conventions for
|
||||
common use cases:
|
||||
|
||||
[%header,cols=5*]
|
||||
|===
|
||||
|Name |Alignment |Endianness |Sign |Sizes in bits (n)
|
||||
|big_intn_t |no |big |signed |8,16,24,32,40,48,56,64
|
||||
|big_uintn_t |no |big |unsigned |8,16,24,32,40,48,56,64
|
||||
|little_intn_t |no |little |signed |8,16,24,32,40,48,56,64
|
||||
|little_uintn_t |no |little |unsigned |8,16,24,32,40,48,56,64
|
||||
|native_intn_t |no |native |signed |8,16,24,32,40,48,56,64
|
||||
|native_uintn_t |no |native |unsigned |8,16,24,32,40,48,56,64
|
||||
|big_intn_at |yes |big |signed |8,16,32,64
|
||||
|big_uintn_at |yes |big |unsigned |8,16,32,64
|
||||
|little_intn_at |yes |little |signed |8,16,32,64
|
||||
|little_uintn_at |yes |little |unsigned |8,16,32,64
|
||||
|===
|
||||
|
||||
The unaligned types do not cause compilers to insert padding bytes in classes
|
||||
and structs. This is an important characteristic that can be exploited to
|
||||
minimize wasted space in memory, files, and network transmissions.
|
||||
|
||||
CAUTION: Code that uses aligned types is possibly non-portable because
|
||||
alignment requirements vary between hardware architectures and because
|
||||
alignment may be affected by compiler switches or pragmas. For example,
|
||||
alignment of an 64-bit integer may be to a 32-bit boundary on a 32-bit machine.
|
||||
Furthermore, aligned types are only available on architectures with 8, 16, 32,
|
||||
and 64-bit integer types.
|
||||
|
||||
TIP: Prefer unaligned arithmetic types.
|
||||
|
||||
TIP: Protect yourself against alignment ills. For example:
|
||||
[none]
|
||||
{blank}::
|
||||
+
|
||||
```
|
||||
static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong");
|
||||
```
|
||||
|
||||
NOTE: One-byte arithmetic types have identical layout on all platforms, so they
|
||||
never actually reverse endianness. They are provided to enable generic code,
|
||||
and to improve code readability and searchability.
|
||||
|
||||
## Class template `endian_arithmetic`
|
||||
|
||||
An `endian_integer` is an integer byte-holder with user-specified
|
||||
<<arithmetic_endianness,endianness>>, value type, size, and
|
||||
<<arithmetic_alignment,alignment>>. The usual operations on arithmetic types
|
||||
are supplied.
|
||||
|
||||
### Synopsis
|
||||
|
||||
```
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/endian/buffers.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace endian
|
||||
{
|
||||
// C++11 features emulated if not available
|
||||
|
||||
enum class align {no, yes};
|
||||
|
||||
template <order Order, class T, std::size_t n_bits,
|
||||
align Align = align::no>
|
||||
class endian_arithmetic
|
||||
: public endian_buffer<Order, T, n_bits, Align>
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
// if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 PODs are not
|
||||
// available then these two constructors will not be present
|
||||
endian_arithmetic() noexcept = default;
|
||||
endian_arithmetic(T v) noexcept;
|
||||
|
||||
endian_arithmetic& operator=(T v) noexcept;
|
||||
operator value_type() const noexcept;
|
||||
value_type value() const noexcept; // for exposition; see endian_buffer
|
||||
const char* data() const noexcept; // for exposition; see endian_buffer
|
||||
|
||||
// arithmetic operations
|
||||
// note that additional operations are provided by the value_type
|
||||
value_type operator+(const endian& x) noexcept;
|
||||
endian& operator+=(endian& x, value_type y) noexcept;
|
||||
endian& operator-=(endian& x, value_type y) noexcept;
|
||||
endian& operator*=(endian& x, value_type y) noexcept;
|
||||
endian& operator/=(endian& x, value_type y) noexcept;
|
||||
endian& operator%=(endian& x, value_type y) noexcept;
|
||||
endian& operator&=(endian& x, value_type y) noexcept;
|
||||
endian& operator|=(endian& x, value_type y) noexcept;
|
||||
endian& operator^=(endian& x, value_type y) noexcept;
|
||||
endian& operator<<=(endian& x, value_type y) noexcept;
|
||||
endian& operator>>=(endian& x, value_type y noexcept;
|
||||
value_type operator<<(const endian& x, value_type y) noexcept;
|
||||
value_type operator>>(const endian& x, value_type y) noexcept;
|
||||
endian& operator++(endian& x) noexcept;
|
||||
endian& operator--(endian& x) noexcept;
|
||||
endian operator++(endian& x, int) noexcept;
|
||||
endian operator--(endian& x, int) noexcept;
|
||||
|
||||
// Stream inserter
|
||||
template <class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const T& x);
|
||||
|
||||
// Stream extractor
|
||||
template <class charT, class traits>
|
||||
friend std::basic_istream<charT, traits>&
|
||||
operator>>(std::basic_istream<charT, traits>& is, T& x);
|
||||
};
|
||||
|
||||
// typedefs
|
||||
|
||||
// unaligned big endian signed integer types
|
||||
typedef endian<order::big, int_least8_t, 8> big_int8_t;
|
||||
typedef endian<order::big, int_least16_t, 16> big_int16_t;
|
||||
typedef endian<order::big, int_least32_t, 24> big_int24_t;
|
||||
typedef endian<order::big, int_least32_t, 32> big_int32_t;
|
||||
typedef endian<order::big, int_least64_t, 40> big_int40_t;
|
||||
typedef endian<order::big, int_least64_t, 48> big_int48_t;
|
||||
typedef endian<order::big, int_least64_t, 56> big_int56_t;
|
||||
typedef endian<order::big, int_least64_t, 64> big_int64_t;
|
||||
|
||||
// unaligned big endian unsigned integer types
|
||||
typedef endian<order::big, uint_least8_t, 8> big_uint8_t;
|
||||
typedef endian<order::big, uint_least16_t, 16> big_uint16_t;
|
||||
typedef endian<order::big, uint_least32_t, 24> big_uint24_t;
|
||||
typedef endian<order::big, uint_least32_t, 32> big_uint32_t;
|
||||
typedef endian<order::big, uint_least64_t, 40> big_uint40_t;
|
||||
typedef endian<order::big, uint_least64_t, 48> big_uint48_t;
|
||||
typedef endian<order::big, uint_least64_t, 56> big_uint56_t;
|
||||
typedef endian<order::big, uint_least64_t, 64> big_uint64_t;
|
||||
|
||||
// unaligned little endian signed integer types
|
||||
typedef endian<order::little, int_least8_t, 8> little_int8_t;
|
||||
typedef endian<order::little, int_least16_t, 16> little_int16_t;
|
||||
typedef endian<order::little, int_least32_t, 24> little_int24_t;
|
||||
typedef endian<order::little, int_least32_t, 32> little_int32_t;
|
||||
typedef endian<order::little, int_least64_t, 40> little_int40_t;
|
||||
typedef endian<order::little, int_least64_t, 48> little_int48_t;
|
||||
typedef endian<order::little, int_least64_t, 56> little_int56_t;
|
||||
typedef endian<order::little, int_least64_t, 64> little_int64_t;
|
||||
|
||||
// unaligned little endian unsigned integer types
|
||||
typedef endian<order::little, uint_least8_t, 8> little_uint8_t;
|
||||
typedef endian<order::little, uint_least16_t, 16> little_uint16_t;
|
||||
typedef endian<order::little, uint_least32_t, 24> little_uint24_t;
|
||||
typedef endian<order::little, uint_least32_t, 32> little_uint32_t;
|
||||
typedef endian<order::little, uint_least64_t, 40> little_uint40_t;
|
||||
typedef endian<order::little, uint_least64_t, 48> little_uint48_t;
|
||||
typedef endian<order::little, uint_least64_t, 56> little_uint56_t;
|
||||
typedef endian<order::little, uint_least64_t, 64> little_uint64_t;
|
||||
|
||||
// unaligned native endian signed integer types
|
||||
typedef implementation-defined_int8_t native_int8_t;
|
||||
typedef implementation-defined_int16_t native_int16_t;
|
||||
typedef implementation-defined_int24_t native_int24_t;
|
||||
typedef implementation-defined_int32_t native_int32_t;
|
||||
typedef implementation-defined_int40_t native_int40_t;
|
||||
typedef implementation-defined_int48_t native_int48_t;
|
||||
typedef implementation-defined_int56_t native_int56_t;
|
||||
typedef implementation-defined_int64_t native_int64_t;
|
||||
|
||||
// unaligned native endian unsigned integer types
|
||||
typedef implementation-defined_uint8_t native_uint8_t;
|
||||
typedef implementation-defined_uint16_t native_uint16_t;
|
||||
typedef implementation-defined_uint24_t native_uint24_t;
|
||||
typedef implementation-defined_uint32_t native_uint32_t;
|
||||
typedef implementation-defined_uint40_t native_uint40_t;
|
||||
typedef implementation-defined_uint48_t native_uint48_t;
|
||||
typedef implementation-defined_uint56_t native_uint56_t;
|
||||
typedef implementation-defined_uint64_t native_uint64_t;
|
||||
|
||||
// aligned big endian signed integer types
|
||||
typedef endian<order::big, int8_t, 8, align::yes> big_int8_at;
|
||||
typedef endian<order::big, int16_t, 16, align::yes> big_int16_at;
|
||||
typedef endian<order::big, int32_t, 32, align::yes> big_int32_at;
|
||||
typedef endian<order::big, int64_t, 64, align::yes> big_int64_at;
|
||||
|
||||
// aligned big endian unsigned integer types
|
||||
typedef endian<order::big, uint8_t, 8, align::yes> big_uint8_at;
|
||||
typedef endian<order::big, uint16_t, 16, align::yes> big_uint16_at;
|
||||
typedef endian<order::big, uint32_t, 32, align::yes> big_uint32_at;
|
||||
typedef endian<order::big, uint64_t, 64, align::yes> big_uint64_at;
|
||||
|
||||
// aligned little endian signed integer types
|
||||
typedef endian<order::little, int8_t, 8, align::yes> little_int8_at;
|
||||
typedef endian<order::little, int16_t, 16, align::yes> little_int16_at;
|
||||
typedef endian<order::little, int32_t, 32, align::yes> little_int32_at;
|
||||
typedef endian<order::little, int64_t, 64, align::yes> little_int64_at;
|
||||
|
||||
// aligned little endian unsigned integer types
|
||||
typedef endian<order::little, uint8_t, 8, align::yes> little_uint8_at;
|
||||
typedef endian<order::little, uint16_t, 16, align::yes> little_uint16_at;
|
||||
typedef endian<order::little, uint32_t, 32, align::yes> little_uint32_at;
|
||||
typedef endian<order::little, uint64_t, 64, align::yes> little_uint64_at;
|
||||
|
||||
// aligned native endian typedefs are not provided because
|
||||
// <cstdint> types are superior for that use case
|
||||
|
||||
} // namespace endian
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
The `implementation-defined` text above is either `big` or `little` according
|
||||
to the endianness of the platform.
|
||||
|
||||
### Members
|
||||
|
||||
```
|
||||
endian() = default; // C++03: endian(){}
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: Constructs an uninitialized object of type
|
||||
`endian_arithmetic<E, T, n_bits, A>`.
|
||||
|
||||
```
|
||||
endian(T v);
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: Constructs an object of type `endian_arithmetic<E, T, n_bits, A>`.
|
||||
Postcondition:: `x == v,` where `x` is the constructed object.
|
||||
|
||||
```
|
||||
endian& operator=(T v);
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Postcondition:: `x == v,` where `x` is the constructed object.
|
||||
Returns:: `*this`.
|
||||
|
||||
```
|
||||
operator T() const;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: The current value stored in `*this`, converted to `value_type`.
|
||||
|
||||
```
|
||||
const char* data() const;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: A pointer to the first byte of the endian binary value stored in
|
||||
`*this`.
|
||||
|
||||
### Other operators
|
||||
|
||||
Other operators on endian objects are forwarded to the equivalent operator on
|
||||
`value_type`.
|
||||
|
||||
### Stream inserter
|
||||
|
||||
```
|
||||
template <class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const T& x);
|
||||
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `os << +x`.
|
||||
[none]
|
||||
|
||||
### Stream extractor
|
||||
|
||||
```
|
||||
template <class charT, class traits>
|
||||
friend std::basic_istream<charT, traits>&
|
||||
operator>>(std::basic_istream<charT, traits>& is, T& x);
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: As if:
|
||||
+
|
||||
```
|
||||
T i;
|
||||
if (is >> i)
|
||||
x = i;
|
||||
```
|
||||
Returns:: `is`.
|
||||
|
||||
## FAQ
|
||||
|
||||
See the <<overview_faq,Endian home page>> FAQ for a library-wide FAQ.
|
||||
|
||||
Why not just use Boost.Serialization?::
|
||||
Serialization involves a conversion for every object involved in I/O. Endian
|
||||
integers require no conversion or copying. They are already in the desired
|
||||
format for binary I/O. Thus they can be read or written in bulk.
|
||||
|
||||
Are endian types PODs?::
|
||||
Yes for {cpp}11. No for {cpp}03, although several
|
||||
<<arithmetic_compilation,macros>> are available to force PODness in all cases.
|
||||
|
||||
What are the implications of endian integer types not being PODs with {cpp}03 compilers?::
|
||||
They can't be used in unions. Also, compilers aren't required to align or lay
|
||||
out storage in portable ways, although this potential problem hasn't prevented
|
||||
use of Boost.Endian with real compilers.
|
||||
|
||||
What good is native endianness?::
|
||||
It provides alignment and size guarantees not available from the built-in
|
||||
types. It eases generic programming.
|
||||
|
||||
Why bother with the aligned endian types?::
|
||||
Aligned integer operations may be faster (as much as 10 to 20 times faster)
|
||||
if the endianness and alignment of the type matches the endianness and
|
||||
alignment requirements of the machine. The code, however, will be somewhat less
|
||||
portable than with the unaligned types.
|
||||
|
||||
Why provide the arithmetic operations?::
|
||||
Providing a full set of operations reduces program clutter and makes code
|
||||
both easier to write and to read. Consider incrementing a variable in a record.
|
||||
It is very convenient to write:
|
||||
+
|
||||
```
|
||||
++record.foo;
|
||||
```
|
||||
+
|
||||
Rather than:
|
||||
+
|
||||
```
|
||||
int temp(record.foo);
|
||||
++temp;
|
||||
record.foo = temp;
|
||||
```
|
||||
|
||||
## Design considerations for Boost.Endian types
|
||||
|
||||
* Must be suitable for I/O - in other words, must be memcpyable.
|
||||
* Must provide exactly the size and internal byte ordering specified.
|
||||
* Must work correctly when the internal integer representation has more bits
|
||||
that the sum of the bits in the external byte representation. Sign extension
|
||||
must work correctly when the internal integer representation type has more
|
||||
bits than the sum of the bits in the external bytes. For example, using
|
||||
a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
|
||||
both positive and negative values.
|
||||
* Must work correctly (including using the same defined external
|
||||
representation) regardless of whether a compiler treats char as signed or
|
||||
unsigned.
|
||||
* Unaligned types must not cause compilers to insert padding bytes.
|
||||
* The implementation should supply optimizations with great care. Experience
|
||||
has shown that optimizations of endian integers often become pessimizations
|
||||
when changing machines or compilers. Pessimizations can also happen when
|
||||
changing compiler switches, compiler versions, or CPU models of the same
|
||||
architecture.
|
||||
|
||||
## Experience
|
||||
|
||||
Classes with similar functionality have been independently developed by
|
||||
several Boost programmers and used very successful in high-value, high-use
|
||||
applications for many years. These independently developed endian libraries
|
||||
often evolved from C libraries that were also widely used. Endian types have
|
||||
proven widely useful across a wide range of computer architectures and
|
||||
applications.
|
||||
|
||||
## Motivating use cases
|
||||
|
||||
Neil Mayhew writes: "I can also provide a meaningful use-case for this
|
||||
library: reading TrueType font files from disk and processing the contents. The
|
||||
data format has fixed endianness (big) and has unaligned values in various
|
||||
places. Using Boost.Endian simplifies and cleans the code wonderfully."
|
||||
|
||||
## {cpp}11
|
||||
|
||||
The availability of the {cpp}11
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
|
||||
Functions] feature is detected automatically, and will be used if present to
|
||||
ensure that objects of `class endian_arithmetic` are trivial, and thus PODs.
|
||||
|
||||
## Compilation
|
||||
Boost.Endian is implemented entirely within headers, with no need to link to any
|
||||
Boost object libraries.
|
||||
|
||||
Several macros allow user control over features:
|
||||
|
||||
* BOOST_ENDIAN_NO_CTORS causes `class endian_arithmetic` to have no
|
||||
constructors. The intended use is for compiling user code that must be portable
|
||||
between compilers regardless of {cpp}11
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
|
||||
Functions] support. Use of constructors will always fail,
|
||||
* BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if
|
||||
the compiler does not support {cpp}11
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
|
||||
Functions]. This is ensures that objects of `class endian_arithmetic` are PODs,
|
||||
and so can be used in {cpp}03 unions. In {cpp}11, `class endian_arithmetic`
|
||||
objects are PODs, even though they have constructors, so can always be used in
|
||||
unions.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Original design developed by Darin Adler based on classes developed by Mark
|
||||
Borgerding. Four original class templates combined into a single
|
||||
`endian_arithmetic` class template by Beman Dawes, who put the library together,
|
||||
provided documentation, added the typedefs, and also added the
|
||||
`unrolled_byte_loops` sign partial specialization to correctly extend the sign
|
||||
when cover integer size differs from endian representation size.
|
521
doc/endian/buffers.adoc
Normal file
521
doc/endian/buffers.adoc
Normal file
@ -0,0 +1,521 @@
|
||||
////
|
||||
Copyright 2011-2016 Beman Dawes
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
////
|
||||
|
||||
[#buffers]
|
||||
# Endian Buffer Types
|
||||
|
||||
## Introduction
|
||||
|
||||
The internal byte order of arithmetic types is traditionally called
|
||||
*endianness*. See the http://en.wikipedia.org/wiki/Endian[Wikipedia] for a full
|
||||
exploration of *endianness*, including definitions of *big endian* and *little
|
||||
endian*.
|
||||
|
||||
Header `boost/endian/buffers.hpp` provides `endian_buffer`, a portable endian
|
||||
integer binary buffer class template with control over byte order, value type,
|
||||
size, and alignment independent of the platform's native endianness. Typedefs
|
||||
provide easy-to-use names for common configurations.
|
||||
|
||||
Use cases primarily involve data portability, either via files or network
|
||||
connections, but these byte-holders may also be used to reduce memory use, file
|
||||
size, or network activity since they provide binary numeric sizes not otherwise
|
||||
available.
|
||||
|
||||
Class `endian_buffer` is aimed at users who wish explicit control over when
|
||||
endianness conversions occur. It also serves as the base class for the
|
||||
<<arithmetic,endian_arithmetic>> class template, which is aimed at users who
|
||||
wish fully automatic endianness conversion and direct support for all normal
|
||||
arithmetic operations.
|
||||
|
||||
## Example
|
||||
|
||||
The `example/endian_example.cpp` program writes a binary file containing
|
||||
four-byte, big-endian and little-endian integers:
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <boost/endian/buffers.hpp> // see Synopsis below
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
using namespace boost::endian;
|
||||
|
||||
namespace
|
||||
{
|
||||
// This is an extract from a very widely used GIS file format.
|
||||
// Why the designer decided to mix big and little endians in
|
||||
// the same file is not known. But this is a real-world format
|
||||
// and users wishing to write low level code manipulating these
|
||||
// files have to deal with the mixed endianness.
|
||||
|
||||
struct header
|
||||
{
|
||||
big_int32_`buf_`t file_code;
|
||||
big_int32_`buf_`t file_length;
|
||||
little_int32_`buf_`t version;
|
||||
little_int32_`buf_`t shape_type;
|
||||
};
|
||||
|
||||
const char* filename = "test.dat";
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
header h;
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check
|
||||
|
||||
h.file_code = 0x01020304;
|
||||
h.file_length = sizeof(header);
|
||||
h.version = 1;
|
||||
h.shape_type = 0x01020304;
|
||||
|
||||
// Low-level I/O such as POSIX read/write or <cstdio>
|
||||
// fread/fwrite is sometimes used for binary file operations
|
||||
// when ultimate efficiency is important. Such I/O is often
|
||||
// performed in some {cpp} wrapper class, but to drive home the
|
||||
// point that endian integers are often used in fairly
|
||||
// low-level code that does bulk I/O operations, <cstdio>
|
||||
// fopen/fwrite is used for I/O in this example.
|
||||
|
||||
std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
|
||||
|
||||
if (!fi)
|
||||
{
|
||||
std::cout << "could not open " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (std::fwrite(&h, sizeof(header), 1, fi)!= 1)
|
||||
{
|
||||
std::cout << "write failure for " << filename << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::fclose(fi);
|
||||
|
||||
std::cout << "created file " << filename << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
After compiling and executing `example/endian_example.cpp`, a hex dump of
|
||||
`test.dat` shows:
|
||||
|
||||
```
|
||||
01020304 00000010 01000000 04030201
|
||||
```
|
||||
|
||||
Notice that the first two 32-bit integers are big endian while the second two
|
||||
are little endian, even though the machine this was compiled and run on was
|
||||
little endian.
|
||||
|
||||
## Limitations
|
||||
|
||||
Requires `<climits>`, `CHAR_BIT == 8`. If `CHAR_BIT` is some other value,
|
||||
compilation will result in an `#error`. This restriction is in place because the
|
||||
design, implementation, testing, and documentation has only considered issues
|
||||
related to 8-bit bytes, and there have been no real-world use cases presented
|
||||
for other sizes.
|
||||
|
||||
In {cpp}03, `endian_buffer` does not meet the requirements for POD types because
|
||||
it has constructors, private data members, and a base class. This means that
|
||||
common use cases are relying on unspecified behavior in that the {cpp} Standard
|
||||
does not guarantee memory layout for non-POD types. This has not been a problem
|
||||
in practice since all known {cpp} compilers lay out memory as if `endian` were
|
||||
a POD type. In {cpp}11, it is possible to specify the default constructor as
|
||||
trivial, and private data members and base classes no longer disqualify a type
|
||||
from being a POD type. Thus under {cpp}11, `endian_buffer` will no longer be
|
||||
relying on unspecified behavior.
|
||||
|
||||
## Feature set
|
||||
|
||||
* Big endian| little endian | native endian byte ordering.
|
||||
* Signed | unsigned
|
||||
* Unaligned | aligned
|
||||
* 1-8 byte (unaligned) | 1, 2, 4, 8 byte (aligned)
|
||||
* Choice of value type
|
||||
|
||||
## Enums and typedefs
|
||||
|
||||
Two scoped enums are provided:
|
||||
|
||||
```
|
||||
enum class order {big, little, native};
|
||||
|
||||
enum class align {no, yes};
|
||||
```
|
||||
|
||||
One class template is provided:
|
||||
|
||||
```
|
||||
template <order Order, typename T, std::size_t Nbits,
|
||||
align Align = align::no>
|
||||
class endian_buffer;
|
||||
```
|
||||
|
||||
Typedefs, such as `big_int32_buf_t`, provide convenient naming conventions for
|
||||
common use cases:
|
||||
|
||||
[%header,cols=5*]
|
||||
|===
|
||||
|Name |Alignment |Endianness |Sign |Sizes in bits (n)
|
||||
|big_intn_buf_t |no |big |signed |8,16,24,32,40,48,56,64
|
||||
|big_uintn_buf_t |no |big |unsigned |8,16,24,32,40,48,56,64
|
||||
|little_intn_buf_t |no |little |signed |8,16,24,32,40,48,56,64
|
||||
|little_uintn_buf_t |no |little |unsigned |8,16,24,32,40,48,56,64
|
||||
|native_intn_buf_t |no |native |signed |8,16,24,32,40,48,56,64
|
||||
|native_uintn_buf_t |no |native |unsigned |8,16,24,32,40,48,56,64
|
||||
|big_intn_buf_at |yes |big |signed |8,16,32,64
|
||||
|big_uintn_buf_at |yes |big |unsigned |8,16,32,64
|
||||
|little_intn_buf_at |yes |little |signed |8,16,32,64
|
||||
|little_uintn_buf_at |yes |little |unsigned |8,16,32,64
|
||||
|===
|
||||
|
||||
The unaligned types do not cause compilers to insert padding bytes in classes
|
||||
and structs. This is an important characteristic that can be exploited to
|
||||
minimize wasted space in memory, files, and network transmissions.
|
||||
|
||||
CAUTION: Code that uses aligned types is possibly non-portable because alignment
|
||||
requirements vary between hardware architectures and because alignment may be
|
||||
affected by compiler switches or pragmas. For example, alignment of an 64-bit
|
||||
integer may be to a 32-bit boundary on a 32-bit machine and to a 64-bit boundary
|
||||
on a 64-bit machine. Furthermore, aligned types are only available on
|
||||
architectures with 8, 16, 32, and 64-bit integer types.
|
||||
|
||||
TIP: Prefer unaligned buffer types.
|
||||
|
||||
TIP: Protect yourself against alignment ills. For example:
|
||||
[none]
|
||||
{blank}::
|
||||
+
|
||||
```
|
||||
static_assert(sizeof(containing_struct) == 12, "sizeof(containing_struct) is wrong");
|
||||
```
|
||||
|
||||
Note: One-byte big and little buffer types have identical layout on all
|
||||
platforms, so they never actually reverse endianness. They are provided to
|
||||
enable generic code, and to improve code readability and searchability.
|
||||
|
||||
## Class template `endian_buffer`
|
||||
|
||||
An `endian_buffer` is a byte-holder for arithmetic types with
|
||||
user-specified <<buffers_endianness,endianness>>, value type, size, and
|
||||
<<buffers_alignment,alignment>>.
|
||||
|
||||
### Synopsis
|
||||
|
||||
```
|
||||
#include <boost/endian/conversion.hpp
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace endian
|
||||
{
|
||||
// C++11 features emulated if not available
|
||||
|
||||
enum class align {no, yes};
|
||||
|
||||
template <order Order, class T, std::size_t Nbits,
|
||||
align Align = align::no>
|
||||
class endian_buffer
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
endian_buffer() noexcept = default;
|
||||
explicit endian_buffer(T v) noexcept;
|
||||
|
||||
endian_buffer& operator=(T v) noexcept;
|
||||
value_type value() const noexcept;
|
||||
const char* data() const noexcept;
|
||||
protected:
|
||||
implementaton-defined endian_value; // for exposition only
|
||||
};
|
||||
|
||||
// stream inserter
|
||||
template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align Align>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os,
|
||||
const endian_buffer<Order, T, n_bits, Align>& x);
|
||||
|
||||
// stream extractor
|
||||
template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align A>
|
||||
std::basic_istream<charT, traits>&
|
||||
operator>>(std::basic_istream<charT, traits>& is,
|
||||
endian_buffer<Order, T, n_bits, Align>& x);
|
||||
|
||||
// typedefs
|
||||
|
||||
// unaligned big endian signed integer buffers
|
||||
typedef endian_buffer<order::big, int_least8_t, 8> big_int8_buf_t;
|
||||
typedef endian_buffer<order::big, int_least16_t, 16> big_int16_buf_t;
|
||||
typedef endian_buffer<order::big, int_least32_t, 24> big_int24_buf_t;
|
||||
typedef endian_buffer<order::big, int_least32_t, 32> big_int32_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 40> big_int40_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 48> big_int48_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 56> big_int56_buf_t;
|
||||
typedef endian_buffer<order::big, int_least64_t, 64> big_int64_buf_t;
|
||||
|
||||
// unaligned big endian unsigned integer buffers
|
||||
typedef endian_buffer<order::big, uint_least8_t, 8> big_uint8_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least16_t, 16> big_uint16_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least32_t, 24> big_uint24_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least32_t, 32> big_uint32_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 40> big_uint40_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 48> big_uint48_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 56> big_uint56_buf_t;
|
||||
typedef endian_buffer<order::big, uint_least64_t, 64> big_uint64_buf_t;
|
||||
|
||||
// unaligned little endian signed integer buffers
|
||||
typedef endian_buffer<order::little, int_least8_t, 8> little_int8_buf_t;
|
||||
typedef endian_buffer<order::little, int_least16_t, 16> little_int16_buf_t;
|
||||
typedef endian_buffer<order::little, int_least32_t, 24> little_int24_buf_t;
|
||||
typedef endian_buffer<order::little, int_least32_t, 32> little_int32_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 40> little_int40_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 48> little_int48_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 56> little_int56_buf_t;
|
||||
typedef endian_buffer<order::little, int_least64_t, 64> little_int64_buf_t;
|
||||
|
||||
// unaligned little endian unsigned integer buffers
|
||||
typedef endian_buffer<order::little, uint_least8_t, 8> little_uint8_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least16_t, 16> little_uint16_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least32_t, 24> little_uint24_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least32_t, 32> little_uint32_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 40> little_uint40_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 48> little_uint48_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 56> little_uint56_buf_t;
|
||||
typedef endian_buffer<order::little, uint_least64_t, 64> little_uint64_buf_t;
|
||||
|
||||
// unaligned native endian signed integer types
|
||||
typedef implementation-defined_int8_buf_t native_int8_buf_t;
|
||||
typedef implementation-defined_int16_buf_t native_int16_buf_t;
|
||||
typedef implementation-defined_int24_buf_t native_int24_buf_t;
|
||||
typedef implementation-defined_int32_buf_t native_int32_buf_t;
|
||||
typedef implementation-defined_int40_buf_t native_int40_buf_t;
|
||||
typedef implementation-defined_int48_buf_t native_int48_buf_t;
|
||||
typedef implementation-defined_int56_buf_t native_int56_buf_t;
|
||||
typedef implementation-defined_int64_buf_t native_int64_buf_t;
|
||||
|
||||
// unaligned native endian unsigned integer types
|
||||
typedef implementation-defined_uint8_buf_t native_uint8_buf_t;
|
||||
typedef implementation-defined_uint16_buf_t native_uint16_buf_t;
|
||||
typedef implementation-defined_uint24_buf_t native_uint24_buf_t;
|
||||
typedef implementation-defined_uint32_buf_t native_uint32_buf_t;
|
||||
typedef implementation-defined_uint40_buf_t native_uint40_buf_t;
|
||||
typedef implementation-defined_uint48_buf_t native_uint48_buf_t;
|
||||
typedef implementation-defined_uint56_buf_t native_uint56_buf_t;
|
||||
typedef implementation-defined_uint64_buf_t native_uint64_buf_t;
|
||||
|
||||
// aligned big endian signed integer buffers
|
||||
typedef endian_buffer<order::big, int8_t, 8, align::yes> big_int8_buf_at;
|
||||
typedef endian_buffer<order::big, int16_t, 16, align::yes> big_int16_buf_at;
|
||||
typedef endian_buffer<order::big, int32_t, 32, align::yes> big_int32_buf_at;
|
||||
typedef endian_buffer<order::big, int64_t, 64, align::yes> big_int64_buf_at;
|
||||
|
||||
// aligned big endian unsigned integer buffers
|
||||
typedef endian_buffer<order::big, uint8_t, 8, align::yes> big_uint8_buf_at;
|
||||
typedef endian_buffer<order::big, uint16_t, 16, align::yes> big_uint16_buf_at;
|
||||
typedef endian_buffer<order::big, uint32_t, 32, align::yes> big_uint32_buf_at;
|
||||
typedef endian_buffer<order::big, uint64_t, 64, align::yes> big_uint64_buf_at;
|
||||
|
||||
// aligned little endian signed integer buffers
|
||||
typedef endian_buffer<order::little, int8_t, 8, align::yes> little_int8_buf_at;
|
||||
typedef endian_buffer<order::little, int16_t, 16, align::yes> little_int16_buf_at;
|
||||
typedef endian_buffer<order::little, int32_t, 32, align::yes> little_int32_buf_at;
|
||||
typedef endian_buffer<order::little, int64_t, 64, align::yes> little_int64_buf_at;
|
||||
|
||||
// aligned little endian unsigned integer buffers
|
||||
typedef endian_buffer<order::little, uint8_t, 8, align::yes> little_uint8_buf_at;
|
||||
typedef endian_buffer<order::little, uint16_t, 16, align::yes> little_uint16_buf_at;
|
||||
typedef endian_buffer<order::little, uint32_t, 32, align::yes> little_uint32_buf_at;
|
||||
typedef endian_buffer<order::little, uint64_t, 64, align::yes> little_uint64_buf_at;
|
||||
|
||||
// aligned native endian typedefs are not provided because
|
||||
// <cstdint> types are superior for this use case
|
||||
|
||||
} // namespace endian
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
The `implementation-defined` text in typedefs above is either `big` or `little`
|
||||
according to the native endianness of the platform.
|
||||
|
||||
The expository data member `endian_value` stores the current value of an
|
||||
`endian_value` object as a sequence of bytes ordered as specified by the
|
||||
`Order` template parameter. The `implementation-defined` type of
|
||||
`endian_value` is a type such as `char[Nbits/CHAR_BIT]` or `T` that meets the
|
||||
requirements imposed by the `Nbits` and `Align` template parameters. The
|
||||
`CHAR_BIT` macro is defined in `<climits>`. The only value of
|
||||
`CHAR_BIT` that is required to be supported is 8.
|
||||
|
||||
Template parameter `T` is required to be a standard integer type ({cpp}std,
|
||||
3.9.1) and `sizeof(T)*CHAR_BIT` is required to be greater or equal to `Nbits`.
|
||||
|
||||
### Members
|
||||
|
||||
```
|
||||
endian_buffer() noexcept = default;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: Constructs an uninitialized object of type `endian_buffer<Order, T,
|
||||
Nbits, Align>`.
|
||||
|
||||
```
|
||||
explicit endian_buffer(T v) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: Constructs an object of type `endian_buffer<Order, T, Nbits, Align>`.
|
||||
Postcondition:: `value() == v & mask`, where `mask` is a constant of type
|
||||
`value_type` with `Nbits` low-order bits set to one.
|
||||
Remarks:: If `Align` is `align::yes` then endianness conversion, if required,
|
||||
is performed by `boost::endian::endian_reverse`.
|
||||
|
||||
```
|
||||
endian_buffer& operator=(T v) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Postcondition:: `value() == v & mask`, where `mask` is a constant of type
|
||||
`value_type` with `Nbits` low-order bits set to one.
|
||||
Returns:: `*this`.
|
||||
Remarks:: If `Align` is `align::yes` then endianness conversion, if required, is
|
||||
performed by `boost::endian::endian_reverse`.
|
||||
|
||||
```
|
||||
value_type value() const noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `endian_value`, converted to `value_type`, if required, and having the
|
||||
endianness of the native platform.
|
||||
Remarks:: If `Align` is `align::yes` then endianness conversion, if required, is
|
||||
performed by `boost::endian::endian_reverse`.
|
||||
|
||||
```
|
||||
const char* data</a>() const noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: A pointer to the first byte of `endian_value`.
|
||||
[none]
|
||||
|
||||
### Non-member functions
|
||||
|
||||
```
|
||||
template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align Align>
|
||||
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os,
|
||||
const endian_buffer<Order, T, n_bits, Align>& x);
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `os << x.value()`.
|
||||
|
||||
```
|
||||
template <class charT, class traits, order Order, class T,
|
||||
std::size_t n_bits, align A>
|
||||
std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is,
|
||||
endian_buffer<Order, T, n_bits, Align>& x);
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: As if:
|
||||
+
|
||||
```
|
||||
T i;
|
||||
if (is >> i)
|
||||
x = i;
|
||||
```
|
||||
Returns:: `is`.
|
||||
|
||||
## FAQ
|
||||
|
||||
See the <<overview_faq,Endian home page>> FAQ for a library-wide FAQ.
|
||||
|
||||
Why not just use Boost.Serialization?::
|
||||
Serialization involves a conversion for every object involved in I/O. Endian
|
||||
integers require no conversion or copying. They are already in the desired
|
||||
format for binary I/O. Thus they can be read or written in bulk.
|
||||
|
||||
Are endian types PODs?::
|
||||
Yes for {cpp}11. No for {cpp}03, although several
|
||||
<<buffers_compilation,macros>> are available to force PODness in all cases.
|
||||
|
||||
What are the implications of endian integer types not being PODs with {cpp}03 compilers?::
|
||||
They can't be used in unions. Also, compilers aren't required to align or lay
|
||||
out storage in portable ways, although this potential problem hasn't prevented
|
||||
use of Boost.Endian with real compilers.
|
||||
|
||||
What good is native endianness?::
|
||||
It provides alignment and size guarantees not available from the built-in
|
||||
types. It eases generic programming.
|
||||
|
||||
Why bother with the aligned endian types?::
|
||||
Aligned integer operations may be faster (as much as 10 to 20 times faster) if
|
||||
the endianness and alignment of the type matches the endianness and alignment
|
||||
requirements of the machine. The code, however, is likely to be somewhat less
|
||||
portable than with the unaligned types.
|
||||
|
||||
## Design considerations for Boost.Endian buffers
|
||||
|
||||
* Must be suitable for I/O - in other words, must be memcpyable.
|
||||
* Must provide exactly the size and internal byte ordering specified.
|
||||
* Must work correctly when the internal integer representation has more bits
|
||||
that the sum of the bits in the external byte representation. Sign extension
|
||||
must work correctly when the internal integer representation type has more
|
||||
bits than the sum of the bits in the external bytes. For example, using
|
||||
a 64-bit integer internally to represent 40-bit (5 byte) numbers must work for
|
||||
both positive and negative values.
|
||||
* Must work correctly (including using the same defined external
|
||||
representation) regardless of whether a compiler treats char as signed or
|
||||
unsigned.
|
||||
* Unaligned types must not cause compilers to insert padding bytes.
|
||||
* The implementation should supply optimizations with great care. Experience
|
||||
has shown that optimizations of endian integers often become pessimizations
|
||||
when changing machines or compilers. Pessimizations can also happen when
|
||||
changing compiler switches, compiler versions, or CPU models of the same
|
||||
architecture.
|
||||
|
||||
## {cpp}11
|
||||
|
||||
The availability of the {cpp}11
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
|
||||
Functions] feature is detected automatically, and will be used if present to
|
||||
ensure that objects of `class endian_buffer` are trivial, and thus
|
||||
PODs.
|
||||
|
||||
## Compilation
|
||||
|
||||
Boost.Endian is implemented entirely within headers, with no need to link to
|
||||
any Boost object libraries.
|
||||
|
||||
Several macros allow user control over features:
|
||||
|
||||
* BOOST_ENDIAN_NO_CTORS causes `class endian_buffer` to have no
|
||||
constructors. The intended use is for compiling user code that must be
|
||||
portable between compilers regardless of {cpp}11
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
|
||||
Functions] support. Use of constructors will always fail,
|
||||
* BOOST_ENDIAN_FORCE_PODNESS causes BOOST_ENDIAN_NO_CTORS to be defined if the
|
||||
compiler does not support {cpp}11
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm[Defaulted
|
||||
Functions]. This is ensures that objects of `class endian_buffer` are PODs, and
|
||||
so can be used in {cpp}03 unions. In {cpp}11, `class endian_buffer` objects are
|
||||
PODs, even though they have constructors, so can always be used in unions.
|
317
doc/endian/choosing_approach.adoc
Normal file
317
doc/endian/choosing_approach.adoc
Normal file
@ -0,0 +1,317 @@
|
||||
////
|
||||
Copyright 2011-2016 Beman Dawes
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
////
|
||||
|
||||
[#choosing]
|
||||
# Choosing Approach
|
||||
|
||||
## Introduction
|
||||
|
||||
Deciding which is the best endianness approach (conversion functions, buffer
|
||||
types, or arithmetic types) for a particular application involves complex
|
||||
engineering trade-offs. It is hard to assess those trade-offs without some
|
||||
understanding of the different interfaces, so you might want to read the
|
||||
<<conversion,conversion functions>>, <<buffers,buffer types>>, and
|
||||
<<arithmetic,arithmetic types>> pages before diving into this page.
|
||||
|
||||
## Choosing between conversion functions, buffer types, and arithmetic types
|
||||
|
||||
The best approach to endianness for a particular application depends on the
|
||||
interaction between the application's needs and the characteristics of each of
|
||||
the three approaches.
|
||||
|
||||
*Recommendation:* If you are new to endianness, uncertain, or don't want to
|
||||
invest the time to study engineering trade-offs, use
|
||||
<<arithmetic,endian arithmetic types>>. They are safe, easy to use, and easy to
|
||||
maintain. Use the _<<choosing_anticipating_need,anticipating need>>_ design
|
||||
pattern locally around performance hot spots like lengthy loops, if needed.
|
||||
|
||||
### Background
|
||||
|
||||
A dealing with endianness usually implies a program portability or a data
|
||||
portability requirement, and often both. That means real programs dealing with
|
||||
endianness are usually complex, so the examples shown here would really be
|
||||
written as multiple functions spread across multiple translation units. They
|
||||
would involve interfaces that can not be altered as they are supplied by
|
||||
third-parties or the standard library.
|
||||
|
||||
### Characteristics
|
||||
|
||||
The characteristics that differentiate the three approaches to endianness are
|
||||
the endianness invariants, conversion explicitness, arithmetic operations, sizes
|
||||
available, and alignment requirements.
|
||||
|
||||
#### Endianness invariants
|
||||
|
||||
*Endian conversion functions* use objects of the ordinary {cpp} arithmetic types
|
||||
like `int` or `unsigned short` to hold values. That breaks the implicit
|
||||
invariant that the {cpp} language rules apply. The usual language rules only apply
|
||||
if the endianness of the object is currently set to the native endianness for
|
||||
the platform. That can make it very hard to reason about logic flow, and result
|
||||
in difficult to find bugs.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
struct data_t // big endian
|
||||
{
|
||||
int32_t v1; // description ...
|
||||
int32_t v2; // description ...
|
||||
... additional character data members (i.e. non-endian)
|
||||
int32_t v3; // description ...
|
||||
};
|
||||
|
||||
data_t data;
|
||||
|
||||
read(data);
|
||||
big_to_native_inplace(data.v1);
|
||||
big_to_native_inplace(data.v2);
|
||||
|
||||
...
|
||||
|
||||
++v1;
|
||||
third_party::func(data.v2);
|
||||
|
||||
...
|
||||
|
||||
native_to_big_inplace(data.v1);
|
||||
native_to_big_inplace(data.v2);
|
||||
write(data);
|
||||
```
|
||||
|
||||
The programmer didn't bother to convert `data.v3` to native endianness because
|
||||
that member isn't used. A later maintainer needs to pass `data.v3` to the
|
||||
third-party function, so adds `third_party::func(data.v3);` somewhere deep in
|
||||
the code. This causes a silent failure because the usual invariant that an
|
||||
object of type `int32_t` holds a value as described by the {cpp} core language
|
||||
does not apply.
|
||||
|
||||
*Endian buffer and arithmetic types* hold values internally as arrays of
|
||||
characters with an invariant that the endianness of the array never changes.
|
||||
That makes these types easier to use and programs easier to maintain.
|
||||
|
||||
Here is the same example, using an endian arithmetic type:
|
||||
|
||||
```
|
||||
struct data_t
|
||||
{
|
||||
big_int32_t v1; // description ...
|
||||
big_int32_t v2; // description ...
|
||||
... additional character data members (i.e. non-endian)
|
||||
big_int32_t v3; // description ...
|
||||
};
|
||||
|
||||
data_t data;
|
||||
|
||||
read(data);
|
||||
|
||||
...
|
||||
|
||||
++v1;
|
||||
third_party::func(data.v2);
|
||||
|
||||
...
|
||||
|
||||
write(data);
|
||||
```
|
||||
|
||||
A later maintainer can add `third_party::func(data.v3)` and it will just-work.
|
||||
|
||||
#### Conversion explicitness
|
||||
|
||||
*Endian conversion functions* and *buffer types* never perform implicit
|
||||
conversions. This gives users explicit control of when conversion occurs, and
|
||||
may help avoid unnecessary conversions.
|
||||
|
||||
*Endian arithmetic types* perform conversion implicitly. That makes these types
|
||||
very easy to use, but can result in unnecessary conversions. Failure to hoist
|
||||
conversions out of inner loops can bring a performance penalty.
|
||||
|
||||
#### Arithmetic operations
|
||||
|
||||
*Endian conversion functions* do not supply arithmetic operations, but this is
|
||||
not a concern since this approach uses ordinary {cpp} arithmetic types to hold
|
||||
values.
|
||||
|
||||
*Endian buffer types* do not supply arithmetic operations. Although this
|
||||
approach avoids unnecessary conversions, it can result in the introduction of
|
||||
additional variables and confuse maintenance programmers.
|
||||
|
||||
*Endian arithmetic types* do supply arithmetic operations. They are very easy to
|
||||
use if lots of arithmetic is involved.
|
||||
|
||||
### Sizes
|
||||
|
||||
*Endianness conversion functions* only support 1, 2, 4, and 8 byte integers.
|
||||
That's sufficient for many applications.
|
||||
|
||||
*Endian buffer and arithmetic types* support 1, 2, 3, 4, 5, 6, 7, and 8 byte
|
||||
integers. For an application where memory use or I/O speed is the limiting
|
||||
factor, using sizes tailored to application needs can be useful.
|
||||
|
||||
#### Alignments
|
||||
|
||||
*Endianness conversion functions* only support aligned integer and
|
||||
floating-point types. That's sufficient for most applications.
|
||||
|
||||
*Endian buffer and arithmetic types* support both aligned and unaligned
|
||||
integer and floating-point types. Unaligned types are rarely needed, but when
|
||||
needed they are often very useful and workarounds are painful. For example:
|
||||
|
||||
Non-portable code like this:
|
||||
|
||||
```
|
||||
struct S {
|
||||
uint16_t a; // big endian
|
||||
uint32_t b; // big endian
|
||||
} __attribute__ ((packed));
|
||||
```
|
||||
|
||||
Can be replaced with portable code like this:
|
||||
|
||||
```
|
||||
struct S {
|
||||
big_uint16_ut a;
|
||||
big_uint32_ut b;
|
||||
};
|
||||
```
|
||||
|
||||
### Design patterns
|
||||
|
||||
Applications often traffic in endian data as records or packets containing
|
||||
multiple endian data elements. For simplicity, we will just call them records.
|
||||
|
||||
If desired endianness differs from native endianness, a conversion has to be
|
||||
performed. When should that conversion occur? Three design patterns have
|
||||
evolved.
|
||||
|
||||
#### Convert only as needed (i.e. lazy)
|
||||
|
||||
This pattern defers conversion to the point in the code where the data
|
||||
element is actually used.
|
||||
|
||||
This pattern is appropriate when which endian element is actually used varies
|
||||
greatly according to record content or other circumstances
|
||||
|
||||
[#choosing_anticipating_need]
|
||||
#### Convert in anticipation of need
|
||||
|
||||
This pattern performs conversion to native endianness in anticipation of use,
|
||||
such as immediately after reading records. If needed, conversion to the output
|
||||
endianness is performed after all possible needs have passed, such as just
|
||||
before writing records.
|
||||
|
||||
One implementation of this pattern is to create a proxy record with endianness
|
||||
converted to native in a read function, and expose only that proxy to the rest
|
||||
of the implementation. If a write function, if needed, handles the conversion
|
||||
from native to the desired output endianness.
|
||||
|
||||
This pattern is appropriate when all endian elements in a record are typically
|
||||
used regardless of record content or other circumstances.
|
||||
|
||||
#### Convert only as needed, except locally in anticipation of need
|
||||
|
||||
This pattern in general defers conversion but for specific local needs does
|
||||
anticipatory conversion. Although particularly appropriate when coupled with the
|
||||
endian buffer or arithmetic types, it also works well with the conversion
|
||||
functions.
|
||||
|
||||
Example:
|
||||
|
||||
[subs=+quotes]
|
||||
```
|
||||
struct data_t
|
||||
{
|
||||
big_int32_t v1;
|
||||
big_int32_t v2;
|
||||
big_int32_t v3;
|
||||
};
|
||||
|
||||
data_t data;
|
||||
|
||||
read(data);
|
||||
|
||||
...
|
||||
++v1;
|
||||
...
|
||||
|
||||
int32_t v3_temp = data.v3; // hoist conversion out of loop
|
||||
|
||||
for (int32_t i = 0; i < `large-number`; ++i)
|
||||
{
|
||||
... `lengthy computation that accesses v3_temp` ...
|
||||
}
|
||||
data.v3 = v3_temp;
|
||||
|
||||
write(data);
|
||||
```
|
||||
|
||||
In general the above pseudo-code leaves conversion up to the endian arithmetic
|
||||
type `big_int32_t`. But to avoid conversion inside the loop, a temporary is
|
||||
created before the loop is entered, and then used to set the new value of
|
||||
`data.v3` after the loop is complete.
|
||||
|
||||
Question: Won't the compiler's optimizer hoist the conversion out of the loop
|
||||
anyhow?
|
||||
|
||||
Answer: V{cpp} 2015 Preview, and probably others, does not, even for a toy test
|
||||
program. Although the savings is small (two register `bswap` instructions), the
|
||||
cost might be significant if the loop is repeated enough times. On the other
|
||||
hand, the program may be so dominated by I/O time that even a lengthy loop will
|
||||
be immaterial.
|
||||
|
||||
### Use case examples
|
||||
|
||||
#### Porting endian unaware codebase
|
||||
|
||||
An existing codebase runs on big endian systems. It does not currently deal
|
||||
with endianness. The codebase needs to be modified so it can run on little
|
||||
endian systems under various operating systems. To ease transition and protect
|
||||
value of existing files, external data will continue to be maintained as big
|
||||
endian.
|
||||
|
||||
The <<arithmetic,endian arithmetic approach>> is recommended to meet these
|
||||
needs. A relatively small number of header files dealing with binary I/O layouts
|
||||
need to change types. For example, `short` or `int16_t` would change to
|
||||
`big_int16_t`. No changes are required for `.cpp` files.
|
||||
|
||||
#### Porting endian aware codebase
|
||||
|
||||
An existing codebase runs on little-endian Linux systems. It already deals with
|
||||
endianness via
|
||||
http://man7.org/linux/man-pages/man3/endian.3.html[Linux provided functions].
|
||||
Because of a business merger, the codebase has to be quickly modified for
|
||||
Windows and possibly other operating systems, while still supporting Linux. The
|
||||
codebase is reliable and the programmers are all well-aware of endian issues.
|
||||
|
||||
These factors all argue for an <<conversion, endian conversion approach>> that
|
||||
just mechanically changes the calls to `htobe32`, etc. to
|
||||
`boost::endian::native_to_big`, etc. and replaces `<endian.h>` with
|
||||
`<boost/endian/conversion.hpp>`.
|
||||
|
||||
#### Reliability and arithmetic-speed
|
||||
|
||||
A new, complex, multi-threaded application is to be developed that must run
|
||||
on little endian machines, but do big endian network I/O. The developers believe
|
||||
computational speed for endian variable is critical but have seen numerous bugs
|
||||
result from inability to reason about endian conversion state. They are also
|
||||
worried that future maintenance changes could inadvertently introduce a lot of
|
||||
slow conversions if full-blown endian arithmetic types are used.
|
||||
|
||||
The <<buffers,endian buffers>> approach is made-to-order for this use case.
|
||||
|
||||
#### Reliability and ease-of-use
|
||||
|
||||
A new, complex, multi-threaded application is to be developed that must run on
|
||||
little endian machines, but do big endian network I/O. The developers believe
|
||||
computational speed for endian variables is *not critical* but have seen
|
||||
numerous bugs result from inability to reason about endian conversion state.
|
||||
They are also concerned about ease-of-use both during development and long-term
|
||||
maintenance.
|
||||
|
||||
Removing concern about conversion speed and adding concern about ease-of-use
|
||||
tips the balance strongly in favor the
|
||||
<<arithmetic,endian arithmetic approach>>.
|
369
doc/endian/conversion.adoc
Normal file
369
doc/endian/conversion.adoc
Normal file
@ -0,0 +1,369 @@
|
||||
////
|
||||
Copyright 2011-2016 Beman Dawes
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
////
|
||||
|
||||
[#conversion]
|
||||
# Endian Conversion Functions
|
||||
|
||||
## Introduction
|
||||
|
||||
Header `boost/endian/conversion.hpp` provides byte order reversal and conversion
|
||||
functions that convert objects of the built-in integer types between native,
|
||||
big, or little endian byte ordering. User defined types are also supported.
|
||||
|
||||
## Reference
|
||||
|
||||
Functions are implemented `inline` if appropriate. For {cpp}03 compilers,
|
||||
`noexcept` is elided. Boost scoped enum emulation is used so that the library
|
||||
still works for compilers that do not support scoped enums.
|
||||
|
||||
### Definitions
|
||||
|
||||
*Endianness* refers to the ordering of bytes within internal or external
|
||||
integers and other arithmetic data. Most-significant byte first is called
|
||||
*big endian* ordering. Least-significant byte first is called
|
||||
*little endian* ordering. Other orderings are possible and some CPU
|
||||
architectures support both big and little ordering.
|
||||
|
||||
NOTE: The names are derived from
|
||||
http://en.wikipedia.org/wiki/Jonathan_Swift[Jonathan Swift]'s satirical novel
|
||||
_http://en.wikipedia.org/wiki/Gulliver's_Travels[Gulliver's Travels]_, where
|
||||
rival kingdoms opened their soft-boiled eggs at different ends. Wikipedia has an
|
||||
extensive description of https://en.wikipedia.org/wiki/Endianness[Endianness].
|
||||
|
||||
The standard integral types ({cpp}std 3.9.1) except `bool` are collectively
|
||||
called the *endian types*.
|
||||
|
||||
### Header `<boost/endian/conversion.hpp>` Synopsis
|
||||
|
||||
[subs=+quotes]
|
||||
```
|
||||
#define BOOST_ENDIAN_INTRINSIC_MSG \
|
||||
"`message describing presence or absence of intrinsics`"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace endian
|
||||
{
|
||||
enum class order
|
||||
{
|
||||
native = `see below`,
|
||||
big = `see below`,
|
||||
little = `see below`,
|
||||
};
|
||||
|
||||
int8_t endian_reverse(int8_t x) noexcept;
|
||||
int16_t endian_reverse(int16_t x) noexcept;
|
||||
int32_t endian_reverse(int32_t x) noexcept;
|
||||
int64_t endian_reverse(int64_t x) noexcept;
|
||||
uint8_t endian_reverse(uint8_t x) noexcept;
|
||||
uint16_t endian_reverse(uint16_t x) noexcept;
|
||||
uint32_t endian_reverse(uint32_t x) noexcept;
|
||||
uint64_t endian_reverse(uint64_t x) noexcept;
|
||||
|
||||
template <class EndianReversible>
|
||||
EndianReversible big_to_native(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible native_to_big(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible little_to_native(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible native_to_little(EndianReversible x) noexcept;
|
||||
template <order O1, order O2, class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x) noexcept;
|
||||
template <class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x,
|
||||
order order1, order order2) noexcept;
|
||||
|
||||
template <class EndianReversible>
|
||||
void endian_reverse_inplace(EndianReversible& x) noexcept;
|
||||
|
||||
template <class EndianReversibleInplace>
|
||||
void big_to_native_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void native_to_big_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void little_to_native_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void native_to_little_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <order O1, order O2, class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept;
|
||||
template <class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x,
|
||||
order order1, order order2) noexcept;
|
||||
|
||||
} // namespace endian
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
The values of `order::little` and `order::big` shall not be equal to one
|
||||
another.
|
||||
|
||||
The value of `order::native` shall be:
|
||||
|
||||
* equal to `order::big` if the execution environment is big endian, otherwise
|
||||
* equal to `order::little` if the execution environment is little endian,
|
||||
otherwise
|
||||
* unequal to both `order::little` and `order::big`.
|
||||
|
||||
### Requirements
|
||||
|
||||
#### Template argument requirements
|
||||
|
||||
The template definitions in the `boost/endian/conversion.hpp` header refer to
|
||||
various named requirements whose details are set out in the tables in this
|
||||
subsection. In these tables, `T` is an object or reference type to be supplied
|
||||
by a {cpp} program instantiating a template; `x` is a value of type (possibly
|
||||
`const`) `T`; `mlx` is a modifiable lvalue of type `T`.
|
||||
|
||||
[#conversion_endianreversible]
|
||||
##### EndianReversible requirements (in addition to `CopyConstructible`)
|
||||
|
||||
[%header,cols=3*]
|
||||
|===
|
||||
|Expression |Return |Requirements
|
||||
|`endian_reverse(x)` |`T`
|
||||
a|`T` is an endian type or a class type.
|
||||
|
||||
If `T` is an endian type, returns the value of `x` with the order of bytes
|
||||
reversed.
|
||||
|
||||
If `T` is a class type, the function:
|
||||
|
||||
* Returns the value of `x` with the order of bytes reversed for all data members
|
||||
of types or arrays of types that meet the `EndianReversible` requirements, and;
|
||||
* Is a non-member function in the same namespace as `T` that can be found by
|
||||
argument dependent lookup (ADL).
|
||||
|===
|
||||
|
||||
[#conversion_endianreversibleinplace]
|
||||
##### EndianReversibleInplace requirements (in addition to `CopyConstructible`)
|
||||
|
||||
[%header,cols=2*]
|
||||
|===
|
||||
|Expression |Requirements
|
||||
|`endian_reverse_inplace(mlx)`
|
||||
a|`T` is an endian type or a class type.
|
||||
|
||||
If `T` is an endian type, reverses the order of bytes in `mlx`.
|
||||
|
||||
If `T` is a class type, the function:
|
||||
|
||||
* Reverses the order of bytes of all data members of `mlx` that have types or
|
||||
arrays of types that meet the `EndianReversible` or `EndianReversibleInplace`
|
||||
requirements, and;
|
||||
* Is a non-member function in the same namespace as `T` that can be found by
|
||||
argument dependent lookup (ADL).
|
||||
|===
|
||||
|
||||
NOTE: Because there is a function template for `endian_reverse_inplace` that
|
||||
calls `endian_reverse`, only `endian_reverse` is required for a user-defined
|
||||
type to meet the `EndianReversibleInplace` requirements. Although User-defined
|
||||
types are not required to supply an `endian_reverse_inplace` function, doing so
|
||||
may improve efficiency.
|
||||
|
||||
#### Customization points for user-defined types (UDTs)
|
||||
|
||||
This subsection describes requirements on the Endian library's implementation.
|
||||
|
||||
The library's function templates requiring
|
||||
`<<conversion_endianreversible,EndianReversible>>` are required to perform
|
||||
reversal of endianness if needed by making an unqualified call to
|
||||
`endian_reverse()`.
|
||||
|
||||
The library's function templates requiring
|
||||
`<<conversion_endianreversibleinplace,EndianReversibleInplace>>` are required to
|
||||
perform reversal of endianness if needed by making an unqualified call to
|
||||
`endian_reverse_inplace()`.
|
||||
|
||||
See `example/udt_conversion_example.cpp` for an example user-defined type.
|
||||
|
||||
### Functions
|
||||
|
||||
```
|
||||
int8_t endian_reverse(int8_t x) noexcept;
|
||||
int16_t endian_reverse(int16_t x) noexcept;
|
||||
int32_t endian_reverse(int32_t x) noexcept;
|
||||
int64_t endian_reverse(int64_t x) noexcept;
|
||||
uint8_t endian_reverse(uint8_t x) noexcept;
|
||||
uint16_t endian_reverse(uint16_t x) noexcept;
|
||||
uint32_t endian_reverse(uint32_t x) noexcept;
|
||||
uint64_t endian_reverse(uint64_t x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `x`, with the order of its constituent bytes reversed.
|
||||
Remarks:: The type of `x` meets the `EndianReversible` requirements.
|
||||
+
|
||||
NOTE: The Boost.Endian library does not provide overloads for the {cpp} standard
|
||||
library supplied types.
|
||||
|
||||
```
|
||||
template <class EndianReversible>
|
||||
EndianReversible big_to_native(EndianReversible x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `conditional_reverse<order::big, order::native>(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversible>
|
||||
EndianReversible native_to_big(EndianReversible x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `conditional_reverse<order::native, order::big>(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversible>
|
||||
EndianReversible little_to_native(EndianReversible x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `conditional_reverse<order::little, order::native>(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversible>
|
||||
EndianReversible native_to_little(EndianReversible x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `conditional_reverse<order::native, order::little>(x)`.
|
||||
|
||||
```
|
||||
template <order O1, order O2, class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `x` if `O1 == O2,` otherwise `endian_reverse(x)`.
|
||||
Remarks:: Whether `x` or `endian_reverse(x)` is to be returned shall be
|
||||
determined at compile time.
|
||||
|
||||
```
|
||||
template <class EndianReversible>
|
||||
EndianReversible conditional_reverse(EndianReversible x,
|
||||
order order1, order order2) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns:: `order1 == order2 ? x : endian_reverse(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversible>
|
||||
void endian_reverse_inplace(EndianReversible& x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: `x` `= endian_reverse(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversibleInplace>
|
||||
void big_to_native_inplace(EndianReversibleInplace& x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: `conditional_reverse_inplace<order::big, order::native>(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversibleInplace>
|
||||
void native_to_big_inplace(EndianReversibleInplace& x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: `conditional_reverse_inplace<order::native, order::big>(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversibleInplace>
|
||||
void little_to_native_inplace(EndianReversibleInplace& x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: `conditional_reverse_inplace<order::little, order::native>(x)`.
|
||||
|
||||
```
|
||||
template <class EndianReversibleInplace>
|
||||
void native_to_little_inplace(EndianReversibleInplace& x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: `conditional_reverse_inplace<order::native, order::little>(x)`.
|
||||
|
||||
```
|
||||
template <order O1, order O2, class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: None if `O1 == O2,` otherwise `endian_reverse_inplace(x)`.
|
||||
Remarks:: Which effect applies shall be determined at compile time.
|
||||
|
||||
```
|
||||
template <class EndianReversibleInplace>
|
||||
void conditional_reverse_inplace(EndianReversibleInplace& x,
|
||||
order order1, order order2) noexcept;
|
||||
```
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Effects:: If `order1 == order2` then `endian_reverse_inplace(x)`.
|
||||
[none]
|
||||
|
||||
## FAQ
|
||||
|
||||
See the <<overview_faq,Endian home page>> FAQ for a library-wide FAQ.
|
||||
|
||||
*Why are both value returning and modify-in-place functions provided?*
|
||||
|
||||
* Returning the result by value is the standard C and {cpp} idiom for functions
|
||||
that compute a value from an argument. Modify-in-place functions allow cleaner
|
||||
code in many real-world endian use cases and are more efficient for user-defined
|
||||
types that have members such as string data that do not need to be reversed.
|
||||
Thus both forms are provided.
|
||||
|
||||
*Why are exact-length 8, 16, 32, and 64-bit integers supported rather than the
|
||||
built-in char, short, int, long, long long, etc?*
|
||||
|
||||
* The primary use case, portable file or network data, needs these de facto
|
||||
standard sizes. Using types that vary with the platform would greatly limit
|
||||
portability for both programs and data.
|
||||
|
||||
*Why not use the Linux names (htobe16, htole16, be16toh, le16toh, etc.) ?*
|
||||
|
||||
* Those names are non-standard and vary even between POSIX-like operating
|
||||
systems. A {cpp} library TS was going to use those names, but found they were
|
||||
sometimes implemented as macros. Since macros do not respect scoping and
|
||||
namespace rules, to use them would be very error prone.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Tomas Puverle was instrumental in identifying and articulating the need to
|
||||
support endian conversion as separate from endian integer types. Phil Endecott
|
||||
suggested the form of the value returning signatures. Vicente Botet and other
|
||||
reviewers suggested supporting user defined types. General reverse template
|
||||
implementation approach using `std::reverse` suggested by Mathias Gaunard.
|
||||
Portable implementation approach for 16, 32, and 64-bit integers suggested by
|
||||
tymofey, with avoidance of undefined behavior as suggested by Giovanni Piero
|
||||
Deretta, and a further refinement suggested by Pyry Jahkola. Intrinsic builtins
|
||||
implementation approach for 16, 32, and 64-bit integers suggested by several
|
||||
reviewers, and by David Stone, who provided his Boost licensed macro
|
||||
implementation that became the starting point for
|
||||
`boost/endian/detail/intrinsic.hpp`. Pierre Talbot provided the
|
||||
`int8_t endian_reverse()` and templated `endian_reverse_inplace()`
|
||||
implementations.
|
79
doc/endian/mini_review_topics.adoc
Normal file
79
doc/endian/mini_review_topics.adoc
Normal file
@ -0,0 +1,79 @@
|
||||
////
|
||||
Copyright 2011-2016 Beman Dawes
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
////
|
||||
|
||||
[#appendix_mini_review_topics]
|
||||
[appendix]
|
||||
# Endian Mini-Review
|
||||
|
||||
The results of the Boost.Endian formal review included a list of issues to be
|
||||
resolved before a mini-review.
|
||||
|
||||
The issues are shown in *bold* below, with the resolution indicated.
|
||||
|
||||
Common use case scenarios should be developed.::
|
||||
Done. The documentation have been refactored. A page is now devoted to
|
||||
<<choosing,Choosing the Approach>> to endianness. See
|
||||
<<choosing_use_cases,Use cases>> for use case scenarios.
|
||||
|
||||
Example programs should be developed for the common use case scenarios.::
|
||||
Done. See <<choosing,Choosing the Approach>>. Example code has been added
|
||||
throughout.
|
||||
|
||||
Documentation should illuminate the differences between endian integer/float type and endian conversion approaches to the common use case scenarios, and provide guidelines for choosing the most appropriate approach in user's applications.::
|
||||
Done. See <<choosing,Choosing the Approach>>.
|
||||
|
||||
Conversion functions supplying results via return should be provided.::
|
||||
Done. See <<conversion,Conversion Functions>>.
|
||||
|
||||
Platform specific performance enhancements such as use of compiler intrinsics or relaxed alignment requirements should be supported.::
|
||||
Done. Compiler (Clang, GCC, Visual{cpp}, etc.) intrinsics and built-in
|
||||
functions are used in the implementation where appropriate, as requested. See
|
||||
<<overview_intrinsic,Built-in support for Intrinsics>>. See
|
||||
<<overview_timings,Timings for Example 2>> to gauge the impact of intrinsics.
|
||||
|
||||
Endian integer (and floating) types should be implemented via the conversion functions. If that can't be done efficiently, consideration should be given to expanding the conversion function signatures to resolve the inefficiencies.::
|
||||
Done. For the endian types, the implementation uses the endian conversion
|
||||
functions, and thus the intrinsics, as requested.
|
||||
|
||||
Benchmarks that measure performance should be provided. It should be possible to compare platform specific performance enhancements against portable base implementations, and to compare endian integer approaches against endian conversion approaches for the common use case scenarios.::
|
||||
Done. See <<overview_timings,Timings for Example 2>>. The `endian/test`
|
||||
directory also contains several additional benchmark and speed test programs.
|
||||
|
||||
Float (32-bits) and double (64-bits) should be supported. IEEE 754 is the primary use case.::
|
||||
Done. The <<buffers,endian buffer types>>,
|
||||
<<arithmetic,endian arithmetic types>> and
|
||||
<<conversion,endian conversion functions>> now support 32-bit `(float)`
|
||||
and 64-bit `(double)` floating point, as requested.
|
||||
|
||||
Support for user defined types (UDTs) is desirable, and should be provided where there would be no conflict with the other concerns.::
|
||||
Done. See <<conversion_customization,Customization points for user-defined
|
||||
types (UDTs)>>.
|
||||
|
||||
There is some concern that endian integer/float arithmetic operations might used inadvertently or inappropriately. The impact of adding an endian_buffer class without arithmetic operations should be investigated.::
|
||||
Done. The endian types have been decomposed into class template
|
||||
`<<buffers,endian_buffer>>` and class template
|
||||
`<<arithmetic,endian_arithmetic>>`. Class `endian_buffer` is a public base
|
||||
class for `endian_arithmetic`, and can also be used by users as a stand-alone
|
||||
class.
|
||||
|
||||
Stream insertion and extraction of the endian integer/float types should be documented and included in the test coverage.::
|
||||
Done. See <<buffers_stream_inserter,Stream inserter>> and
|
||||
<<buffers_stream_extractor,Stream extractor>>.
|
||||
|
||||
Binary I/O support that was investigated during development of the Endian library should be put up for mini-review for inclusion in the Boost I/O library.::
|
||||
Not done yet. Will be handled as a separate min-review soon after the Endian
|
||||
mini-review.
|
||||
|
||||
Other requested changes.::
|
||||
In addition to the named-endianness conversion functions, functions that
|
||||
perform compile-time (via template) and run-time (via function argument)
|
||||
dispatch are now provided.
|
||||
`order*native` is now a synonym for `order*big` or `order*little` according
|
||||
to the endianness of the platform. This reduces the number of template
|
||||
specializations required.
|
||||
Headers have been reorganized to make them easier to read, with a synopsis
|
||||
at the front and implementation following.
|
443
doc/endian/overview.adoc
Normal file
443
doc/endian/overview.adoc
Normal file
@ -0,0 +1,443 @@
|
||||
////
|
||||
Copyright 2011-2016 Beman Dawes
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
////
|
||||
|
||||
[#overview]
|
||||
# Overview
|
||||
|
||||
## Abstract
|
||||
|
||||
Boost.Endian provides facilities to manipulate the
|
||||
<<overview_endianness,endianness>> of integers and user-defined types.
|
||||
|
||||
* Three approaches to endianness are supported. Each has a long history of
|
||||
successful use, and each approach has use cases where it is preferred over the
|
||||
other approaches.
|
||||
* Primary uses:
|
||||
** Data portability. The Endian library supports binary data exchange, via
|
||||
either external media or network transmission, regardless of platform
|
||||
endianness.
|
||||
** Program portability. POSIX-based and Windows-based operating systems
|
||||
traditionally supply libraries with non-portable functions to perform endian
|
||||
conversion. There are at least four incompatible sets of functions in common
|
||||
use. The Endian library is portable across all {cpp} platforms.
|
||||
* Secondary use: Minimizing data size via sizes and/or alignments not supported
|
||||
by the standard {cpp} integer types.
|
||||
|
||||
[#overview_endianness]
|
||||
## Introduction to endianness
|
||||
|
||||
Consider the following code:
|
||||
|
||||
```
|
||||
int16_t i = 0x0102;
|
||||
FILE * file = fopen("test.bin", "wb"); // binary file!
|
||||
fwrite(&i, sizeof(int16_t), 1, file);
|
||||
fclose(file);
|
||||
```
|
||||
|
||||
On OS X, Linux, or Windows systems with an Intel CPU, a hex dump of the
|
||||
"test.bin" output file produces:
|
||||
|
||||
```
|
||||
0201
|
||||
```
|
||||
|
||||
On OS X systems with a PowerPC CPU, or Solaris systems with a SPARC CPU, a hex
|
||||
dump of the "test.bin" output file produces:
|
||||
|
||||
```
|
||||
0102
|
||||
```
|
||||
|
||||
What's happening here is that Intel CPUs order the bytes of an integer with the
|
||||
least-significant byte first, while SPARC CPUs place the most-significant byte
|
||||
first. Some CPUs, such as the PowerPC, allow the operating system to choose
|
||||
which ordering applies.
|
||||
|
||||
Most-significant-byte-first ordering is traditionally called "big endian"
|
||||
ordering and least-significant-byte-first is traditionally called
|
||||
"little-endian" ordering. The names are derived from
|
||||
http://en.wikipedia.org/wiki/Jonathan_Swift[Jonathan Swift]'s satirical novel
|
||||
_http://en.wikipedia.org/wiki/Gulliver's_Travels[Gulliver's Travels]_, where
|
||||
rival kingdoms opened their soft-boiled eggs at different ends.
|
||||
|
||||
See Wikipedia's http://en.wikipedia.org/wiki/Endianness[Endianness] article for
|
||||
an extensive discussion of endianness.
|
||||
|
||||
Programmers can usually ignore endianness, except when reading a core dump on
|
||||
little-endian systems. But programmers have to deal with endianness when
|
||||
exchanging binary integers and binary floating point values between computer
|
||||
systems with differing endianness, whether by physical file transfer or over a
|
||||
network. And programmers may also want to use the library when minimizing either
|
||||
internal or external data sizes is advantageous.
|
||||
|
||||
[#overview_introduction]
|
||||
## Introduction to the Boost.Endian library
|
||||
|
||||
Boost.Endian provides three different approaches to dealing with endianness. All
|
||||
three approaches support integers and user-define types (UDTs).
|
||||
|
||||
Each approach has a long history of successful use, and each approach has use
|
||||
cases where it is preferred to the other approaches.
|
||||
|
||||
<<conversion,Endian conversion functions>>::
|
||||
The application uses the built-in integer types to hold values, and calls the
|
||||
provided conversion functions to convert byte ordering as needed. Both mutating
|
||||
and non-mutating conversions are supplied, and each comes in unconditional and
|
||||
conditional variants.
|
||||
|
||||
<<buffers, Endian buffer types>>::
|
||||
The application uses the provided endian buffer types to hold values, and
|
||||
explicitly converts to and from the built-in integer types. Buffer sizes of 8,
|
||||
16, 24, 32, 40, 48, 56, and 64 bits (i.e. 1, 2, 3, 4, 5, 6, 7, and 8 bytes) are
|
||||
provided. Unaligned integer buffer types are provided for all sizes, and aligned
|
||||
buffer types are provided for 16, 32, and 64-bit sizes. The provided specific
|
||||
types are typedefs for a generic class template that may be used directly for
|
||||
less common use cases.
|
||||
|
||||
<<arithmetic.html, Endian arithmetic types>>::
|
||||
The application uses the provided endian arithmetic types, which supply the same
|
||||
operations as the built-in {cpp} arithmetic types. All conversions are implicit.
|
||||
Arithmetic sizes of 8, 16, 24, 32, 40, 48, 56, and 64 bits (i.e. 1, 2, 3, 4, 5,
|
||||
6, 7, and 8 bytes) are provided. Unaligned integer types are provided for all
|
||||
sizes and aligned arithmetic types are provided for 16, 32, and 64-bit sizes.
|
||||
The provided specific types are typedefs for a generic class template that may
|
||||
be used directly in generic code of for less common use cases.
|
||||
|
||||
Boost Endian is a header-only library. {cpp}11 features affecting interfaces,
|
||||
such as `noexcept`, are used only if available. See
|
||||
<<overview_cpp03_support,{cpp}03 support for {cpp}11 features>> for details.
|
||||
|
||||
## Choosing between conversion functions, buffer types, and arithmetic types
|
||||
|
||||
This section has been moved to its own <<choosing,Choosing the Approach>> page.
|
||||
|
||||
[#overview_intrinsic]
|
||||
## Built-in support for Intrinsics
|
||||
|
||||
Most compilers, including GCC, Clang, and Visual {cpp}, supply built-in support
|
||||
for byte swapping intrinsics. The Endian library uses these intrinsics when
|
||||
available since they may result in smaller and faster generated code,
|
||||
particularly for optimized builds.
|
||||
|
||||
Defining the macro `BOOST_ENDIAN_NO_INTRINSICS` will suppress use of the
|
||||
intrinsics. This is useful when a compiler has no intrinsic support or fails to
|
||||
locate the appropriate header, perhaps because it is an older release or has
|
||||
very limited supporting libraries.
|
||||
|
||||
The macro `BOOST_ENDIAN_INTRINSIC_MSG` is defined as either
|
||||
`"no byte swap intrinsics"` or a string describing the particular set of
|
||||
intrinsics being used. This is useful for eliminating missing intrinsics as a
|
||||
source of performance issues.
|
||||
|
||||
## Performance
|
||||
|
||||
Consider this problem:
|
||||
|
||||
### Example 1
|
||||
Add 100 to a big endian value in a file, then write the result to a file
|
||||
[%header,cols=2*]
|
||||
|===
|
||||
|Endian arithmetic type approach |Endian conversion function approach
|
||||
a|
|
||||
----
|
||||
big_int32_at x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
x += 100;
|
||||
|
||||
... write x to a file ...
|
||||
----
|
||||
a|
|
||||
----
|
||||
int32_t x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
big_to_native_inplace(x);
|
||||
x += 100;
|
||||
native_to_big_inplace(x);
|
||||
|
||||
... write x to a file ...
|
||||
----
|
||||
|===
|
||||
|
||||
*There will be no performance difference between the two approaches in optimized
|
||||
builds, regardless of the native endianness of the machine.* That's because
|
||||
optimizing compilers will generate exactly the same code for each. That
|
||||
conclusion was confirmed by studying the generated assembly code for GCC and
|
||||
Visual {cpp}. Furthermore, time spent doing I/O will determine the speed of this
|
||||
application.
|
||||
|
||||
Now consider a slightly different problem:
|
||||
|
||||
### Example 2
|
||||
Add a million values to a big endian value in a file, then write the result to a
|
||||
file
|
||||
[%header,cols=2*]
|
||||
|===
|
||||
|Endian arithmetic type approach |Endian conversion function approach
|
||||
a|
|
||||
----
|
||||
big_int32_at x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
for (int32_t i = 0; i < 1000000; ++i)
|
||||
x += i;
|
||||
|
||||
... write x to a file ...
|
||||
----
|
||||
a|
|
||||
----
|
||||
int32_t x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
big_to_native_inplace(x);
|
||||
|
||||
for (int32_t i = 0; i < 1000000; ++i)
|
||||
x += i;
|
||||
|
||||
native_to_big_inplace(x);
|
||||
|
||||
... write x to a file ...
|
||||
----
|
||||
|===
|
||||
|
||||
With the Endian arithmetic approach, on little endian platforms an implicit
|
||||
conversion from and then back to big endian is done inside the loop. With the
|
||||
Endian conversion function approach, the user has ensured the conversions are
|
||||
done outside the loop, so the code may run more quickly on little endian
|
||||
platforms.
|
||||
|
||||
### Timings
|
||||
|
||||
These tests were run against release builds on a circa 2012 4-core little endian
|
||||
X64 Intel Core i5-3570K CPU @ 3.40GHz under Windows 7.
|
||||
|
||||
CAUTION: The Windows CPU timer has very high granularity. Repeated runs of the
|
||||
same tests often yield considerably different results.
|
||||
|
||||
See `test/loop_time_test.cpp` for the actual code and `benchmark/Jamfile.v2` for
|
||||
the build setup.
|
||||
|
||||
#### GNU C++ version 4.8.2 on Linux virtual machine
|
||||
Iterations: 10'000'000'000, Intrinsics: __builtin_bswap16, etc.
|
||||
[%header,cols=3*]
|
||||
|===
|
||||
|Test Case |Endian arithmetic type |Endian conversion function
|
||||
|16-bit aligned big endian |8.46 s |5.28 s
|
||||
|16-bit aligned little endian |5.28 s |5.22 s
|
||||
|32-bit aligned big endian |8.40 s |2.11 s
|
||||
|32-bit aligned little endian |2.11 s |2.10 s
|
||||
|64-bit aligned big endian |14.02 s |3.10 s
|
||||
|64-bit aligned little endian |3.00 s |3.03 s
|
||||
|===
|
||||
|
||||
#### Microsoft Visual C++ version 14.0
|
||||
Iterations: 10'000'000'000, Intrinsics: cstdlib _byteswap_ushort, etc.
|
||||
[%header,cols=3*]
|
||||
|===
|
||||
|Test Case |Endian arithmetic type |Endian conversion function
|
||||
|16-bit aligned big endian |8.27 s |5.26 s
|
||||
|16-bit aligned little endian |5.29 s |5.32 s
|
||||
|32-bit aligned big endian |8.36 s |5.24 s
|
||||
|32-bit aligned little endian |5.24 s |5.24 s
|
||||
|64-bit aligned big endian |13.65 s |3.34 s
|
||||
|64-bit aligned little endian |3.35 s |2.73 s
|
||||
|===
|
||||
|
||||
## Overall FAQ
|
||||
|
||||
Is the implementation header only?::
|
||||
Yes.
|
||||
|
||||
Are {cpp}03 compilers supported?::
|
||||
Yes.
|
||||
|
||||
Does the implementation use compiler intrinsic built-in byte swapping?::
|
||||
Yes, if available. See <<overview_intrinsic,Intrinsic built-in support>>.
|
||||
|
||||
Why bother with endianness?::
|
||||
Binary data portability is the primary use case.
|
||||
|
||||
Does endianness have any uses outside of portable binary file or network I/O formats?::
|
||||
Using the unaligned integer types with a size tailored to the application's
|
||||
needs is a minor secondary use that saves internal or external memory space. For
|
||||
example, using `big_int40_buf_t` or `big_int40_t` in a large array saves a lot
|
||||
of space compared to one of the 64-bit types.
|
||||
|
||||
Why bother with binary I/O? Why not just use {cpp} Standard Library stream inserters and extractors?::
|
||||
* Data interchange formats often specify binary integer data. Binary integer
|
||||
data is smaller and therefore I/O is faster and file sizes are smaller. Transfer
|
||||
between systems is less expensive.
|
||||
* Furthermore, binary integer data is of fixed size, and so fixed-size disk
|
||||
records are possible without padding, easing sorting and allowing random access.
|
||||
* Disadvantages, such as the inability to use text utilities on the resulting
|
||||
files, limit usefulness to applications where the binary I/O advantages are
|
||||
paramount.
|
||||
|
||||
Which is better, big-endian or little-endian?::
|
||||
Big-endian tends to be preferred in a networking environment and is a bit more
|
||||
of an industry standard, but little-endian may be preferred for applications
|
||||
that run primarily on x86, x86-64, and other little-endian CPU's. The
|
||||
http://en.wikipedia.org/wiki/Endian[Wikipedia] article gives more pros and cons.
|
||||
|
||||
Why are only big and little native endianness supported?::
|
||||
These are the only endian schemes that have any practical value today. PDP-11
|
||||
and the other middle endian approaches are interesting curiosities but have no
|
||||
relevance for today's {cpp} developers. The same is true for architectures that
|
||||
allow runtime endianness switching. The
|
||||
<<conversion_native_order_specification,specification for native ordering>> has
|
||||
been carefully crafted to allow support for such orderings in the future, should
|
||||
the need arise. Thanks to Howard Hinnant for suggesting this.
|
||||
|
||||
Why do both the buffer and arithmetic types exist?::
|
||||
Conversions in the buffer types are explicit. Conversions in the arithmetic
|
||||
types are implicit. This fundamental difference is a deliberate design feature
|
||||
that would be lost if the inheritance hierarchy were collapsed.
|
||||
The original design provided only arithmetic types. Buffer types were requested
|
||||
during formal review by those wishing total control over when conversion occurs.
|
||||
They also felt that buffer types would be less likely to be misused by
|
||||
maintenance programmers not familiar with the implications of performing a lot
|
||||
of integer operations on the endian arithmetic integer types.
|
||||
|
||||
What is gained by using the buffer types rather than always just using the arithmetic types?::
|
||||
Assurance that hidden conversions are not performed. This is of overriding
|
||||
importance to users concerned about achieving the ultimate in terms of speed.
|
||||
"Always just using the arithmetic types" is fine for other users. When the
|
||||
ultimate in speed needs to be ensured, the arithmetic types can be used in the
|
||||
same design patterns or idioms that would be used for buffer types, resulting in
|
||||
the same code being generated for either types.
|
||||
|
||||
What are the limitations of integer support?::
|
||||
Tests have only been performed on machines that use two's complement
|
||||
arithmetic. The Endian conversion functions only support 16, 32, and 64-bit
|
||||
aligned integers. The endian types only support 8, 16, 24, 32, 40, 48, 56, and
|
||||
64-bit unaligned integers, and 8, 16, 32, and 64-bit aligned integers.
|
||||
|
||||
Why is there no floating point support?::
|
||||
An attempt was made to support four-byte ``float``s and eight-byte
|
||||
``double``s, limited to
|
||||
http://en.wikipedia.org/wiki/IEEE_floating_point[IEEE 754] (also known as
|
||||
ISO/IEC/IEEE 60559) floating point and further limited to systems where floating
|
||||
point endianness does not differ from integer endianness. Even with those
|
||||
limitations, support for floating point types was not reliable and was removed.
|
||||
For example, simply reversing the endianness of a floating point number can
|
||||
result in a signaling-NAN. For all practical purposes, binary serialization and
|
||||
endianness for integers are one and the same problem. That is not true for
|
||||
floating point numbers, so binary serialization interfaces and formats for
|
||||
floating point does not fit well in an endian-based library.
|
||||
|
||||
|
||||
## Release history
|
||||
|
||||
### Changes requested by formal review
|
||||
|
||||
The library was reworked from top to bottom to accommodate changes requested
|
||||
during the formal review. See <<appendix_mini_review_topics,Mini-Review>>
|
||||
page for details.
|
||||
|
||||
### Other changes since formal review
|
||||
|
||||
* Header `boost/endian/endian.hpp` has been renamed to
|
||||
`boost/endian/arithmetic.hpp`. Headers
|
||||
`boost/endian/conversion.hpp` and `boost/endian/buffers.hpp` have been added.
|
||||
Infrastructure file names were changed accordingly.
|
||||
* The endian arithmetic type aliases have been renamed, using a naming pattern
|
||||
that is consistent for both integer and floating point, and a consistent set of
|
||||
aliases supplied for the endian buffer types.
|
||||
* The unaligned-type alias names still have the `_t` suffix, but the
|
||||
aligned-type alias names now have an `_at` suffix.
|
||||
* `endian_reverse()` overloads for `int8_t` and `uint8_t` have been added for
|
||||
improved generality. (Pierre Talbot)
|
||||
* Overloads of `endian_reverse_inplace()` have been replaced with a single
|
||||
`endian_reverse_inplace()` template. (Pierre Talbot)
|
||||
* For X86 and X64 architectures, which permit unaligned loads and stores,
|
||||
unaligned little endian buffer and arithmetic types use regular loads and
|
||||
stores when the size is exact. This makes unaligned little endian buffer and
|
||||
arithmetic types significantly more efficient on these architectures. (Jeremy
|
||||
Maitin-Shepard)
|
||||
* {cpp}11 features affecting interfaces, such as `noexcept`, are now used.
|
||||
{cpp}03 compilers are still supported.
|
||||
* Acknowledgements have been updated.
|
||||
|
||||
## Compatibility with interim releases
|
||||
|
||||
Prior to the official Boost release, class template `endian_arithmetic` has been
|
||||
used for a decade or more with the same functionality but under the name
|
||||
`endian`. Other names also changed in the official release. If the macro
|
||||
`BOOST_ENDIAN_DEPRECATED_NAMES` is defined, those old now deprecated names are
|
||||
still supported. However, the class template `endian` name is only provided for
|
||||
compilers supporting {cpp}11 template aliases. For {cpp}03 compilers, the name
|
||||
will have to be changed to `endian_arithmetic`.
|
||||
|
||||
To support backward header compatibility, deprecated header
|
||||
`boost/endian/endian.hpp` forwards to `boost/endian/arithmetic.hpp`. It requires
|
||||
`BOOST_ENDIAN_DEPRECATED_NAMES` be defined. It should only be used while
|
||||
transitioning to the official Boost release of the library as it will be removed
|
||||
in some future release.
|
||||
|
||||
## {cpp}03 support for {cpp}11 features
|
||||
|
||||
[%header,cols=2*]
|
||||
|===
|
||||
|{cpp}11 Feature
|
||||
|Action with {cpp}03 Compilers
|
||||
|Scoped enums
|
||||
|Uses header
|
||||
http://www.boost.org/libs/core/doc/html/core/scoped_enum.html[boost/core/scoped_enum.hpp]
|
||||
to emulate {cpp}11 scoped enums.
|
||||
|`noexcept`
|
||||
|Uses `BOOST_NOEXCEPT` macro, which is defined as null for compilers not
|
||||
supporting this {cpp}11 feature.
|
||||
|{cpp}11 PODs
|
||||
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm[N2342])
|
||||
|Takes advantage of {cpp}03 compilers that relax {cpp}03 POD rules, but see
|
||||
Limitations <<buffers_limitations,here>> and <<arithmetic_limitations,here>>.
|
||||
Also see macros for explicit POD control <<buffers_compilation,here>> and
|
||||
<<arithmetic_compilation,here>>
|
||||
|===
|
||||
|
||||
## Future directions
|
||||
|
||||
Standardization.::
|
||||
The plan is to submit Boost.Endian to the {cpp} standards committee for possible
|
||||
inclusion in a Technical Specification or the {cpp} standard itself.
|
||||
|
||||
Specializations for `numeric_limits`.::
|
||||
Roger Leigh requested that all `boost::endian` types provide `numeric_limits`
|
||||
specializations.
|
||||
See https://github.com/boostorg/endian/issues/4[GitHub issue 4].
|
||||
|
||||
Character buffer support.::
|
||||
Peter Dimov pointed out during the mini-review that getting and setting basic
|
||||
arithmetic types (or `<cstdint>` equivalents) from/to an offset into an array of
|
||||
unsigned char is a common need. See
|
||||
http://lists.boost.org/Archives/boost/2015/01/219574.php[Boost.Endian
|
||||
mini-review posting].
|
||||
|
||||
Out-of-range detection.::
|
||||
Peter Dimov pointed suggested during the mini-review that throwing an exception
|
||||
on buffer values being out-of-range might be desirable. See the end of
|
||||
http://lists.boost.org/Archives/boost/2015/01/219659.php[this posting] and
|
||||
subsequent replies.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Comments and suggestions were received from Adder, Benaka Moorthi, Christopher
|
||||
Kohlhoff, Cliff Green, Daniel James, Dave Handley, Gennaro Proto, Giovanni Piero
|
||||
Deretta, Gordon Woodhull, dizzy, Hartmut Kaiser, Howard Hinnant, Jason Newton,
|
||||
Jeff Flinn, Jeremy Maitin-Shepard, John Filo, John Maddock, Kim Barrett, Marsh
|
||||
Ray, Martin Bonner, Mathias Gaunard, Matias Capeletto, Neil Mayhew, Nevin Liber,
|
||||
Olaf van der Spek, Paul Bristow, Peter Dimov, Pierre Talbot, Phil Endecott,
|
||||
Philip Bennefall, Pyry Jahkola, Rene Rivera, Robert Stewart, Roger Leigh, Roland
|
||||
Schwarz, Scott McMurray, Sebastian Redl, Tim Blechmann, Tim Moore, tymofey,
|
||||
Tomas Puverle, Vincente Botet, Yuval Ronen and Vitaly Budovsk. Apologies if
|
||||
anyone has been missed.
|
@ -1,97 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Floating Point Concerns</title>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Floating Point Concerns</h1>
|
||||
|
||||
<p>Consider this simple implementation of <code>endian_reverse</code>:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>template <class T>
|
||||
inline T endian_reverse(T x) BOOST_NOEXCEPT
|
||||
{
|
||||
std::reverse(reinterpret_cast<unsigned char*>(&x),
|
||||
reinterpret_cast<unsigned char*>(&x) + sizeof(T));
|
||||
return x;
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<p><b>Under what conditions with this code fail?</b></p>
|
||||
<p dir="ltr">It will fail if an object of type <code>T</code> has one or more
|
||||
bit patterns that cause a failure. Failures usually occur when an invalid
|
||||
or otherwise special bit pattern is loaded into or saved from a hardware
|
||||
register.</p>
|
||||
<p dir="ltr">The problem could in theory occur with both integers and floating
|
||||
point numbers, but the <a href="http://en.wikipedia.org/wiki/Two's_complement">
|
||||
two's complement integers</a> ubiquitous in modern computer architectures do not
|
||||
have any invalid or otherwise special bit patterns that cause failure when
|
||||
byte-wise reversed.</p>
|
||||
<p dir="ltr">But floating point numbers are a different story. Even if we limit
|
||||
discussion to IEEE 754 (aka ISO/IEC/IEEE 60559) binary representations of 4 and
|
||||
8 byte sizes, several problems are easy to demonstrate:</p>
|
||||
<ul>
|
||||
<li dir="ltr">
|
||||
<p dir="ltr">...</li>
|
||||
</ul>
|
||||
<h2 dir="ltr">Safe interfaces and possible reference implementations</h2>
|
||||
<h3 dir="ltr">In-place interface</h3>
|
||||
<blockquote>
|
||||
<pre dir="ltr">template <class T>
|
||||
inline void endian_reverse_inplace(T& x)
|
||||
{
|
||||
std::reverse(reinterpret_cast<unsigned char*>(&x),
|
||||
reinterpret_cast<unsigned char*>(&x) + sizeof(T));
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<p dir="ltr">This is the same as the current (i.e integer) customization point
|
||||
interface, so there is no need for any change.</p>
|
||||
<p dir="ltr"><b>Warning:</b> Even thought <code>x</code> may have had a valid
|
||||
value on the originating platform, after calling this function the value of
|
||||
<code>x</code> may differ or be invalid on this platform.</p>
|
||||
<h3 dir="ltr">Copy interface</h3>
|
||||
<blockquote>
|
||||
<pre dir="ltr">template <class T>
|
||||
inline void endian_reverse_copy(const T& from, T& to)
|
||||
{
|
||||
std::reverse_copy(reinterpret_cast<const unsigned char*>(&from),
|
||||
reinterpret_cast<const unsigned char*>(&from) + sizeof(T),
|
||||
reinterpret_cast<unsigned char*>(&to));
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<p><b>Warning:</b> Even thought <code>from</code> may have been a valid value on
|
||||
the originating platform, after calling this function the value of <code>to</code>
|
||||
may differ or be invalid on this platform.</p>
|
||||
<h3>Return-by-value interface</h3>
|
||||
<blockquote>
|
||||
<pre>template <class T>
|
||||
inline T endian_reverse_to_native(<span style="background-color: #FFFF00">const</span><span style="background-color: #FFFF00"> T&</span> x) BOOST_NOEXCEPT
|
||||
{
|
||||
T tmp;
|
||||
std::reverse_copy(reinterpret_cast<const unsigned char*>(&x),
|
||||
reinterpret_cast<const unsigned char*>(&x) + sizeof(T),
|
||||
reinterpret_cast<unsigned char*>(&tmp));
|
||||
return tmp;
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<p><b>Warning:</b> Even thought <code>x</code> may have had a valid value on the
|
||||
originating platform, the value of returned by this function may differ or be
|
||||
invalid on this platform.</p>
|
||||
<h2>Acknowledgements</h2>
|
||||
<hr>
|
||||
<p>Last revised: <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->27 March, 2015<!--webbot bot="Timestamp" endspan i-checksum="28924" --></p>
|
||||
<p><EFBFBD> Copyright Beman Dawes, 2015</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
606
doc/index.html
606
doc/index.html
@ -1,606 +0,0 @@
|
||||
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns="http://www.w3.org/TR/REC-html40">
|
||||
|
||||
<head>
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<title>Endian Library</title>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
|
||||
<tr>
|
||||
<td width="339">
|
||||
<a href="../../../index.html">
|
||||
<img src="../../../boost.png" alt="Boost logo" align="middle" border="0" width="277" height="86"></a></td>
|
||||
<td align="middle" width="1253">
|
||||
<b>
|
||||
<font size="6">Endian Library</font></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse"
|
||||
bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
||||
<tr>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p></p>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" align="right">
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#D7EEFF" align="center">
|
||||
<i><b>Contents</b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" bgcolor="#E8F5FF">
|
||||
<a href="#Abstract">Abstract</a><br>
|
||||
<a href="#Introduction-to-endianness">Introduction to endianness</a><br>
|
||||
<a href="#Introduction">Introduction to the Boost.Endian library</a><br>
|
||||
<a href="#Choosing">Choosing between conversion functions,</a><br>
|
||||
<a href="#Choosing">buffer types, and arithmetic types</a><br>
|
||||
<a href="#Intrinsic">Built-in support for Intrinsics</a><br>
|
||||
<a href="#Performance">Performance</a><br>
|
||||
<a href="#Timings">Timings</a><br>
|
||||
<a href="#FAQ">Overall FAQ</a><br>
|
||||
<a href="#Release-history">Release history</a><br>
|
||||
<a href="#Changes-requested-by-formal-review">Changes
|
||||
requested by formal review</a><br>
|
||||
<a href="#Other-changes-since-formal-review">Other changes since
|
||||
formal review</a><br>
|
||||
<a href="#Compatibility">Compatibility with interim releases</a><br>
|
||||
<a href="#C++03-support">C++03 support for C++11 features</a><br>
|
||||
<a href="#Future-directions">Future directions</a><br>
|
||||
<a href="#Acknowledgements">Acknowledgements</a><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="Abstract">Abstract</a></h2>
|
||||
|
||||
<p>Boost.Endian provides facilities to manipulate the
|
||||
<a href="#Introduction-to-endianness">endianness</a> of integers and user-defined types.</p>
|
||||
<ul>
|
||||
<li>Three approaches to endianness are supported. Each has a
|
||||
long history of successful use, and each approach has use cases where it is
|
||||
preferred over the other approaches.<br>
|
||||
</li>
|
||||
<li>Primary uses:<br>
|
||||
<ul>
|
||||
<li>Data portability. The Endian library supports binary data exchange, via either external media or network transmission,
|
||||
regardless of platform endianness.<br>
|
||||
</li>
|
||||
<li>Program portability. POSIX-based and
|
||||
Windows-based operating systems traditionally supply libraries with
|
||||
non-portable functions to perform endian conversion. There are at least four
|
||||
incompatible sets of functions in common use. The Endian library is
|
||||
portable across all C++ platforms.<br>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
<li>Secondary use: Minimizing data size via sizes and/or alignments not supported by the
|
||||
standard C++ integer types.</li>
|
||||
</ul>
|
||||
|
||||
<h2><a name="Introduction-to-endianness">Introduction to endianness</a></h2>
|
||||
|
||||
<p>Consider the following code:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>int16_t i = 0x0102;
|
||||
FILE * file = fopen("test.bin", "wb"); // binary file!
|
||||
fwrite(&i, sizeof(int16_t), 1, file);
|
||||
fclose(file);</pre>
|
||||
</blockquote>
|
||||
<p>On OS X, Linux, or Windows systems with an Intel CPU, a hex dump
|
||||
of the "test.bin" output file produces:</p>
|
||||
<blockquote>
|
||||
<p><code>0201</code></p>
|
||||
</blockquote>
|
||||
<p>On OS X systems with a PowerPC CPU, or Solaris systems with a SPARC CPU, a hex dump of the "test.bin"
|
||||
output file produces:</p>
|
||||
<blockquote>
|
||||
<p><code>0102</code></p>
|
||||
</blockquote>
|
||||
<p>What's happening here is that Intel CPUs order the bytes of an integer with
|
||||
the least-significant byte first, while SPARC CPUs place the most-significant
|
||||
byte first. Some CPUs, such as the PowerPC, allow the operating system to
|
||||
choose which ordering applies.</p>
|
||||
<p><a name="definition"></a>Most-significant-byte-first ordering is traditionally called "big endian"
|
||||
ordering and least-significant-byte-first is traditionally called
|
||||
"little-endian" ordering. The names are derived from
|
||||
<a href="http://en.wikipedia.org/wiki/Jonathan_Swift" title="Jonathan Swift">
|
||||
Jonathan Swift</a>'s satirical novel <i>
|
||||
<a href="http://en.wikipedia.org/wiki/Gulliver's_Travels" title="Gulliver's Travels">
|
||||
Gulliver’s Travels</a></i>, where rival kingdoms opened their soft-boiled eggs
|
||||
at different ends.</p>
|
||||
<p>See Wikipedia's
|
||||
<a href="http://en.wikipedia.org/wiki/Endianness">Endianness</a> article for an
|
||||
extensive discussion of endianness.</p>
|
||||
<p>Programmers can usually ignore endianness, except when reading a core
|
||||
dump on little-endian systems. But programmers have to deal with endianness when exchanging binary integers and binary floating point
|
||||
values between computer systems with differing endianness, whether by physical file transfer or over a network.
|
||||
And programmers may also want to use the library when minimizing either internal or
|
||||
external data sizes is advantageous.</p>
|
||||
<h2><a name="Introduction">Introduction</a> to the Boost.Endian library</h2>
|
||||
|
||||
<p>Boost.Endian provides three different approaches to dealing with
|
||||
|
||||
endianness. All three approaches support integers and user-define types (UDTs).</p>
|
||||
|
||||
<p>Each approach has a long history of successful use, and each approach has use
|
||||
cases where it is preferred to the other approaches.</p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><b><a href="conversion.html">Endian conversion functions</a> -</b> The
|
||||
application uses the built-in integer types to hold values, and calls the
|
||||
provided conversion functions to convert byte ordering as needed. Both mutating
|
||||
and non-mutating conversions are supplied, and each comes in unconditional and
|
||||
conditional variants.</p>
|
||||
|
||||
<p><b><a href="buffers.html">Endian buffer types</a> -</b> The application uses the provided endian
|
||||
buffer types
|
||||
to hold values, and explicitly converts to and from the built-in integer types. Buffer sizes of 8, 16, 24, 32, 40, 48, 56, and 64 bits (i.e.
|
||||
1, 2, 3, 4, 5, 6, 7, and 8 bytes) are provided. Unaligned integer buffer types
|
||||
are provided for all sizes, and aligned buffer types are provided for 16, 32, and
|
||||
64-bit sizes. The provided specific types are typedefs for a generic class
|
||||
template that may be used directly for less common use cases.</p>
|
||||
|
||||
<p><b><a href="arithmetic.html">Endian arithmetic types</a> -</b> The
|
||||
application uses the provided endian arithmetic types, which supply the same
|
||||
operations as the built-in C++ arithmetic types. All conversions are implicit.
|
||||
Arithmetic sizes of 8, 16, 24, 32, 40, 48, 56, and 64 bits (i.e. 1, 2, 3, 4, 5,
|
||||
6, 7, and 8 bytes) are provided. Unaligned integer types are provided for all
|
||||
sizes and aligned
|
||||
arithmetic types are provided for 16, 32, and 64-bit sizes. The provided
|
||||
specific types are typedefs for a generic class template that may be used
|
||||
directly in generic code of for less common use cases.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p>Boost Endian is a header-only library. C++11 features
|
||||
affecting interfaces, such as <code>noexcept</code>, are used only if available.
|
||||
See <a href="#C++03-support">C++03 support for C++11 features</a> for details.</p>
|
||||
|
||||
<h2><a name="Choosing">Choosing</a> between conversion functions, buffer types,
|
||||
and arithmetic types</h2>
|
||||
|
||||
<p>This section has been moved to its own <a href="choosing_approach.html">
|
||||
Choosing the Approach</a> page. </p>
|
||||
|
||||
<h2>Built-in support for <a name="Intrinsic">Intrinsic</a>s</h2>
|
||||
<p>Most compilers, including GCC, Clang, and Visual C++, supply built-in support for byte swapping intrinsics.
|
||||
The Endian library uses these intrinsics when available since they may result in smaller and faster generated code, particularly for
|
||||
optimized
|
||||
builds.</p>
|
||||
<p>Defining the macro <code>BOOST_ENDIAN_NO_INTRINSICS</code> will suppress use
|
||||
of the intrinsics. This is useful when a compiler has no intrinsic support or
|
||||
fails to locate the appropriate header, perhaps because it
|
||||
is an older release or has very limited supporting libraries.</p>
|
||||
<p>The macro <code>BOOST_ENDIAN_INTRINSIC_MSG</code> is defined as
|
||||
either <code>"no byte swap intrinsics"</code> or a string describing the
|
||||
particular set of intrinsics being used. This is useful for eliminating missing
|
||||
intrinsics as a source of performance issues.</p>
|
||||
|
||||
<h2><a name="Performance">Performance</a></h2>
|
||||
|
||||
<p>Consider this problem:</p>
|
||||
|
||||
<div align="center">
|
||||
<center>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<p align="center"><i><b><a name="Example-1">Example 1</a></b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><b><i>Add 100 to a big endian value in a file, then write the
|
||||
result to a file</i> </b> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i><b>Endian arithmetic type approach</b></i></td>
|
||||
<td><i><b>Endian conversion function approach</b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<pre>big_int32_at x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
x += 100;
|
||||
|
||||
... write x to a file ...
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
int32_t x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
big_to_native_inplace(x);
|
||||
x += 100;
|
||||
native_to_big_inplace(x);
|
||||
|
||||
... write x to a file ...
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<p><b>There will be no performance difference between the two approaches in
|
||||
optimized builds,
|
||||
regardless of the native endianness of the machine.</b> That's because optimizing compilers will generate exactly the same code for each. That conclusion was confirmed by
|
||||
studying the generated assembly code for GCC and Visual C++. Furthermore, time
|
||||
spent doing I/O will determine the speed of this application.</p>
|
||||
|
||||
<p>Now consider a slightly different problem: </p>
|
||||
|
||||
<div align="center">
|
||||
<center>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<p align="center"><b><i><a name="Example-2">Example 2</a></i></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><i><b>Add a million values to a big endian value in a file, then write the
|
||||
result to a file </b></i> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i><b>Endian arithmetic type approach</b></i></td>
|
||||
<td><i><b>Endian conversion function approach</b></i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<pre>big_int32_at x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
for (int32_t i = 0; i < 1000000; ++i)
|
||||
x += i;
|
||||
|
||||
... write x to a file ...
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>int32_t x;
|
||||
|
||||
... read into x from a file ...
|
||||
|
||||
big_to_native_inplace(x);
|
||||
|
||||
for (int32_t i = 0; i < 1000000; ++i)
|
||||
x += i;
|
||||
|
||||
native_to_big_inplace(x);
|
||||
|
||||
... write x to a file ...
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<p>With the Endian arithmetic approach, on little endian platforms an implicit conversion from and then back to
|
||||
big endian is done inside the loop. With the Endian conversion function
|
||||
approach, the user has ensured the conversions are done outside the loop, so the
|
||||
code may run more quickly on little endian platforms.</p>
|
||||
|
||||
<h3><a name="Timings">Timings</a></h3>
|
||||
<p>These tests were run against release builds on a circa 2012 4-core little endian X64 Intel Core i5-3570K
|
||||
CPU @ 3.40GHz under Windows 7.</p>
|
||||
|
||||
<p><b>Caveat emptor: The Windows CPU timer has very high granularity. Repeated
|
||||
runs of the same tests often yield considerably different results.</b></p>
|
||||
|
||||
<p>See <b>test/loop_time_test.cpp</b> for the actual code and <b>benchmark/Jamfile.v2</b> for the build
|
||||
setup.</p>
|
||||
|
||||
|
||||
<div align="center">
|
||||
<center>
|
||||
<table border="1" cellpadding="5" cellspacing="0"style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr><td colspan="6" align="center"><b>GNU C++ version 4.8.2 on Linux virtual
|
||||
machine</b></td></tr>
|
||||
<tr><td colspan="6" align="center"><b> Iterations: 10'000'000'000, Intrinsics: __builtin_bswap16, etc.</b></td></tr>
|
||||
<tr><td><b>Test Case</b></td>
|
||||
<td align="center"><b>Endian<br>arithmetic<br>type</b></td>
|
||||
<td align="center"><b>Endian<br>conversion<br>function</b></td>
|
||||
</tr>
|
||||
<tr><td>16-bit aligned big endian</td><td align="right">8.46 s</td><td align="right">5.28 s</td></tr>
|
||||
<tr><td>16-bit aligned little endian</td><td align="right">5.28 s</td><td align="right">5.22 s</td></tr>
|
||||
<tr><td>32-bit aligned big endian</td><td align="right">8.40 s</td><td align="right">2.11 s</td></tr>
|
||||
<tr><td>32-bit aligned little endian</td><td align="right">2.11 s</td><td align="right">2.10 s</td></tr>
|
||||
<tr><td>64-bit aligned big endian</td><td align="right">14.02 s</td><td align="right">3.10 s</td></tr>
|
||||
<tr><td>64-bit aligned little endian</td><td align="right">3.00 s</td><td align="right">3.03 s</td></tr>
|
||||
|
||||
</table>
|
||||
</center>
|
||||
</div>
|
||||
<p></p>
|
||||
|
||||
<div align="center"> <center>
|
||||
<table border="1" cellpadding="5" cellspacing="0"style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr><td colspan="6" align="center"><b>Microsoft Visual C++ version 14.0</b></td></tr>
|
||||
<tr><td colspan="6" align="center"><b> Iterations: 10'000'000'000, Intrinsics: cstdlib _byteswap_ushort, etc.</b></td></tr>
|
||||
<tr><td><b>Test Case</b></td>
|
||||
<td align="center"><b>Endian<br>arithmetic<br>type</b></td>
|
||||
<td align="center"><b>Endian<br>conversion<br>function</b></td>
|
||||
</tr>
|
||||
<tr><td>16-bit aligned big endian</td><td align="right">8.27 s</td><td align="right">5.26 s</td></tr>
|
||||
<tr><td>16-bit aligned little endian</td><td align="right">5.29 s</td><td align="right">5.32 s</td></tr>
|
||||
<tr><td>32-bit aligned big endian</td><td align="right">8.36 s</td><td align="right">5.24 s</td></tr>
|
||||
<tr><td>32-bit aligned little endian</td><td align="right">5.24 s</td><td align="right">5.24 s</td></tr>
|
||||
<tr><td>64-bit aligned big endian</td><td align="right">13.65 s</td><td align="right">3.34 s</td></tr>
|
||||
<tr><td>64-bit aligned little endian</td><td align="right">3.35 s</td><td align="right">2.73 s</td></tr>
|
||||
</table>
|
||||
</center></div>
|
||||
|
||||
|
||||
<h2>Overall <a name="FAQ">FAQ</a></h2>
|
||||
|
||||
<p><b>Is the implementation header only?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>Yes.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p><b>Are C++03 compilers supported?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>Yes.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p><b>Does the implementation use compiler intrinsic built-in byte swapping?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>Yes, if available. See <a href="#Intrinsic">Intrinsic built-in support</a>.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p><b>Why bother with endianness?</b></p>
|
||||
<blockquote>
|
||||
<p>Binary data portability is the primary use case.</p>
|
||||
</blockquote>
|
||||
<p><b>Does endianness have any uses outside of portable binary file or network
|
||||
I/O formats?</b> </p>
|
||||
<blockquote>
|
||||
<p>Using the unaligned integer types with a size tailored to the application's
|
||||
needs is a minor secondary use that saves internal or external memory space. For
|
||||
example, using <code>big_int40_buf_t</code> or <code>big_int40_t</code> in a
|
||||
large array saves a lot of space compared to one of the 64-bit types.</p>
|
||||
</blockquote>
|
||||
<p><b>Why bother with binary I/O? Why not just use C++ Standard Library stream
|
||||
inserters and extractors?</b></p>
|
||||
<blockquote>
|
||||
<p>Data interchange formats often specify binary integer data.</p>
|
||||
<p>Binary integer data is smaller and therefore I/O is faster and file sizes
|
||||
are smaller. Transfer between systems is less expensive.</p>
|
||||
<p >Furthermore, binary integer data is of fixed size, and so fixed-size disk
|
||||
records are possible without padding, easing sorting and allowing random access.</p>
|
||||
<p >Disadvantages, such as the inability to use text utilities on the
|
||||
resulting files, limit usefulness to applications where the binary I/O
|
||||
advantages are paramount.</p>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Which is better, big-endian or little-endian?</b></p>
|
||||
<blockquote>
|
||||
<p>Big-endian tends to be preferred in a networking environment and is a bit
|
||||
more of an industry standard, but little-endian may be preferred for
|
||||
applications that run primarily on x86, x86-64, and other little-endian
|
||||
CPU's. The <a href="http://en.wikipedia.org/wiki/Endian">Wikipedia</a> article
|
||||
gives more pros and cons.</p>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Why are only big and little native endianness supported?</b></p>
|
||||
<blockquote>
|
||||
<p>These are the only endian schemes that have any practical value today. PDP-11
|
||||
and the other middle endian approaches are interesting curiosities
|
||||
but have no relevance for today's C++ developers. The same is true for
|
||||
architectures that allow runtime endianness switching. The
|
||||
<a href="conversion.html#native-order-specification">specification for native
|
||||
ordering</a> has been carefully crafted to allow support for such orderings in
|
||||
the future, should the need arise. Thanks to Howard Hinnant for suggesting this. </p>
|
||||
</blockquote>
|
||||
|
||||
<p><b>Why do both the buffer and arithmetic types exist?</b></p>
|
||||
<blockquote>
|
||||
<p>Conversions in the buffer types are explicit. Conversions in the arithmetic
|
||||
types are implicit. This fundamental difference is a deliberate design feature
|
||||
that would be lost if the inheritance hierarchy were collapsed.</p>
|
||||
<p>The original design provided only arithmetic types. Buffer types were
|
||||
requested during formal review by those wishing total control over when
|
||||
conversion occurs. They also felt that buffer types would be less likely to be
|
||||
misused by maintenance programmers not familiar with the implications of
|
||||
performing a lot of integer operations on the endian arithmetic integer types.</p>
|
||||
</blockquote>
|
||||
<p><b>What is gained by using the buffer types rather than always just using the
|
||||
arithmetic types?</b></p>
|
||||
<blockquote>
|
||||
<p>Assurance that hidden conversions are not performed. This is of overriding
|
||||
importance to users concerned about achieving the ultimate in terms of speed. </p>
|
||||
<p>"Always just using the arithmetic types" is fine for other users. When the
|
||||
ultimate in speed needs to be ensured, the arithmetic types can be used in the
|
||||
same design patterns or idioms that would be used for buffer types, resulting in
|
||||
the same code being generated for either types.</p>
|
||||
</blockquote>
|
||||
|
||||
<p><b>What are the limitations of integer support?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>Tests have only been
|
||||
performed on machines that use two's complement arithmetic. The Endian
|
||||
conversion functions only support 16, 32, and 64-bit aligned integers. The
|
||||
endian types only support 8, 16, 24, 32, 40, 48, 56, and 64-bit unaligned integers,
|
||||
and 8, 16, 32, and 64-bit aligned integers.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p><b>Why is there no floating point support?</b></p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p>An attempt was made to support four-byte <code>float</code>s and eight-byte
|
||||
<code>double</code>s, limited to
|
||||
<a href="http://en.wikipedia.org/wiki/IEEE_floating_point">IEEE 754</a> (also
|
||||
know as ISO/IEC/IEEE 60559) floating point and further limited to systems where
|
||||
floating point endianness does not differ from integer
|
||||
endianness.</p>
|
||||
|
||||
<p>Even with those limitations, support for floating point types was not
|
||||
reliable and was removed. For example, simply reversing the endianness of a
|
||||
floating point number can result in a signaling-NAN. For all practical purposes,
|
||||
binary serialization and endianness for integers are one and the same problem.
|
||||
That is not true for floating point numbers, so binary serialization interfaces
|
||||
and formats for floating point does not fit well in an endian-based library.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h2><a name="Release-history">Release history</a></h2>
|
||||
<h3><a name="Changes-requested-by-formal-review">Changes requested by formal review</a></h3>
|
||||
<p>The library was reworked from top to bottom to accommodate changes requested
|
||||
during the formal review. See <a href="mini_review_topics.html">Mini-Review</a>
|
||||
page for details.</p>
|
||||
<h3><a name="Other-changes-since-formal-review">Other changes since formal
|
||||
review</a></h3>
|
||||
<ul>
|
||||
<li>Header <code>boost/endian/endian.hpp</code> has been renamed to <code>
|
||||
boost/endian/arithmetic.hpp</code>. Headers
|
||||
<code>boost/endian/conversion.hpp</code> and <code>boost/endian/buffers.hpp</code> have been
|
||||
added.
|
||||
Infrastructure file names were changed accordingly.</li>
|
||||
<li>The endian arithmetic type aliases have been renamed,
|
||||
using a naming pattern that is consistent for both integer and floating point,
|
||||
and a consistent set of aliases supplied for the endian buffer types.</li>
|
||||
<li>The unaligned-type alias names still have the <code>_t</code> suffix, but
|
||||
the aligned-type alias names now have an <code>_at</code> suffix..</li>
|
||||
<li><code>endian_reverse()</code> overloads for <code>int8_t</code> and <code>
|
||||
uint8_t</code> have been added for improved generality. (Pierre Talbot)</li>
|
||||
<li>Overloads of <code>endian_reverse_inplace()</code> have been replaced with a single <code>
|
||||
endian_reverse_inplace()</code> template. (Pierre Talbot)</li>
|
||||
<li>For X86 and X64 architectures, which permit unaligned loads and stores,
|
||||
unaligned little endian buffer and arithmetic types use regular loads and
|
||||
stores when the size is exact. This makes unaligned little endian buffer and
|
||||
arithmetic types significantly more efficient on these architectures. (Jeremy
|
||||
Maitin-Shepard)</li>
|
||||
<li>C++11 features affecting interfaces, such as <code>noexcept</code>, are now used.
|
||||
C++03 compilers are still
|
||||
supported.</li>
|
||||
<li>Acknowledgements have been updated.</li>
|
||||
</ul>
|
||||
|
||||
<h2><a name="Compatibility">Compatibility</a> with interim releases</h2>
|
||||
|
||||
<p>Prior to the official Boost release, class template <code>
|
||||
endian_arithmetic</code> has been used for a decade or more with the same
|
||||
functionality but under the name <code>endian</code>. Other names also changed
|
||||
in the official release. If the macro <code>BOOST_ENDIAN_DEPRECATED_NAMES</code>
|
||||
is defined, those old now deprecated names are still supported. However, the
|
||||
class template <code>endian</code> name is only provided for compilers
|
||||
supporting C++11 template aliases. For C++03 compilers, the name will have to be
|
||||
changed to <code>endian_arithmetic</code>.</p>
|
||||
|
||||
<p>To support backward header compatibility, deprecated header <code>boost/endian/endian.hpp</code>
|
||||
forwards to <code>boost/endian/arithmetic.hpp</code>. It requires <code>
|
||||
BOOST_ENDIAN_DEPRECATED_NAMES</code> be defined. It should only be used while
|
||||
transitioning to the official Boost release of the library as it will be removed
|
||||
in some future release.</p>
|
||||
|
||||
<h2><a name="C++03-support">C++03 support</a> for C++11 features</h2>
|
||||
|
||||
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||
<tr>
|
||||
<td><b>C++11 Feature</b></td>
|
||||
<td><b>Action with C++03 Compilers </b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Scoped enums </td>
|
||||
<td>Uses header <code class="computeroutput">
|
||||
<a href="http://www.boost.org/libs/core/doc/html/core/scoped_enum.html">
|
||||
<span class="identifier">boost</span><span class="special">/</span><span class="identifier">core</span><span class="special">/</span><span class="identifier">scoped_enum</span><span class="special">.</span><span class="identifier">hpp</span></a></code><span class="identifier">
|
||||
to emulate C++11 scoped enums.</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>noexcept</code></td>
|
||||
<td><span class="identifier">Uses BOOST_NOEXCEPT macro, which is defined as
|
||||
null for compilers not supporting this C++11 feature.</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>C++11 PODs (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm">N2342</a>)</td>
|
||||
<td><span class="identifier">Takes advantage of C++03 compilers that
|
||||
relax C++03 POD rules, but see Limitations
|
||||
<a href="buffers.html#Limitations">here</a> and
|
||||
<a href="arithmetic.html#Limitations">here</a>. Also see macros for explicit
|
||||
POD control <a href="buffers.html#Compilation">here</a> and
|
||||
<a href="arithmetic.html#Compilation">here</a>.</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="Future-directions">Future directions</a></h2>
|
||||
|
||||
<p><b>Standardization.</b> The plan is to submit Boost.Endian to the C++
|
||||
standards committee for possible inclusion in a Technical Specification or the
|
||||
C++ standard itself.</p>
|
||||
|
||||
<p><b>Specializations for <code>numeric_limits</code>.</b> Roger Leigh
|
||||
requested that all <code>boost::endian</code> types provide <code>numeric_limits</code>
|
||||
specializations. See <a href="https://github.com/boostorg/endian/issues/4">
|
||||
GitHub issue 4</a>.</p>
|
||||
|
||||
<p><b>Character buffer support.</b> Peter Dimov pointed out during the
|
||||
mini-review that getting and setting basic arithmetic types (or <code><cstdint></code>
|
||||
equivalents) from/to an offset into an array of unsigned char is a common need.
|
||||
See <a href="http://lists.boost.org/Archives/boost/2015/01/219574.php">
|
||||
Boost.Endian mini-review posting</a>.</p>
|
||||
|
||||
<p><b>Out-of-range detection.</b> Peter Dimov pointed suggested during the
|
||||
mini-review that throwing an exception on buffer values being out-of-range might
|
||||
be desirable. See the end of
|
||||
<a href="http://lists.boost.org/Archives/boost/2015/01/219659.php">this posting</a>
|
||||
and subsequent replies.</p>
|
||||
|
||||
<h2><a name="Acknowledgements">Acknowledgements</a></h2>
|
||||
<p>Comments and suggestions were received from Adder, Benaka Moorthi,
|
||||
Christopher Kohlhoff, Cliff Green, Daniel James, Dave Handley, Gennaro Proto, Giovanni Piero
|
||||
Deretta, Gordon Woodhull, dizzy, Hartmut Kaiser, Howard Hinnant, Jason Newton, Jeff Flinn, Jeremy Maitin-Shepard, John Filo, John
|
||||
Maddock, Kim Barrett, Marsh Ray, Martin Bonner, Mathias Gaunard, Matias
|
||||
Capeletto, Neil Mayhew, Nevin Liber,
|
||||
Olaf van der Spek, Paul Bristow, Peter Dimov, Pierre Talbot, Phil Endecott,
|
||||
Philip Bennefall, Pyry Jahkola,
|
||||
Rene Rivera, Robert Stewart, Roger Leigh, Roland Schwarz, Scott McMurray, Sebastian Redl, Tim
|
||||
Blechmann, Tim Moore, tymofey, Tomas Puverle, Vincente Botet, Yuval Ronen and
|
||||
Vitaly Budovsk. Apologies if anyone has been missed.</p>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->05 April, 2016<!--webbot bot="Timestamp" endspan i-checksum="29990" --></p>
|
||||
<p>© Copyright Beman Dawes, 2011, 2013</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See
|
||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,150 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Endian Mini-Review</title>
|
||||
</head>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
<body>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
|
||||
<tr>
|
||||
<td width="339">
|
||||
<a href="../../../index.html">
|
||||
<img src="../../../boost.png" alt="Boost logo" align="middle" border="0" width="277" height="86"></a></td>
|
||||
<td align="middle" width="1253">
|
||||
<b>
|
||||
<font size="6">Endian </font></b><font size="6"><b>Mini-Review</b></font></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse"
|
||||
bordercolor="#111111" bgcolor="#D7EEFF" width="100%">
|
||||
<tr>
|
||||
<td><b>
|
||||
<a href="index.html">Endian Home</a>
|
||||
<a href="conversion.html">Conversion Functions</a>
|
||||
<a href="arithmetic.html">Arithmetic Types</a>
|
||||
<a href="buffers.html">Buffer Types</a>
|
||||
<a href="choosing_approach.html">Choosing Approach</a></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p></p>
|
||||
|
||||
<p>The results of the Boost.Endian formal review included a list of issues to be
|
||||
resolved before a mini-review.</p>
|
||||
|
||||
<p>The issues are shown in <b>bold</b> below, with the resolution indicated.</p>
|
||||
|
||||
<p><b>1. Common use case scenarios should be developed.</b></p>
|
||||
<blockquote>
|
||||
|
||||
<p>Done. The documentation have been refactored. A page is now devoted to
|
||||
<a href="choosing_approach.html">Choosing the Approach</a> to endianness. See
|
||||
<a href="choosing_approach.html#Use-cases">Use cases</a> for use case
|
||||
scenarios.</p>
|
||||
</blockquote>
|
||||
<p><b>2. Example programs should be developed for the common use case scenarios.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. See <a href="choosing_approach.html">Choosing the Approach</a>.
|
||||
Example code has been added throughout.</p>
|
||||
</blockquote>
|
||||
<p><b>3. Documentation should illuminate the differences between endian
|
||||
integer/float type and endian conversion approaches to the common use
|
||||
case scenarios, and provide guidelines for choosing the most appropriate
|
||||
approach in user's applications.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. See <a href="choosing_approach.html">Choosing the Approach</a>.</p>
|
||||
</blockquote>
|
||||
<p><b>4 .Conversion functions supplying results via return should be provided.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. See <a href="conversion.html">ConversionFunctions</a>.</p>
|
||||
</blockquote>
|
||||
<p><b>5. Platform specific performance enhancements such as use of compiler intrinsics or relaxed alignment requirements should be supported.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. Compiler (Clang, GCC, VisualC++, etc.) intrinsics and built-in
|
||||
functions are used in the implementation where appropriate, as requested. See
|
||||
<a href="index.html#Intrinsic">Built-in support for Intrinsics</a>. See
|
||||
<a href="index.html#Timings">Timings for Example 2</a> to gauge the impact of
|
||||
intrinsics.</p>
|
||||
</blockquote>
|
||||
<p><b>6. Endian integer (and floating) types should be implemented via the
|
||||
conversion functions. If that can't be done efficiently, consideration
|
||||
should be given to expanding the conversion function signatures to
|
||||
resolve the inefficiencies.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. For the endian types, the implementation uses the endian conversion
|
||||
functions, and thus the intrinsics, as requested.</p>
|
||||
</blockquote>
|
||||
<p><b>7. Benchmarks that measure performance should be provided. It should be
|
||||
possible to compare platform specific performance enhancements against
|
||||
portable base implementations, and to compare endian integer approaches
|
||||
against endian conversion approaches for the common use case scenarios.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. See <a href="index.html#Timings">Timings for Example 2</a>. The <code>endian/test</code> directory
|
||||
also contains several additional benchmark and speed test programs.</p>
|
||||
</blockquote>
|
||||
<p><b>8. Float (32-bits) and double (64-bits) should be supported. IEEE 754 is
|
||||
the primary use case.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. The <a href="buffers.html">endian buffer types</a>,
|
||||
<a href="arithmetic.html">endian arithmetic types</a> and
|
||||
<a href="conversion.html">endian conversion functions</a> now support 32-bit (<code>float)</code>
|
||||
and 64-bit <code>(double)</code> floating point, as requested.</p>
|
||||
</blockquote>
|
||||
<p><b>9. Support for user defined types (UDTs) is desirable, and should be
|
||||
provided where there would be no conflict with the other concerns.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. See <a href="conversion.html#Customization-points">Customization
|
||||
points for user-defined types (UDTs)</a>.</p>
|
||||
</blockquote>
|
||||
<p><b>10. There is some concern that endian integer/float arithmetic operations
|
||||
might used inadvertently or inappropriately. The impact of adding an endian_buffer
|
||||
class without arithmetic operations should be investigated.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. The endian types have been decomposed into class template <code>
|
||||
<a href="buffers.html">endian_buffer</a></code> and class template <code>
|
||||
<a href="arithmetic.html">endian_arithmetic</a></code>. Class
|
||||
<code>endian_buffer</code> is a public base class for <code>endian_arithmetic</code>,
|
||||
and can also be used by users as a stand-alone class.</p>
|
||||
</blockquote>
|
||||
<p><b>11. Stream insertion and extraction of the endian integer/float types should
|
||||
be documented and included in the test coverage.</b></p>
|
||||
<blockquote>
|
||||
<p>Done. See <a href="buffers.html#Stream-inserter">Stream inserter</a> and
|
||||
<a href="buffers.html#Stream-extractor">Stream extractor</a>.</p>
|
||||
</blockquote>
|
||||
<p><b>12. Binary I/O support that was investigated during development of the Endian
|
||||
library should be put up for mini-review for inclusion in the Boost I/O
|
||||
library.</b></p>
|
||||
|
||||
<blockquote>
|
||||
<p>Not done yet. Will be handled as a separate min-review soon after the
|
||||
Endian mini-review.</p>
|
||||
|
||||
</blockquote>
|
||||
<p><b>13. Other requested changes.</b></p>
|
||||
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>In addition to the named-endianness conversion functions, functions that perform
|
||||
compile-time (via template) and run-time (via function argument) dispatch
|
||||
are now provided.</li>
|
||||
<li><code>order::native</code> is now a synonym for <code>order::big</code>
|
||||
or <code>order::little</code> according to the endianness of the platform. This reduces the number of template specializations required.</li>
|
||||
<li>Headers have been reorganized to make them easier to read,
|
||||
with a synopsis at the front and implementation following.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->19 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38903" --></p>
|
||||
<p>© Copyright Beman Dawes, 2014</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See
|
||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/ LICENSE_1_0.txt</a></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,31 +0,0 @@
|
||||
Windows
|
||||
-------
|
||||
|
||||
Prerequisites
|
||||
|
||||
Boost libraries available in boost-root\stage\lib. Example:
|
||||
|
||||
cd boost-root
|
||||
.\bootstrap
|
||||
.\b2 --with-system --with-chrono --with-timer link=shared stage
|
||||
|
||||
The provided Visual Studio solution (endian/test/msvc/endian.sln) has a property page
|
||||
(endian/test/msvc/common.prop) with these Common Properties set (do not include the
|
||||
double quotes):
|
||||
|
||||
VC++ Directores|Executable Directories: prefix default value with "..\..\..\..\..\stage\lib;"
|
||||
(Click "Inherit from parent or project defaults" if not checked)
|
||||
|
||||
C/C++|General|Additional Include Directories: prefix default value with "..\..\..\..\..\stage\lib;"
|
||||
|
||||
Linker|General|Additional Library Directories: prefix default value with "..\..\..\..\..\stage\lib;"
|
||||
|
||||
C/C++|Preprocessor: prefix default value with "BOOST_ALL_DYN_LINK;"
|
||||
|
||||
IMPORTANT: If Preprocessor macros are supplied via a common property page,
|
||||
<inherit from parent or project defaults> must be set for each project!
|
||||
|
||||
------------------------------------------------------------------------------------------
|
||||
Copyright Beman Dawes, 2013
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
See http://www.boost.org/LICENSE_1_0.txt
|
134
doc/p0803r0.html
134
doc/p0803r0.html
@ -1,134 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style>
|
||||
body
|
||||
{
|
||||
font-family: arial, sans-serif;
|
||||
max-width: 6.75in;
|
||||
margin: 0px auto;
|
||||
font-size: 85%;
|
||||
}
|
||||
ins {background-color: #CCFFCC; text-decoration: none;}
|
||||
del {background-color: #FFCACA; text-decoration: none;}
|
||||
pre {background-color: #D7EEFF; font-size: 95%; font-family: "courier new", courier, serif;}
|
||||
code {font-family: "courier new", courier, serif;}
|
||||
table {font-size: 90%;}
|
||||
</style>
|
||||
<title>Endian RFC</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="left">Doc. no.:</td>
|
||||
<td align="left">P0803R0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Date:</td>
|
||||
<td align="left">
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%Y-%m-%d" startspan -->2017-10-15<!--webbot bot="Timestamp" endspan i-checksum="12057" --></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Reply to:</td>
|
||||
<td align="left">Beman Dawes <bdawes at acm dot org>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Audience:</td>
|
||||
<td align="left">Library Evolution</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<h1 align="center">Endian Library Request for Comments (R0)</h1>
|
||||
|
||||
|
||||
<h2>Abstract</h2>
|
||||
<p>The Boost Endian library manipulates the
|
||||
<a href="https://en.wikipedia.org/wiki/Endianness">endianness</a> of integers
|
||||
and user-defined types. It provides three approaches to dealing with endianness:
|
||||
conversion functions, buffer classes, and arithmetic classes. Each approach
|
||||
has use cases where it is preferred over the other approaches. The purpose of
|
||||
this RFC is to determine interest in adding all or any of these components to
|
||||
the C++ standard library or a library TS.</p>
|
||||
<h2>Introduction</h2>
|
||||
<p>The Boost Endian documentation (<a href="https://www.boost.org/libs/endian/doc/index.html">www.boost.org/libs/endian/doc</a>)
|
||||
provides an <a href="https://www.boost.org/libs/endian/doc/index.html">overview</a>
|
||||
and detailed technical specifications for the
|
||||
<a href="https://www.boost.org/libs/endian/doc/conversion.html">conversion
|
||||
functions</a>, <a href="https://www.boost.org/libs/endian/doc/arithmetic.html">
|
||||
arithmetic types</a>, and
|
||||
<a href="https://www.boost.org/libs/endian/doc/buffers.html">buffer types</a>.
|
||||
</p>
|
||||
<p>A separate discussion covers
|
||||
<a href="https://www.boost.org/libs/endian/doc/choosing_approach.html">choosing
|
||||
between the three approaches</a> provided by the library.</p>
|
||||
<p>For those not interested in plowing through the entire documentation, the
|
||||
<a href="https://www.boost.org/libs/endian/doc/index.html#FAQ">Overall FAQ</a>,
|
||||
<a href="https://www.boost.org/libs/endian/doc/conversion.html#FAQ">Conversion
|
||||
FAQ</a>, <a href="https://www.boost.org/libs/endian/doc/arithmetic.html#FAQ">
|
||||
Arithmetic FAQ</a>, and
|
||||
<a href="https://www.boost.org/libs/endian/doc/buffers.html#FAQ">Buffers FAQ</a>
|
||||
answer a lot of question likely to arise during standardization.</p>
|
||||
<h2>Motivation for standardization</h2>
|
||||
<ul>
|
||||
<li>Lack of any one de facto standard endianness capability in either C or
|
||||
C++. While most platforms provides some way to handle endianness in C, the
|
||||
mechanism varies from platform to platform.</li>
|
||||
<li>Commonly used endian handling functions are extremely error prone. While
|
||||
the Boost Endian conversion functions have the same problems, the buffer and
|
||||
arithmetic classes do not.</li>
|
||||
<li>Surprisingly difficult to write and test yourself in a portable yet
|
||||
efficient (i.e. using intrinsics) way. </li>
|
||||
<li>Explicit requests for standardization from Boost Endian users.</li>
|
||||
<li>The Boost library is existing practice with years of both implementation
|
||||
and end-user experience.</li>
|
||||
<li>The committee has already failed once to standardize endian conversion
|
||||
functions; perhaps now is time to do it right.</li>
|
||||
</ul>
|
||||
<h2>Impact on the standard library</h2>
|
||||
<p>All three proposed approaches to endianness would be a pure additions to the
|
||||
standard library and would break no existing user code (modulo the usual
|
||||
namespace caveats).</p>
|
||||
<h2>Proposed wording</h2>
|
||||
<p>The Boost Endian reference documentation for
|
||||
<a href="https://www.boost.org/libs/endian/doc/conversion.html#Reference">
|
||||
Conversion</a>,
|
||||
<a href="https://www.boost.org/libs/endian/doc/arithmetic.html#endian">
|
||||
Arithmetic</a>, and
|
||||
<a href="https://www.boost.org/libs/endian/doc/buffers.html#endian">Buffer</a>
|
||||
approaches follows the standard library's <i>Method of description</i>
|
||||
[description], so provides a fairly close approximation of what proposed wording
|
||||
would look like. Actual proposed wording will be provided in a proposal document
|
||||
for any portions of the library of interest to the committee. Names will need
|
||||
the usual bikeshedding.</p>
|
||||
<h2>Questions for the Library Evolution Group</h2>
|
||||
<ul>
|
||||
<li>How would you likely vote on a fully-worded and reviewed proposal to add a
|
||||
standardized version of the Boost Endian conversion functions to the standard
|
||||
library or a library TS?<br>
|
||||
</li>
|
||||
<li>How would you likely vote on a fully-worded and reviewed proposal to add a
|
||||
standardized version of the Boost Endian buffer classes to the standard
|
||||
library or a library TS?<br>
|
||||
</li>
|
||||
<li>How would you likely vote on a fully-worded and reviewed proposal to add a
|
||||
standardized version of the Boost Endian arithmetic classes to the standard
|
||||
library or a library TS?</li>
|
||||
</ul>
|
||||
<h2>Acknowledgements</h2>
|
||||
<p>The original design for the arithmetic classes was developed by Darin Adler
|
||||
based on work by Mark Borgerding. The Boost documentation acknowledges
|
||||
<a href="https://www.boost.org/libs/endian/doc/index.html#Acknowledgements">45+
|
||||
other people</a>.</p>
|
||||
<hr>
|
||||
<p> </p>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,8 +0,0 @@
|
||||
copy /y c:\boost\develop\libs\endian\doc\* d:\boost\endian-gh-pages
|
||||
pushd d:\boost\endian-gh-pages
|
||||
git commit -a -m "copy from develop"
|
||||
git push
|
||||
popd
|
||||
rem Copyright Beman Dawes, 2014
|
||||
rem Distributed under the Boost Software License, Version 1.0.
|
||||
rem See www.boost.org/LICENSE_1_0.txt
|
140
doc/std-rfc.html
140
doc/std-rfc.html
@ -1,140 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style>
|
||||
body
|
||||
{
|
||||
font-family: arial, sans-serif;
|
||||
max-width: 6.75in;
|
||||
margin: 0px auto;
|
||||
font-size: 85%;
|
||||
}
|
||||
ins {background-color: #CCFFCC; text-decoration: none;}
|
||||
del {background-color: #FFCACA; text-decoration: none;}
|
||||
pre {background-color: #D7EEFF; font-size: 95%; font-family: "courier new", courier, serif;}
|
||||
code {font-family: "courier new", courier, serif;}
|
||||
table {font-size: 90%;}
|
||||
</style>
|
||||
<title>Endian RFC</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="left">Doc. no.:</td>
|
||||
<td align="left">D0803R1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Date:</td>
|
||||
<td align="left">
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%Y-%m-%d" startspan -->2017-11-10<!--webbot bot="Timestamp" endspan i-checksum="12111" --></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Reply to:</td>
|
||||
<td align="left">Beman Dawes <bdawes at acm dot org>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Audience:</td>
|
||||
<td align="left">Library Evolution</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<h1 align="center">Endian Library Request for Comments (R1)</h1>
|
||||
|
||||
|
||||
<h2>Abstract</h2>
|
||||
<p>The Boost Endian library manipulates the
|
||||
<a href="https://en.wikipedia.org/wiki/Endianness">endianness</a> of integers
|
||||
and user-defined types. It provides three approaches to dealing with endianness:
|
||||
conversion functions, buffer classes, and arithmetic classes. Each approach
|
||||
has use cases where it is preferred by users over the other approaches, but
|
||||
adding all three approaches to the standard library would likely be too much of
|
||||
a good thing. The purpose of
|
||||
this RFC is to determine interest in adding the Boost conversion functions alone to
|
||||
the C++ standard library or a library TS.</p>
|
||||
<h2>Introduction</h2>
|
||||
<p>The Boost Endian documentation (<a href="https://www.boost.org/libs/endian/doc/index.html">www.boost.org/libs/endian/doc</a>)
|
||||
provides an <a href="https://www.boost.org/libs/endian/doc/index.html">overview</a>
|
||||
and detailed technical specifications for the
|
||||
<a href="https://www.boost.org/libs/endian/doc/conversion.html">conversion
|
||||
functions</a>, <a href="https://www.boost.org/libs/endian/doc/arithmetic.html">
|
||||
arithmetic types</a>, and
|
||||
<a href="https://www.boost.org/libs/endian/doc/buffers.html">buffer types</a>.
|
||||
</p>
|
||||
<p>A separate discussion covers
|
||||
<a href="https://www.boost.org/libs/endian/doc/choosing_approach.html">choosing
|
||||
between the three approaches</a> provided by the library.</p>
|
||||
<p>For those not interested in plowing through the entire documentation, the
|
||||
<a href="https://www.boost.org/libs/endian/doc/index.html#FAQ">Overall FAQ</a>,
|
||||
<a href="https://www.boost.org/libs/endian/doc/conversion.html#FAQ">Conversion
|
||||
FAQ</a>, <a href="https://www.boost.org/libs/endian/doc/arithmetic.html#FAQ">
|
||||
Arithmetic FAQ</a>, and
|
||||
<a href="https://www.boost.org/libs/endian/doc/buffers.html#FAQ">Buffers FAQ</a>
|
||||
answer a lot of question likely to arise during standardization.</p>
|
||||
<h2>Motivation for standardization</h2>
|
||||
Lack of any one de facto standard endianness capability in either C or
|
||||
C++. While most platforms provides some way to handle endianness in C, the
|
||||
mechanism varies from platform to platform.<ul>
|
||||
<li>Commonly used C endian handling functions are extremely error prone. While
|
||||
the Boost Endian conversion functions have some of the same problems, the buffer and
|
||||
arithmetic classes do not.</li>
|
||||
<li>Surprisingly difficult to write and test yourself in a portable yet
|
||||
efficient (i.e. using intrinsics) way. </li>
|
||||
<li>Explicit requests for standardization from Boost Endian users.</li>
|
||||
<li>The Boost library is existing practice with years of both implementation
|
||||
and end-user experience.</li>
|
||||
<li>The committee has already started to standardize endian conversion
|
||||
functions once, but had to pull the proposal at the last minute because of
|
||||
name clashes with widely used macros.</li>
|
||||
</ul>
|
||||
<h2>Motivation for standardizing only the conversion functions</h2>
|
||||
<ul>
|
||||
<li>KISS; Providing three different solutions to the same problem space
|
||||
regularly confuses to Boost users and makes endianness solutions harder to
|
||||
teach.</li>
|
||||
<li>The conversion functions are what end users would need to build their own
|
||||
higher level abstractions.</li>
|
||||
<li>The safe use patterns for the conversion functions are already familiar to
|
||||
users of platform specific C endian conversion functions.</li>
|
||||
<li>The Boost buffer and arithmetic types are specified and implemented in
|
||||
terms of the conversion functions, so are easy to add later if desired.</li>
|
||||
</ul>
|
||||
<h2>Impact on the standard library</h2>
|
||||
<p>Endianness conversion functions would be pure additions to the
|
||||
standard library and would break no existing user code (modulo the usual
|
||||
namespace <code>std</code> caveats).</p>
|
||||
<h2>Proposed wording</h2>
|
||||
<p>The Boost Endian reference documentation for
|
||||
<a href="https://www.boost.org/libs/endian/doc/conversion.html#Reference">
|
||||
Conversion</a> follows the standard library's <i>Method of description</i>
|
||||
[description], so provides a fairly close approximation of what proposed wording
|
||||
would look like. Actual proposed wording will be provided in a proposal document
|
||||
if the library is of interest to the committee. Names will need
|
||||
the usual review.</p>
|
||||
<h2>Revision history</h2>
|
||||
<p>R1: Limits proposal to the conversion functions. KISS.</p>
|
||||
<p>R0: Considers adding all three endianness approaches to the standard library.</p>
|
||||
<h2>Question for the Library Evolution Group</h2>
|
||||
Assuming a fully-worded and reviewed proposal to add a
|
||||
standardized version of the Boost Endian conversion functions to the standard
|
||||
library or a library TS, how would you likely vote for it?<h2>Target?</h2>
|
||||
<p>It is premature to discuss whether to target a TS or the IS. We need to have
|
||||
an acceptable proposal in hand and see where we are in the release cycle before
|
||||
deciding on the target. </p>
|
||||
<h2>Acknowledgements</h2>
|
||||
<p>The original design for the arithmetic classes was developed by Darin Adler
|
||||
based on work by Mark Borgerding. The Boost documentation acknowledges
|
||||
<a href="https://www.boost.org/libs/endian/doc/index.html#Acknowledgements">45+
|
||||
other people</a>.</p>
|
||||
<hr>
|
||||
<p> </p>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
|
||||
body
|
||||
{
|
||||
font-family: arial, sans-serif;
|
||||
max-width: 6.5in;
|
||||
margin: 0px auto;
|
||||
font-size: 85%;
|
||||
}
|
||||
ins {background-color: #CCFFCC;}
|
||||
del {background-color: #FFCACA;}
|
||||
pre {background-color: #D7EEFF; font-size: 95%; font-family: "courier new", courier, serif;}
|
||||
code {font-size: 110%; font-family: "courier new", courier, serif;}
|
||||
table {font-size: 100%;}
|
||||
|
||||
/*
|
||||
<20> Copyright Beman Dawes, 2014
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
See www.boost.org/LICENSE_1_0.txt
|
||||
*/
|
||||
|
@ -1,106 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Endian Library Do List</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Endian Library TODO List</h1>
|
||||
|
||||
<h2>To Do</h2>
|
||||
<h2>Format Review Comments</h2>
|
||||
<h3 dir="ltr">Interesting</h3>
|
||||
<ul>
|
||||
<li dir="ltr">
|
||||
<p dir="ltr">John Filo - "Absolutely. I'd like to see support for float and
|
||||
double, but<br>
|
||||
even without those additions, I still vote yes." "For those who deal with
|
||||
non-native endian data, this library is<br>
|
||||
extremely useful. It automatically eliminates a whole class of common<br>
|
||||
programming errors when dealing with such data."<br>
|
||||
</li>
|
||||
<li dir="ltr">
|
||||
<p dir="ltr">Hartmut Kaiser - "Even if this is not a full review, I would like
|
||||
to vote YES to include this <br>
|
||||
library into Boost.
|
||||
<p>Boost.Spirit is using (and shipping) with an older version of this library
|
||||
<br>
|
||||
for several years now and we never had any problems with its usage in <br>
|
||||
Spirit. It is used as the underlying framework for the binary parsers and <br>
|
||||
generators and it is functioning as advertised.</p>
|
||||
<p>As a quick test I replaced the internal (older) version of Boost.Endian in
|
||||
<br>
|
||||
Spirit with the reviewed version. All of Spirits regression tests still <br>
|
||||
pass. "<br>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Executive summary</h3>
|
||||
<ul>
|
||||
<li>Common use case scenarios should be developed.</li>
|
||||
<li>Example programs should be developed for the common use case scenarios.</li>
|
||||
<li>Documentation should illuminate the differences between endian
|
||||
integer/float type and endian conversion approaches to the common use case
|
||||
scenarios, and provide guidelines for choosing the most appropriate approach
|
||||
for user's applications.</li>
|
||||
<li>Conversion functions supplying results via <code>return</code> should be
|
||||
provided.</li>
|
||||
<li>Platform specific performance enhancements such as use of compiler
|
||||
intrinsics or relaxed alignment requirements should be supported.</li>
|
||||
<li>Endian integer (and floating) types should be implemented via the
|
||||
conversion functions. If that can't be done efficiently, consideration should
|
||||
be given to expanding the conversion function signatures to resolve the
|
||||
inefficiencies.</li>
|
||||
<li>Benchmarks that measure performance should be provided. It should be
|
||||
possible to compare platform specific performance enhancements against
|
||||
portable base implementations, and to compare endian integer approaches
|
||||
against endian conversion approaches for the common use case scenarios.</li>
|
||||
<li>Float (32-bits) and double (64-bits) should be supported. IEEE 754 is the
|
||||
primary use case.</li>
|
||||
<li>Support for user defined types (UDTs) is desirable, and should be
|
||||
supported where there would be no conflict with the other concerns.</li>
|
||||
<li>There is some concern that endian integer/float arithmetic operations
|
||||
might used
|
||||
inadvertently or inappropriately. The impact of adding an endian_buffer class without arithmetic
|
||||
operations should be investigated.</li>
|
||||
<li>Stream insertion and extraction of the endian integer/float types should
|
||||
be documented and included in the test coverage.</li>
|
||||
<li>Binary I/O support that was investigated during development of the Endian
|
||||
library should be put up for min-review for inclusion in the Boost I/O
|
||||
library.</li>
|
||||
</ul>
|
||||
<h3>Docs</h3>
|
||||
<ul>
|
||||
<li>one other point ... the help file seems to directly link to the c++
|
||||
headers.<br>
|
||||
this should be changed:<br>
|
||||
<br>
|
||||
* some browsers (at least chromium) will not display the header when clicking<br>
|
||||
the link, but will save them on disk.<br>
|
||||
<br>
|
||||
* providing a direct link to the source code from the docs implies that the<br>
|
||||
user will get some information that are necessary to use the library by<br>
|
||||
reading the sources. imo, this is not the case for using boost.endian.<br>
|
||||
<br>
|
||||
* if a user opens integer.hpp, the first 60 lines just contain copyright, some<br>
|
||||
historical notes, compiler-specific stuff, includes and ifdefs. imo, this is<br>
|
||||
the implementation part, which should not be exposed to a user.<br>
|
||||
<br>
|
||||
so i'd suggest to completely remove the links to the c++ headers.<br>
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p>Last revised:
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->17 January, 2015<!--webbot bot="Timestamp" endspan i-checksum="38899" --></p>
|
||||
<p>© Copyright Beman Dawes, 2012</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. See
|
||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a></p>
|
||||
<p> </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
18
index.html
18
index.html
@ -1,14 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=doc/index.html">
|
||||
<meta http-equiv="refresh" content="0; URL=doc/html/endian.html">
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="doc/index.html">doc/index.html</a>. <hr>
|
||||
<p><font size="2"><EFBFBD> Copyright Beman Dawes, 2001</font></p>
|
||||
<p><font size="2">Distributed under the Boost Software License, Version 1.0.
|
||||
(See <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)
|
||||
</font>
|
||||
<a href="doc/html/endian.html">doc/html/endian.html</a>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
<!--
|
||||
Copyright 2001 Beman Dawes
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
Reference in New Issue
Block a user