Add unaligned floating point types and supporting infrastructure.

This commit is contained in:
Beman
2013-05-26 08:25:10 -04:00
parent a7ba65f830
commit dff7c1254e
9 changed files with 270 additions and 18 deletions

View File

@@ -133,12 +133,12 @@ requirements. Floating point types are not currently supported.</p>
<h2><a name="Choosing">Choosing</a> between endian types and endian
conversion functions</h2>
<p>Which approach is best for dealing with endianness depends on the
application.</p>
<p>Which approach is best for dealing with endianness depends on
application concerns.</p>
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
<tr>
<th colspan="2">Advantages</th>
<th colspan="2">Needs that favor one approach over the other</th>
</tr>
<tr>
<th width="50%"><b><a href="types.html">Endian types</a></b></th>
@@ -147,31 +147,37 @@ application.</p>
<tr>
<td valign="top">
<ul>
<li>Mimic the built-in types. This can simplify use and eliminate logic
errors since there is no need to reason about the current endianness of
variables.<br>
<li>A need to simplify program logic and eliminate logic
errors. Since the endian types mimic the built-in types, there is no need to reason about the current endianness of variables
and that can simplify program logic and eliminate logic errors.<br>
&nbsp;</li>
<li>1, 2, 3, 4, 5, 6, 7, and 8 byte integers are supported. Use of 3, 5,
6, or 7 byte integers can reduce internal and external space usage and
<li>A need to use unusual integer sizes (i.e. 3, 5,
6, or 7 bytes) to reduce internal and external space usage and
save I/O time.<br>
&nbsp;</li>
<li>Alignment is not required. This can eliminate padding bytes in
<li>A need to use unaligned variables. Endian types can eliminate padding bytes in
structures, reducing internal and external space usage and saving I/O
time.</li>
time. They can deals with structures defined like this:</li>
</ul>
<blockquote>
<p><code>struct S {<br>
&nbsp; uint16_t a;<br>
&nbsp; uint32_t b;<br>
} __attribute__ ((packed));</code></p>
</blockquote>
</td>
<td valign="top">
<ul>
<li>Already familiar to developers who have been using C conversion
<li>A need to leverage knowledge of developers who have been using C byte
swapping
functions for years.<br>
&nbsp;</li>
<li>Uses less CPU time, particularly if each variable is used many times
relative to I/O of the variable.<br>
<li>A need to save CPU time when a variable is used many times
relative to its I/O.<br>
&nbsp;</li>
<li>Easier to pass structures to third-party libraries expecting a
<li>A need to pass structures to third-party libraries expecting a
specific structure format.<br>
&nbsp;</li>
<li>Supports <code>float</code> and <code>double</code>.</li>
</ul>
</td>
</tr>

View File

@@ -10,6 +10,7 @@
//----------------------------------------------------------------------------//
#define _CRT_SECURE_NO_DEPRECATE // quiet VC++ 8.0 foolishness
#define _SCL_SECURE_NO_WARNINGS
#include <boost/endian/detail/disable_warnings.hpp>

View File

@@ -126,13 +126,23 @@ namespace endian
//----------------------------------- end synopsis -------------------------------------//
namespace detail
// This function is unsafe for general use, so is placed in namespace detail.
// These functions are unsafe for general use, so is placed in namespace detail.
// Think of what happens if you reverse_value a std::pair<int16_t, int_16_t>; the bytes
// from first end up in second and the bytes from second end up in first. Not good!
{
// general reverse_value function template useful in testing
template <class T>
inline T reverse_value(T x) BOOST_NOEXCEPT; // convert little to big or visa versa
// conditional unaligned reverse copy, patterned after std::reverse_copy
template <class T>
inline void big_reverse_copy(T from, char* to) BOOST_NOEXCEPT;
template <class T>
inline void big_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT;
template <class T>
inline void little_reverse_copy(T from, char* to) BOOST_NOEXCEPT;
template <class T>
inline void little_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT;
}
//--------------------------------------------------------------------------------------//
@@ -237,7 +247,7 @@ namespace endian
return *(const double*)&tmp;
}
namespace detail // this function is unsafe for general use, so placed in namespace detail
namespace detail
{
// general reverse_value function template implementation approach using std::reverse
// suggested by Mathias Gaunard
@@ -250,7 +260,45 @@ namespace endian
reinterpret_cast<char*>(&tmp) + sizeof(T));
return tmp;
}
}
template <class T>
inline void big_reverse_copy(T from, char* to) BOOST_NOEXCEPT
{
# ifdef BOOST_BIG_ENDIAN
std::memcpy(to, reinterpret_cast<const char*>(&from), sizeof(T));
# else
std::reverse_copy(reinterpret_cast<const char*>(&from),
reinterpret_cast<const char*>(&from)+sizeof(T), to);
# endif
}
template <class T>
inline void big_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT
{
# ifdef BOOST_BIG_ENDIAN
std::memcpy(reinterpret_cast<char*>(&to), from, sizeof(T));
# else
std::reverse_copy(from, from+sizeof(T), reinterpret_cast<char*>(&to));
# endif
}
template <class T>
inline void little_reverse_copy(T from, char* to) BOOST_NOEXCEPT
{
# ifdef BOOST_LITTLE_ENDIAN
std::memcpy(to, reinterpret_cast<const char*>(&from), sizeof(T));
# else
std::reverse_copy(reinterpret_cast<const char*>(&from),
reinterpret_cast<const char*>(&from)+sizeof(T), to);
# endif
}
template <class T>
inline void little_reverse_copy(const char* from, T& to) BOOST_NOEXCEPT
{
# ifdef BOOST_LITTLE_ENDIAN
std::memcpy(reinterpret_cast<char*>(&to), from, sizeof(T));
# else
std::reverse_copy(from, from+sizeof(T), reinterpret_cast<char*>(&to));
# endif
}
}
template <class ReversibleValue >
inline ReversibleValue big_endian_value(ReversibleValue x) BOOST_NOEXCEPT

View File

@@ -88,6 +88,14 @@ namespace endian
typedef boost::endian::endian<order::little, float, 32, align::yes> little_float32_t;
typedef boost::endian::endian<order::little, double, 64, align::yes> little_float64_t;
// unaligned big endian floating point types
typedef boost::endian::endian<order::big, float, 32, align::no> big_float32un_t;
typedef boost::endian::endian<order::big, double, 64, align::no> big_float64un_t;
// unaligned little endian floating point types
typedef boost::endian::endian<order::little, float, 32, align::no> little_float32un_t;
typedef boost::endian::endian<order::little, double, 64, align::no> little_float64un_t;
// aligned big endian signed integer types
typedef endian<order::big, int16_t, 16, align::yes> big_int16_t;
typedef endian<order::big, int32_t, 32, align::yes> big_int32_t;
@@ -182,6 +190,7 @@ namespace endian
{
namespace detail
{
// Unrolled loops for loading and storing streams of bytes.
template <typename T, std::size_t n_bytes,
@@ -312,6 +321,106 @@ namespace endian
private:
char m_value[n_bits/8];
};
// unaligned float big endian specialization
template <>
class endian< order::big, float, 32, align::no >
: cover_operators< endian< order::big, float, 32 >, float >
{
public:
typedef float value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
{ detail::big_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
{ detail::big_reverse_copy(val, m_value); return *this; }
operator value_type() const BOOST_NOEXCEPT
{
value_type tmp;
detail::big_reverse_copy(m_value, tmp);
return tmp;
}
const char* data() const BOOST_NOEXCEPT { return m_value; }
private:
char m_value[sizeof(value_type)];
};
// unaligned double big endian specialization
template <>
class endian< order::big, double, 64, align::no >
: cover_operators< endian< order::big, double, 64 >, double >
{
public:
typedef double value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
{ detail::big_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
{ detail::big_reverse_copy(val, m_value); return *this; }
operator value_type() const BOOST_NOEXCEPT
{
value_type tmp;
detail::big_reverse_copy(m_value, tmp);
return tmp;
}
const char* data() const BOOST_NOEXCEPT { return m_value; }
private:
char m_value[sizeof(value_type)];
};
// unaligned float little endian specialization
template <>
class endian< order::little, float, 32, align::no >
: cover_operators< endian< order::little, float, 32 >, float >
{
public:
typedef float value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
{ detail::little_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
{ detail::little_reverse_copy(val, m_value); return *this; }
operator value_type() const BOOST_NOEXCEPT
{
value_type tmp;
detail::little_reverse_copy(m_value, tmp);
return tmp;
}
const char* data() const BOOST_NOEXCEPT { return m_value; }
private:
char m_value[sizeof(value_type)];
};
// unaligned double little endian specialization
template <>
class endian< order::little, double, 64, align::no >
: cover_operators< endian< order::little, double, 64 >, double >
{
public:
typedef double value_type;
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(value_type val) BOOST_NOEXCEPT
{ detail::little_reverse_copy(val, m_value); }
# endif
endian & operator=(value_type val) BOOST_NOEXCEPT
{ detail::little_reverse_copy(val, m_value); return *this; }
operator value_type() const BOOST_NOEXCEPT
{
value_type tmp;
detail::little_reverse_copy(m_value, tmp);
return tmp;
}
const char* data() const BOOST_NOEXCEPT { return m_value; }
private:
char m_value[sizeof(value_type)];
};
// unaligned little endian specialization
template <typename T, std::size_t n_bits>

View File

@@ -9,6 +9,8 @@
//----------------------------------------------------------------------------//
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_ENDIAN_FORCE_PODNESS
#include <boost/endian/detail/disable_warnings.hpp>

View File

@@ -16,6 +16,8 @@
//----------------------------------------------------------------------------//
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_ENDIAN_LOG
#include <boost/endian/detail/disable_warnings.hpp>

View File

@@ -16,6 +16,8 @@
//----------------------------------------------------------------------------//
#define _SCL_SECURE_NO_WARNINGS
#include <boost/endian/detail/disable_warnings.hpp>
#include <boost/endian/types.hpp>
@@ -234,6 +236,17 @@ namespace
VERIFY(little_float32.data() == reinterpret_cast<const char *>(&little_float32));
VERIFY(little_float64.data() == reinterpret_cast<const char *>(&little_float64));
big_float32un_t big_float32un;
big_float64un_t big_float64un;
little_float32un_t little_float32un;
little_float64un_t little_float64un;
VERIFY(big_float32un.data() == reinterpret_cast<const char *>(&big_float32un));
VERIFY(big_float64un.data() == reinterpret_cast<const char *>(&big_float64un));
VERIFY(little_float32un.data() == reinterpret_cast<const char *>(&little_float32un));
VERIFY(little_float64un.data() == reinterpret_cast<const char *>(&little_float64un));
VERIFY(big_8.data() == reinterpret_cast<const char *>(&big_8));
VERIFY(big_16.data() == reinterpret_cast<const char *>(&big_16));
VERIFY(big_24.data() == reinterpret_cast<const char *>(&big_24));
@@ -318,6 +331,11 @@ namespace
VERIFY_SIZE(sizeof( little_float32_t ), 4 );
VERIFY_SIZE(sizeof( little_float64_t ), 8 );
VERIFY_SIZE(sizeof( big_float32un_t ), 4 );
VERIFY_SIZE(sizeof( big_float64un_t ), 8 );
VERIFY_SIZE(sizeof( little_float32un_t ), 4 );
VERIFY_SIZE(sizeof( little_float64un_t ), 8 );
VERIFY_SIZE( sizeof( big_8_t ), 1 );
VERIFY_SIZE( sizeof( big_16_t ), 2 );
VERIFY_SIZE( sizeof( big_24_t ), 3 );
@@ -486,6 +504,18 @@ namespace
native_u64_t v31;
};
struct big_float_struct
{
int16_t v0;
big_float32_t v1;
};
struct big_unaligned_float_struct
{
int16_t v0;
big_float32un_t v1;
};
// aligned test cases
struct big_aligned_struct
@@ -514,6 +544,8 @@ namespace
VERIFY_SIZE( sizeof(native_u_struct), 39 );
VERIFY_SIZE( sizeof(big_aligned_struct), 24 );
VERIFY_SIZE( sizeof(little_aligned_struct), 24 );
VERIFY_SIZE( sizeof(big_float_struct), 8 );
VERIFY_SIZE( sizeof(big_unaligned_float_struct), 6 );
if ( saved_err_count == err_count )
{
@@ -526,6 +558,7 @@ namespace
void check_representation_and_range_and_ops()
{
// aligned floating point types
float big_float32_expected = std::numeric_limits<float>::max();
boost::endian::big_endian(big_float32_expected);
big_float32_t big_float32(std::numeric_limits<float>::max());
@@ -560,6 +593,52 @@ namespace
VERIFY_VALUE_AND_OPS( little_float64_t, double, std::numeric_limits<double>::max() );
VERIFY_VALUE_AND_OPS( little_float64_t, double, std::numeric_limits<double>::min() );
// unaligned floating point types
float big_float32un_expected = std::numeric_limits<float>::max();
boost::endian::big_endian(big_float32un_expected);
big_float32un_t big_float32un(std::numeric_limits<float>::max());
VERIFY(std::memcmp(big_float32un.data(),
reinterpret_cast<const char*>(&big_float32un_expected), sizeof(float)) == 0);
float little_float32un_expected = std::numeric_limits<float>::max();
boost::endian::little_endian(little_float32un_expected);
little_float32un_t little_float32un(std::numeric_limits<float>::max());
VERIFY(std::memcmp(little_float32un.data(),
reinterpret_cast<const char*>(&little_float32un_expected), sizeof(float)) == 0);
double big_float64un_expected = std::numeric_limits<double>::max();
boost::endian::big_endian(big_float64un_expected);
big_float64un_t big_float64un(std::numeric_limits<double>::max());
VERIFY(std::memcmp(big_float64un.data(),
reinterpret_cast<const char*>(&big_float64un_expected), sizeof(double)) == 0);
double little_float64un_expected = std::numeric_limits<double>::max();
boost::endian::little_endian(little_float64un_expected);
little_float64un_t little_float64un(std::numeric_limits<double>::max());
VERIFY(std::memcmp(little_float64un.data(),
reinterpret_cast<const char*>(&little_float64un_expected), sizeof(double)) == 0);
VERIFY_VALUE_AND_OPS( big_float32un_t, float, std::numeric_limits<float>::max() );
VERIFY_VALUE_AND_OPS( big_float32un_t, float, std::numeric_limits<float>::min() );
VERIFY_VALUE_AND_OPS( big_float64un_t, double, std::numeric_limits<double>::max() );
VERIFY_VALUE_AND_OPS( big_float64un_t, double, std::numeric_limits<double>::min() );
VERIFY_VALUE_AND_OPS( little_float32un_t, float, std::numeric_limits<float>::max() );
VERIFY_VALUE_AND_OPS( little_float32un_t, float, std::numeric_limits<float>::min() );
VERIFY_VALUE_AND_OPS( little_float64un_t, double, std::numeric_limits<double>::max() );
VERIFY_VALUE_AND_OPS( little_float64un_t, double, std::numeric_limits<double>::min() );
float a = 1.0F;
big_float32_t b(1.0F);
big_float32un_t c(1.0F);
little_float32_t d(1.0F);
little_float32un_t e(1.0F);
VERIFY(a==b);
VERIFY(a==c);
VERIFY(a==d);
VERIFY(a==e);
// unaligned integer types
VERIFY_BIG_REPRESENTATION( big_8_t );
VERIFY_VALUE_AND_OPS( big_8_t, int_least8_t, 0x7f );
VERIFY_VALUE_AND_OPS( big_8_t, int_least8_t, -0x80 );
@@ -728,6 +807,7 @@ namespace
VERIFY_NATIVE_REPRESENTATION( native_u64_t );
VERIFY_VALUE_AND_OPS( native_u64_t, uint_least64_t, 0xffffffffffffffffULL );
// aligned integer types
VERIFY_BIG_REPRESENTATION( big_int16_t );
VERIFY_VALUE_AND_OPS( big_int16_t, int_least16_t, 0x7fff );
VERIFY_VALUE_AND_OPS( big_int16_t, int_least16_t, -0x8000 );

View File

@@ -7,6 +7,8 @@
//--------------------------------------------------------------------------------------//
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_ENDIAN_NO_INTRINSICS
//#define BOOST_ENDIAN_LOG

View File

@@ -13,6 +13,8 @@
//--------------------------------------------------------------------------------------//
#define _SCL_SECURE_NO_WARNINGS
#include "speed_test_functions.hpp"
namespace user