Initial done_list.html. Improve general FAQ. Update example. Add BOOST_NOEXCEPT to types.hpp and cover_operators.hpp.

This commit is contained in:
Beman
2013-05-22 13:26:51 -04:00
parent c7beb10785
commit 41f0c15844
7 changed files with 242 additions and 171 deletions

44
doc/done_list.html Normal file
View File

@@ -0,0 +1,44 @@
<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>New Page 1</title>
</head>
<body>
<h1>Endian changes since formal review</h1>
<ul>
<li>Headers rename to endian/types.hpp and endian/conversion.hpp.
Infrastructure file names changed accordingly.</li>
<li>The conversion.hpp conversion functions have been much revised, refactored,
renamed and otherwise improved based on review comments.<ul>
<li>UDT's are supported.</li>
<li><code>float</code>(32-bits) and <code>double</code> (64-bits) are
supported.</li>
<li>Both return-by-value and modify-in-place interfaces are provided.</li>
<li>Synonyms for the BSD byte swapping function names popularized by OS X
and Linux are provided, so that that developers already used to these name
can continue to use them if they wish.</li>
<li>In addition to the fixed endianness functions, functions that perform
compile-time (via template) and run-time (via function argument) dispatch
are now provided.</li>
</ul>
</li>
<li>Compiler (Clang, GCC, VisualC++, etc.) intrinsics and built-in functions
are used in the implementation where appropriate.</li>
<li>For the aligned endian integer types, the implementation uses
conversion.hpp conversion functions.</li>
<li>C++11 features such as <code>noexcept</code> are used, while still
supporting C++03 compilers.</li>
<li>Acknowledgements have been updated.</li>
<li>Headers have been reorganized to make them easier to read, as requested,
with a synopsis at the front and implementation following.</li>
</ul>
</body>
</html>

View File

@@ -178,11 +178,14 @@ application.</p>
</table>
<h2>Overall <a name="FAQ">FAQ</a></h2>
<p><b>Why bother with endianness? Does endianness have any uses outside of
portable binary file or network I/O formats?</b> </p>
<p><b>Why bother with endianness?</b></p>
<blockquote>
<p>Binary data portability is the primary use case, and that implies I/O.</p>
<p>Using the 3, 5, 6, and 7 byte integer types to save internal or external
<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 to save internal or external
memory space is a minor secondary use case.</p>
</blockquote>
<p><b>Why bother with binary I/O? Why not just use C++ Standard Library stream
@@ -198,6 +201,13 @@ files, limit usefulness to applications where the binary I/O advantages are
paramount.</p>
</blockquote>
<p><b>Why is only big, little, and 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 historical curiosities
but have no relevance to C++ developers.</p>
</blockquote>
<h2><a name="Acknowledgements">Acknowledgements</a></h2>
<p>Comments and suggestions were
received from
@@ -216,7 +226,7 @@ Tim Blechmann, Tim Moore, tymofey, Tomas Puverle, Vincente Botet, Yuval Ronen
and Vitaly Budovski,.</p>
<hr>
<p>Last revised:
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->20 May, 2013<!--webbot bot="Timestamp" endspan i-checksum="13976" --></p>
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->22 May, 2013<!--webbot bot="Timestamp" endspan i-checksum="13980" --></p>
<p><EFBFBD> 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>

View File

@@ -109,64 +109,69 @@ using namespace boost::endian;
namespace
{
// This is an extract from a very widely used GIS file format. I have no idea
// why a designer would mix big and little endians in the same file - 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.
// This is an extract from a very widely used GIS file format. Who knows
// why a designer would mix big and little endians in the same file - 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
{
big32_t file_code;
big32_t file_length;
little32_t version;
little32_t shape_type;
big_int32_t file_code;
big_int32_t file_length;
little_int32_t version;
little_int32_t shape_type;
};
const char * filename = &quot;test.dat&quot;;
const char* filename = &quot;test.dat&quot;;
}
int main()
int main(int, char* [])
{
BOOST_STATIC_ASSERT( sizeof( header ) == 16U ); // check requirement
BOOST_STATIC_ASSERT(sizeof(header) == 16U); // reality check
header h;
h.file_code = 0x01020304;
h.file_length = sizeof( header );
h.version = -1;
h.file_length = sizeof(header);
h.version = 1;
h.shape_type = 0x01020304;
// Low-level I/O such as POSIX read/write or &lt;cstdio&gt; 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, &lt;cstdio&gt; fopen/fwrite is used for I/O in this example.
// Low-level I/O such as POSIX read/write or &lt;cstdio&gt; 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, &lt;cstdio&gt; fopen/fwrite is used for I/O in this example.
std::FILE * fi;
if ( !(fi = std::fopen( filename, &quot;wb&quot; )) ) // MUST BE BINARY
std::FILE* fi = std::fopen(filename, &quot;wb&quot;); // MUST BE BINARY
if (!fi)
{
std::cout &lt;&lt; &quot;could not open &quot; &lt;&lt; filename &lt;&lt; '\n';
return 1;
}
if ( std::fwrite( &amp;h, sizeof( header ), 1, fi ) != 1 )
if (std::fwrite(&amp;h, sizeof(header), 1, fi)!= 1)
{
std::cout &lt;&lt; &quot;write failure for &quot; &lt;&lt; filename &lt;&lt; '\n';
return 1;
}
std::fclose( fi );
std::fclose(fi);
std::cout &lt;&lt; &quot;created file &quot; &lt;&lt; filename &lt;&lt; '\n';
return 0;
}</pre>
}
</pre>
</blockquote>
<p>After compiling and executing <a href="endian_example.cpp">endian_example.cpp</a>,
a hex dump of <code>test.dat</code> shows:</p>
<blockquote>
<pre>0102 0304 0000 0010 ffff ffff 0403 0201</pre>
<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>&lt;climits&gt;</code> <code>CHAR_BIT == 8</code>. If <code>CHAR_BIT</code>
is some other value, compilation will result in an <code>#error</code>. This
@@ -178,7 +183,7 @@ 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 do layout memory as if <code>
endian</code> were a POD type. In C++11, it will be possible to specify the
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 will
no longer disqualify a type from being a POD. Thus under C++11, <code>endian</code>
will no longer be relying on unspecified behavior.</p>
@@ -190,15 +195,19 @@ will no longer be relying on unspecified behavior.</p>
<li>1-8 byte (unaligned) | 2, 4, 8 byte (aligned)</li>
<li>Choice of integer value type</li>
</ul>
<h2><a name="Types">Typedefs</a></h2>
<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 &lt;<a href="#endianness">endianness</a>::enum_t E, typename T, std::size_t n_bytes,
<a href="#alignment">alignment</a>::enum_t A = alignment::unaligned&gt;
class endian;
<pre>template &lt;order Order, typename T, std::size_t n_bits, align A = align::no&gt;
class endian;
</pre>
</blockquote>
<p>Sixty typedefs, such as <code>big32_t</code>, provide convenient naming
<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%">
@@ -210,76 +219,76 @@ conventions for common use cases:</p>
<td width="49%" align="center"><b><i>Alignment</i></b></td>
</tr>
<tr>
<td width="18%"><code>big</code><b><i>n</i></b><code>_t</code></td>
<td width="10%"><code>big</code></td>
<td width="10%">signed</td>
<td width="15%">8,16,24,32,40,48,56,64</td>
<td width="49%"><code>unaligned</code></td>
</tr>
<tr>
<td width="18%"><code>ubig</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>big</code></td>
<td width="10%">unsigned</td>
<td width="15%">8,16,24,32,40,48,56,64</td>
<td width="49%"><code>unaligned</code></td>
</tr>
<tr>
<td width="18%"><code>little</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>little</code></td>
<td width="10%">signed</td>
<td width="15%">8,16,24,32,40,48,56,64</td>
<td width="49%"><code>unaligned</code></td>
</tr>
<tr>
<td width="18%"><code>ulittle</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>little</code></td>
<td width="10%">unsigned</td>
<td width="15%">8,16,24,32,40,48,56,64</td>
<td width="49%"><code>unaligned</code></td>
</tr>
<tr>
<td width="18%"><code>native</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>native</code></td>
<td width="10%">signed</td>
<td width="15%">8,16,24,32,40,48,56,64</td>
<td width="49%"><code>unaligned</code></td>
</tr>
<tr>
<td width="18%"><code>unative</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>native</code></td>
<td width="10%">unsigned</td>
<td width="15%">8,16,24,32,40,48,56,64</td>
<td width="49%"><code>unaligned</code></td>
</tr>
<tr>
<td width="18%"><code>aligned_big</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>big</code></td>
<td width="10%">signed</td>
<td width="18%"><code>big_int</code><i><b>n</b></i><code>_t</code></td>
<td width="10%" align="center"><code>big</code></td>
<td width="10%" align="center">signed</td>
<td width="15%">16,32,64</td>
<td width="49%"><code>aligned</code></td>
<td width="49%" align="center"><code>yes</code></td>
</tr>
<tr>
<td width="18%"><code>aligned_ubig</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>big</code></td>
<td width="10%">unsigned</td>
<td width="18%"><code>big_uint</code><i><b>n</b></i><code>_t</code></td>
<td width="10%" align="center"><code>big</code></td>
<td width="10%" align="center">unsigned</td>
<td width="15%">16,32,64</td>
<td width="49%"><code>aligned</code></td>
<td width="49%" align="center"><code>yes</code></td>
</tr>
<tr>
<td width="18%"><code>aligned_little</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>little</code></td>
<td width="10%">signed</td>
<td width="18%"><code>little_int</code><i><b>n</b></i><code>_t</code></td>
<td width="10%" align="center"><code>little</code></td>
<td width="10%" align="center">signed</td>
<td width="15%">16,32,64</td>
<td width="49%"><code>aligned</code></td>
<td width="49%" align="center"><code>yes</code></td>
</tr>
<tr>
<td width="18%"><code>aligned_ulittle</code><i><b>n</b></i><code>_t</code></td>
<td width="10%"><code>little</code></td>
<td width="10%">unsigned</td>
<td width="18%"><code>little_uint</code><i><b>n</b></i><code>_t</code></td>
<td width="10%" align="center"><code>little</code></td>
<td width="10%" align="center">unsigned</td>
<td width="15%">16,32,64</td>
<td width="49%"><code>aligned</code></td>
<td width="49%" align="center"><code>yes</code></td>
</tr>
</table>
<tr>
<td width="18%"><code>big_</code><b><i>n</i></b><code>_t</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>
<td width="49%" align="center"><code>no</code></td>
</tr>
<tr>
<td width="18%"><code>big_u</code><i><b>n</b></i><code>_t</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>
<td width="49%" align="center"><code>no</code></td>
</tr>
<tr>
<td width="18%"><code>little_</code><i><b>n</b></i><code>_t</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>
<td width="49%" align="center"><code>no</code></td>
</tr>
<tr>
<td width="18%"><code>little_u</code><i><b>n</b></i><code>_t</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>
<td width="49%" align="center"><code>no</code></td>
</tr>
<tr>
<td width="18%"><code>native_</code><i><b>n</b></i><code>_t</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>
<td width="49%" align="center"><code>no</code></td>
</tr>
<tr>
<td width="18%"><code>native_u</code><i><b>n</b></i><code>_t</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>
<td width="49%" align="center"><code>no</code></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
@@ -289,8 +298,9 @@ Code that uses a</span>ligned types is inherently non-portable because alignment
requirements vary between hardware architectures and because alignment may be
affected by compiler switches or pragmas. Furthermore, aligned types
are only available on architectures with 16, 32, and 64-bit integer types.</p>
<p><b><i>Note:</i></b> One-byte big-endian, little-endian, and native-endian types provide identical
functionality. All three names are provided to improve code readability and searchability.</p>
<p><b><i>Note:</i></b> One-byte big-endian, little-endian, and native-endian types
have identical
functionality. They are provided to improve code readability and searchability.</p>
<h3><a name="Comment-on-naming">Comment on naming</a></h3>
<p>When first exposed to endian types, programmers often fit them into a mental model
based on the <code>&lt;cstdint&gt;</code> types. Using that model, it is natural to
@@ -593,7 +603,7 @@ 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 -->21 May, 2013<!--webbot bot="Timestamp" endspan i-checksum="13978" --></p>
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->22 May, 2013<!--webbot bot="Timestamp" endspan i-checksum="13980" --></p>
<p><EFBFBD> Copyright Beman Dawes, 2006-2009</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>

View File

@@ -22,7 +22,7 @@ using namespace boost::endian;
namespace
{
// This is an extract from a very widely used GIS file format. I have no idea
// This is an extract from a very widely used GIS file format. Who knows
// why a designer would mix big and little endians in the same file - 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.
@@ -35,18 +35,18 @@ namespace
little_int32_t shape_type;
};
const char * filename = "test.dat";
const char* filename = "test.dat";
}
int main(int, char * [])
int main(int, char* [])
{
BOOST_STATIC_ASSERT( sizeof( header ) == 16U ); // check requirement
BOOST_STATIC_ASSERT(sizeof(header) == 16U); // reality check
header h;
h.file_code = 0x01020304;
h.file_length = sizeof( header );
h.version = -1;
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
@@ -55,21 +55,21 @@ int main(int, char * [])
// 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
std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
if ( !fi )
if (!fi)
{
std::cout << "could not open " << filename << '\n';
return 1;
}
if ( std::fwrite( &h, sizeof( header ), 1, fi ) != 1 )
if (std::fwrite(&h, sizeof(header), 1, fi)!= 1)
{
std::cout << "write failure for " << filename << '\n';
return 1;
}
std::fclose( fi );
std::fclose(fi);
std::cout << "created file " << filename << '\n';

View File

@@ -23,7 +23,7 @@ namespace boost
namespace endian
{
#ifndef BOOST_ENDIAN_ORDER_ENUM_DEFINED
BOOST_SCOPED_ENUM_START(order) { big, little, native }; BOOST_SCOPED_ENUM_END
BOOST_SCOPED_ENUM_START(order) {big, little, native}; BOOST_SCOPED_ENUM_END
# define BOOST_ENDIAN_ORDER_ENUM_DEFINED
#endif

View File

@@ -28,6 +28,7 @@
# include <boost/operators.hpp>
# endif
#include <boost/config.hpp>
#include <iosfwd>
namespace boost
@@ -47,46 +48,46 @@ namespace boost
// built into unary +.
// Unary operations.
friend IntegerType operator+(const T& x) { return x; }
friend IntegerType operator+(const T& x) BOOST_NOEXCEPT { return x; }
# ifndef BOOST_MINIMAL_INTEGER_COVER_OPERATORS
friend IntegerType operator-(const T& x) { return -+x; }
friend IntegerType operator~(const T& x) { return ~+x; }
friend IntegerType operator!(const T& x) { return !+x; }
friend IntegerType operator-(const T& x) BOOST_NOEXCEPT { return -+x; }
friend IntegerType operator~(const T& x) BOOST_NOEXCEPT { return ~+x; }
friend IntegerType operator!(const T& x) BOOST_NOEXCEPT { return !+x; }
// The basic ordering operations.
friend bool operator==(const T& x, IntegerType y) { return +x == y; }
friend bool operator<(const T& x, IntegerType y) { return +x < y; }
friend bool operator==(const T& x, IntegerType y) BOOST_NOEXCEPT { return +x == y; }
friend bool operator<(const T& x, IntegerType y) BOOST_NOEXCEPT { return +x < y; }
# endif
// The basic arithmetic operations.
friend T& operator+=(T& x, IntegerType y) { return x = +x + y; }
friend T& operator-=(T& x, IntegerType y) { return x = +x - y; }
friend T& operator*=(T& x, IntegerType y) { return x = +x * y; }
friend T& operator/=(T& x, IntegerType y) { return x = +x / y; }
friend T& operator%=(T& x, IntegerType y) { return x = +x % y; }
friend T& operator&=(T& x, IntegerType y) { return x = +x & y; }
friend T& operator|=(T& x, IntegerType y) { return x = +x | y; }
friend T& operator^=(T& x, IntegerType y) { return x = +x ^ y; }
friend T& operator<<=(T& x, IntegerType y) { return x = +x << y; }
friend T& operator>>=(T& x, IntegerType y) { return x = +x >> y; }
friend T& operator+=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x + y; }
friend T& operator-=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x - y; }
friend T& operator*=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x * y; }
friend T& operator/=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x / y; }
friend T& operator%=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x % y; }
friend T& operator&=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x & y; }
friend T& operator|=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x | y; }
friend T& operator^=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x ^ y; }
friend T& operator<<=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x << y; }
friend T& operator>>=(T& x, IntegerType y) BOOST_NOEXCEPT { return x = +x >> y; }
// A few binary arithmetic operations not covered by operators base class.
friend IntegerType operator<<(const T& x, IntegerType y) { return +x << y; }
friend IntegerType operator>>(const T& x, IntegerType y) { return +x >> y; }
friend IntegerType operator<<(const T& x, IntegerType y) BOOST_NOEXCEPT { return +x << y; }
friend IntegerType operator>>(const T& x, IntegerType y) BOOST_NOEXCEPT { return +x >> y; }
// Auto-increment and auto-decrement can be defined in terms of the
// arithmetic operations.
friend T& operator++(T& x) { return x += 1; }
friend T& operator--(T& x) { return x -= 1; }
friend T& operator++(T& x) BOOST_NOEXCEPT { return x += 1; }
friend T& operator--(T& x) BOOST_NOEXCEPT { return x -= 1; }
# ifdef BOOST_MINIMAL_INTEGER_COVER_OPERATORS
friend T operator++(T& x, int)
friend T operator++(T& x, int) BOOST_NOEXCEPT
{
T tmp(x);
x += 1;
return tmp;
}
friend T operator--(T& x, int)
friend T operator--(T& x, int) BOOST_NOEXCEPT
{
T tmp(x);
x -= 1;

View File

@@ -182,17 +182,17 @@ namespace endian
{
typedef unrolled_byte_loops<T, n_bytes - 1, sign> next;
static T load_big(const unsigned char* bytes)
static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT
{ return *(bytes - 1) | (next::load_big(bytes - 1) << 8); }
static T load_little(const unsigned char* bytes)
static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT
{ return *bytes | (next::load_little(bytes + 1) << 8); }
static void store_big(char* bytes, T value)
static void store_big(char* bytes, T value) BOOST_NOEXCEPT
{
*(bytes - 1) = static_cast<char>(value);
next::store_big(bytes - 1, value >> 8);
}
static void store_little(char* bytes, T value)
static void store_little(char* bytes, T value) BOOST_NOEXCEPT
{
*bytes = static_cast<char>(value);
next::store_little(bytes + 1, value >> 8);
@@ -202,13 +202,13 @@ namespace endian
template <typename T>
struct unrolled_byte_loops<T, 1, false>
{
static T load_big(const unsigned char* bytes)
static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT
{ return *(bytes - 1); }
static T load_little(const unsigned char* bytes)
static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT
{ return *bytes; }
static void store_big(char* bytes, T value)
static void store_big(char* bytes, T value) BOOST_NOEXCEPT
{ *(bytes - 1) = static_cast<char>(value); }
static void store_little(char* bytes, T value)
static void store_little(char* bytes, T value) BOOST_NOEXCEPT
{ *bytes = static_cast<char>(value); }
};
@@ -216,19 +216,19 @@ namespace endian
template <typename T>
struct unrolled_byte_loops<T, 1, true>
{
static T load_big(const unsigned char* bytes)
static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT
{ return *reinterpret_cast<const signed char*>(bytes - 1); }
static T load_little(const unsigned char* bytes)
static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT
{ return *reinterpret_cast<const signed char*>(bytes); }
static void store_big(char* bytes, T value)
static void store_big(char* bytes, T value) BOOST_NOEXCEPT
{ *(bytes - 1) = static_cast<char>(value); }
static void store_little(char* bytes, T value)
static void store_little(char* bytes, T value) BOOST_NOEXCEPT
{ *bytes = static_cast<char>(value); }
};
template <typename T, std::size_t n_bytes>
inline
T load_big_endian(const void* bytes)
T load_big_endian(const void* bytes) BOOST_NOEXCEPT
{
return unrolled_byte_loops<T, n_bytes>::load_big
(static_cast<const unsigned char*>(bytes) + n_bytes);
@@ -236,7 +236,7 @@ namespace endian
template <typename T, std::size_t n_bytes>
inline
T load_little_endian(const void* bytes)
T load_little_endian(const void* bytes) BOOST_NOEXCEPT
{
return unrolled_byte_loops<T, n_bytes>::load_little
(static_cast<const unsigned char*>(bytes));
@@ -244,7 +244,7 @@ namespace endian
template <typename T, std::size_t n_bytes>
inline
void store_big_endian(void* bytes, T value)
void store_big_endian(void* bytes, T value) BOOST_NOEXCEPT
{
unrolled_byte_loops<T, n_bytes>::store_big
(static_cast<char*>(bytes) + n_bytes, value);
@@ -252,7 +252,7 @@ namespace endian
template <typename T, std::size_t n_bytes>
inline
void store_little_endian(void* bytes, T value)
void store_little_endian(void* bytes, T value) BOOST_NOEXCEPT
{
unrolled_byte_loops<T, n_bytes>::store_little
(static_cast<char*>(bytes), value);
@@ -281,7 +281,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val)
explicit endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -290,8 +290,9 @@ namespace endian
detail::store_big_endian<T, n_bits/8>(m_value, val);
}
# endif
endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const
endian & operator=(T val) BOOST_NOEXCEPT
{ detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -299,7 +300,7 @@ namespace endian
# endif
return detail::load_big_endian<T, n_bits/8>(m_value);
}
const char* data() const { return m_value; }
const char* data() const BOOST_NOEXCEPT { return m_value; }
private:
char m_value[n_bits/8];
};
@@ -314,7 +315,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val)
explicit endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -323,8 +324,9 @@ namespace endian
detail::store_little_endian<T, n_bits/8>(m_value, val);
}
# endif
endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const
endian & operator=(T val) BOOST_NOEXCEPT
{ detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -332,7 +334,7 @@ namespace endian
# endif
return detail::load_little_endian<T, n_bits/8>(m_value);
}
const char* data() const { return m_value; }
const char* data() const BOOST_NOEXCEPT { return m_value; }
private:
char m_value[n_bits/8];
};
@@ -348,19 +350,23 @@ namespace endian
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
# ifdef BOOST_BIG_ENDIAN
explicit endian(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); }
explicit endian(T val) BOOST_NOEXCEPT { detail::store_big_endian<T, n_bits/8>(m_value, val); }
# else
explicit endian(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); }
explicit endian(T val) BOOST_NOEXCEPT { detail::store_little_endian<T, n_bits/8>(m_value, val); }
# endif
# endif
# ifdef BOOST_BIG_ENDIAN
endian & operator=(T val) { detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const { return detail::load_big_endian<T, n_bits/8>(m_value); }
endian & operator=(T val) BOOST_NOEXCEPT
{ detail::store_big_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const BOOST_NOEXCEPT
{ return detail::load_big_endian<T, n_bits/8>(m_value); }
# else
endian & operator=(T val) { detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const { return detail::load_little_endian<T, n_bits/8>(m_value); }
endian & operator=(T val) BOOST_NOEXCEPT
{ detail::store_little_endian<T, n_bits/8>(m_value, val); return *this; }
operator T() const BOOST_NOEXCEPT
{ return detail::load_little_endian<T, n_bits/8>(m_value); }
# endif
const char* data() const { return m_value; }
const char* data() const BOOST_NOEXCEPT { return m_value; }
private:
char m_value[n_bits/8];
};
@@ -378,7 +384,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val)
explicit endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -388,12 +394,12 @@ namespace endian
}
# endif
endian& operator=(T val)
endian& operator=(T val) BOOST_NOEXCEPT
{
m_value = ::boost::endian::big_endian_value(val);
return *this;
}
operator T() const
operator T() const BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -401,7 +407,7 @@ namespace endian
# endif
return ::boost::endian::big_endian_value(m_value);
}
const char* data() const {return reinterpret_cast<const char*>(&m_value);}
const char* data() const BOOST_NOEXCEPT {return reinterpret_cast<const char*>(&m_value);}
private:
T m_value;
};
@@ -417,7 +423,7 @@ namespace endian
typedef T value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val)
explicit endian(T val) BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -427,12 +433,12 @@ namespace endian
}
# endif
endian& operator=(T val)
endian& operator=(T val) BOOST_NOEXCEPT
{
m_value = ::boost::endian::little_endian_value(val);
return *this;
}
operator T() const
operator T() const BOOST_NOEXCEPT
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
@@ -440,7 +446,7 @@ namespace endian
# endif
return ::boost::endian::little_endian_value(m_value);
}
const char* data() const {return reinterpret_cast<const char*>(&m_value);}
const char* data() const BOOST_NOEXCEPT {return reinterpret_cast<const char*>(&m_value);}
private:
T m_value;
};