mirror of
https://github.com/boostorg/endian.git
synced 2025-07-31 21:14:38 +02:00
Add unaligned floating point types and supporting infrastructure.
This commit is contained in:
@@ -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>
|
||||
</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>
|
||||
</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>
|
||||
uint16_t a;<br>
|
||||
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>
|
||||
</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>
|
||||
</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>
|
||||
</li>
|
||||
<li>Supports <code>float</code> and <code>double</code>.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
@@ -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>
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
@@ -9,6 +9,8 @@
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
|
||||
#define BOOST_ENDIAN_FORCE_PODNESS
|
||||
|
||||
#include <boost/endian/detail/disable_warnings.hpp>
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
|
||||
#define BOOST_ENDIAN_LOG
|
||||
|
||||
#include <boost/endian/detail/disable_warnings.hpp>
|
||||
|
@@ -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 );
|
||||
|
@@ -7,6 +7,8 @@
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
|
||||
#define BOOST_ENDIAN_NO_INTRINSICS
|
||||
//#define BOOST_ENDIAN_LOG
|
||||
|
||||
|
@@ -13,6 +13,8 @@
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
|
||||
#include "speed_test_functions.hpp"
|
||||
|
||||
namespace user
|
||||
|
Reference in New Issue
Block a user