From 6f84684e9ed545cec93cdcbd69f53eee23e4d818 Mon Sep 17 00:00:00 2001
From: Beman
Date: Wed, 22 May 2013 08:14:51 -0400
Subject: [PATCH] Add separate big and little specializations for aligned case;
the attempt to combine into a single specialization was selecting the
unaligned specialization. Rework speed_test to try to get more meaningful
results and cover more test cases.
---
doc/types.html | 192 +++++++++++---------
include/boost/endian/types.hpp | 71 +++++++-
test/msvc2012/speed_test/speed_test.vcxproj | 4 +-
test/speed_test.cpp | 127 ++++++++-----
4 files changed, 251 insertions(+), 143 deletions(-)
diff --git a/doc/types.html b/doc/types.html
index 893d5e9..5e5dbdc 100644
--- a/doc/types.html
+++ b/doc/types.html
@@ -314,113 +314,129 @@ usual operations on integers are supplied.
{
namespace endian
{
-
- enum class endianness { big, little, native }; // scoped enum emulated on C++03
- enum class alignment { unaligned, aligned }; // scoped enum emulated on C++03
+ // C++11 features emulated if not available
+
+ enum class order {big, little, native};
+ enum class align {no, yes};
- template <endianness E, typename T, std::size_t n_bits,
- alignment A = alignment::unaligned>
- class endian : cover_operators< endian<E, T, n_bits, A>, T >
+ template <order Order, typename T, std::size_t n_bits, align A = align::no>
+ class endian
{
public:
- typedef T value_type;
+ typedef T value_type;
// if BOOST_ENDIAN_FORCE_PODNESS is defined && C++11 POD's are not
// available then these two constructors will not be present
- endian() = default; // = default replaced by {} on C++03
- explicit endian(T v);
+ endian() noexcept = default;
+ explicit endian(T v) noexcept;
- endian& operator=(T v);
- operator T() const;
- const char* data() const;
+ endian& operator=(T v) noexcept;
+ operator T() const noexcept;
+ const char* data() const noexcept;
+
+ // arithmetic operations; additional operators provided by 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;
};
- // unaligned big endian signed integer types
- typedef endian< endianness::big, int_least8_t, 8 > big8_t;
- typedef endian< endianness::big, int_least16_t, 16 > big16_t;
- typedef endian< endianness::big, int_least32_t, 24 > big24_t;
- typedef endian< endianness::big, int_least32_t, 32 > big32_t;
- typedef endian< endianness::big, int_least64_t, 40 > big40_t;
- typedef endian< endianness::big, int_least64_t, 48 > big48_t;
- typedef endian< endianness::big, int_least64_t, 56 > big56_t;
- typedef endian< endianness::big, int_least64_t, 64 > big64_t;
-
- // unaligned big endian unsigned integer types
- typedef endian< endianness::big, uint_least8_t, 8 > ubig8_t;
- typedef endian< endianness::big, uint_least16_t, 16 > ubig16_t;
- typedef endian< endianness::big, uint_least32_t, 24 > ubig24_t;
- typedef endian< endianness::big, uint_least32_t, 32 > ubig32_t;
- typedef endian< endianness::big, uint_least64_t, 40 > ubig40_t;
- typedef endian< endianness::big, uint_least64_t, 48 > ubig48_t;
- typedef endian< endianness::big, uint_least64_t, 56 > ubig56_t;
- typedef endian< endianness::big, uint_least64_t, 64 > ubig64_t;
-
- // unaligned little endian signed integer types
- typedef endian< endianness::little, int_least8_t, 8 > little8_t;
- typedef endian< endianness::little, int_least16_t, 16 > little16_t;
- typedef endian< endianness::little, int_least32_t, 24 > little24_t;
- typedef endian< endianness::little, int_least32_t, 32 > little32_t;
- typedef endian< endianness::little, int_least64_t, 40 > little40_t;
- typedef endian< endianness::little, int_least64_t, 48 > little48_t;
- typedef endian< endianness::little, int_least64_t, 56 > little56_t;
- typedef endian< endianness::little, int_least64_t, 64 > little64_t;
-
- // unaligned little endian unsigned integer types
- typedef endian< endianness::little, uint_least8_t, 8 > ulittle8_t;
- typedef endian< endianness::little, uint_least16_t, 16 > ulittle16_t;
- typedef endian< endianness::little, uint_least32_t, 24 > ulittle24_t;
- typedef endian< endianness::little, uint_least32_t, 32 > ulittle32_t;
- typedef endian< endianness::little, uint_least64_t, 40 > ulittle40_t;
- typedef endian< endianness::little, uint_least64_t, 48 > ulittle48_t;
- typedef endian< endianness::little, uint_least64_t, 56 > ulittle56_t;
- typedef endian< endianness::little, uint_least64_t, 64 > ulittle64_t;
-
- // unaligned native endian signed integer types
- typedef endian< endianness::native, int_least8_t, 8 > native8_t;
- typedef endian< endianness::native, int_least16_t, 16 > native16_t;
- typedef endian< endianness::native, int_least32_t, 24 > native24_t;
- typedef endian< endianness::native, int_least32_t, 32 > native32_t;
- typedef endian< endianness::native, int_least64_t, 40 > native40_t;
- typedef endian< endianness::native, int_least64_t, 48 > native48_t;
- typedef endian< endianness::native, int_least64_t, 56 > native56_t;
- typedef endian< endianness::native, int_least64_t, 64 > native64_t;
-
- // unaligned native endian unsigned integer types
- typedef endian< endianness::native, uint_least8_t, 8 > unative8_t;
- typedef endian< endianness::native, uint_least16_t, 16 > unative16_t;
- typedef endian< endianness::native, uint_least32_t, 24 > unative24_t;
- typedef endian< endianness::native, uint_least32_t, 32 > unative32_t;
- typedef endian< endianness::native, uint_least64_t, 40 > unative40_t;
- typedef endian< endianness::native, uint_least64_t, 48 > unative48_t;
- typedef endian< endianness::native, uint_least64_t, 56 > unative56_t;
- typedef endian< endianness::native, uint_least64_t, 64 > unative64_t;
-
- // These types only present if platform has exact size integers:
-
// aligned big endian signed integer types
- typedef endian< endianness::big, int16_t, 16, alignment::aligned > aligned_big16_t;
- typedef endian< endianness::big, int32_t, 32, alignment::aligned > aligned_big32_t;
- typedef endian< endianness::big, int64_t, 64, alignment::aligned > aligned_big64_t;
+ typedef endian<order::big, int16_t, 16, align::yes> big_int16_t;
+ typedef endian<order::big, int32_t, 32, align::yes> big_int32_t;
+ typedef endian<order::big, int64_t, 64, align::yes> big_int64_t;
// aligned big endian unsigned integer types
- typedef endian< endianness::big, uint16_t, 16, alignment::aligned > aligned_ubig16_t;
- typedef endian< endianness::big, uint32_t, 32, alignment::aligned > aligned_ubig32_t;
- typedef endian< endianness::big, uint64_t, 64, alignment::aligned > aligned_ubig64_t;
+ typedef endian<order::big, uint16_t, 16, align::yes> big_uint16_t;
+ typedef endian<order::big, uint32_t, 32, align::yes> big_uint32_t;
+ typedef endian<order::big, uint64_t, 64, align::yes> big_uint64_t;
// aligned little endian signed integer types
- typedef endian< endianness::little, int16_t, 16, alignment::aligned > aligned_little2_t;
- typedef endian< endianness::little, int32_t, 32, alignment::aligned > aligned_little4_t;
- typedef endian< endianness::little, int64_t, 64, alignment::aligned > aligned_little8_t;
+ typedef endian<order::little, int16_t, 16, align::yes> little_int16_t;
+ typedef endian<order::little, int32_t, 32, align::yes> little_int32_t;
+ typedef endian<order::little, int64_t, 64, align::yes> little_int64_t;
// aligned little endian unsigned integer types
- typedef endian< endianness::little, uint16_t, 16, alignment::aligned > aligned_ulittle2_t;
- typedef endian< endianness::little, uint32_t, 32, alignment::aligned > aligned_ulittle4_t;
- typedef endian< endianness::little, uint64_t, 64, alignment::aligned > aligned_ulittle8_t;
-
+ typedef endian<order::little, uint16_t, 16, align::yes> little_uint16_t;
+ typedef endian<order::little, uint32_t, 32, align::yes> little_uint32_t;
+ typedef endian<order::little, uint64_t, 64, align::yes> little_uint64_t;
// aligned native endian typedefs are not provided because
// <cstdint> types are superior for this use case
+ // unaligned big endian signed integer types
+ typedef endian<order::big, int_least8_t, 8> big_8_t;
+ typedef endian<order::big, int_least16_t, 16> big_16_t;
+ typedef endian<order::big, int_least32_t, 24> big_24_t;
+ typedef endian<order::big, int_least32_t, 32> big_32_t;
+ typedef endian<order::big, int_least64_t, 40> big_40_t;
+ typedef endian<order::big, int_least64_t, 48> big_48_t;
+ typedef endian<order::big, int_least64_t, 56> big_56_t;
+ typedef endian<order::big, int_least64_t, 64> big_64_t;
+
+ // unaligned big endian unsigned integer types
+ typedef endian<order::big, uint_least8_t, 8> big_u8_t;
+ typedef endian<order::big, uint_least16_t, 16> big_u16_t;
+ typedef endian<order::big, uint_least32_t, 24> big_u24_t;
+ typedef endian<order::big, uint_least32_t, 32> big_u32_t;
+ typedef endian<order::big, uint_least64_t, 40> big_u40_t;
+ typedef endian<order::big, uint_least64_t, 48> big_u48_t;
+ typedef endian<order::big, uint_least64_t, 56> big_u56_t;
+ typedef endian<order::big, uint_least64_t, 64> big_u64_t;
+
+ // unaligned little endian signed integer types
+ typedef endian<order::little, int_least8_t, 8> little_8_t;
+ typedef endian<order::little, int_least16_t, 16> little_16_t;
+ typedef endian<order::little, int_least32_t, 24> little_24_t;
+ typedef endian<order::little, int_least32_t, 32> little_32_t;
+ typedef endian<order::little, int_least64_t, 40> little_40_t;
+ typedef endian<order::little, int_least64_t, 48> little_48_t;
+ typedef endian<order::little, int_least64_t, 56> little_56_t;
+ typedef endian<order::little, int_least64_t, 64> little_64_t;
+
+ // unaligned little endian unsigned integer types
+ typedef endian<order::little, uint_least8_t, 8> little_u8_t;
+ typedef endian<order::little, uint_least16_t, 16> little_u16_t;
+ typedef endian<order::little, uint_least32_t, 24> little_u24_t;
+ typedef endian<order::little, uint_least32_t, 32> little_u32_t;
+ typedef endian<order::little, uint_least64_t, 40> little_u40_t;
+ typedef endian<order::little, uint_least64_t, 48> little_u48_t;
+ typedef endian<order::little, uint_least64_t, 56> little_u56_t;
+ typedef endian<order::little, uint_least64_t, 64> little_u64_t;
+
+ // unaligned native endian signed integer types
+ typedef endian<order::native, int_least8_t, 8> native_8_t;
+ typedef endian<order::native, int_least16_t, 16> native_16_t;
+ typedef endian<order::native, int_least32_t, 24> native_24_t;
+ typedef endian<order::native, int_least32_t, 32> native_32_t;
+ typedef endian<order::native, int_least64_t, 40> native_40_t;
+ typedef endian<order::native, int_least64_t, 48> native_48_t;
+ typedef endian<order::native, int_least64_t, 56> native_56_t;
+ typedef endian<order::native, int_least64_t, 64> native_64_t;
+
+ // unaligned native endian unsigned integer types
+ typedef endian<order::native, uint_least8_t, 8> native_u8_t;
+ typedef endian<order::native, uint_least16_t, 16> native_u16_t;
+ typedef endian<order::native, uint_least32_t, 24> native_u24_t;
+ typedef endian<order::native, uint_least32_t, 32> native_u32_t;
+ typedef endian<order::native, uint_least64_t, 40> native_u40_t;
+ typedef endian<order::native, uint_least64_t, 48> native_u48_t;
+ typedef endian<order::native, uint_least64_t, 56> native_u56_t;
+ typedef endian<order::native, uint_least64_t, 64> native_u64_t;
+
} // namespace endian
} // namespace boost
@@ -577,7 +593,7 @@ sign partial specialization to correctly extend the sign when cover integer size
differs from endian representation size.
Last revised:
-20 May, 2013
+21 May, 2013
© Copyright Beman Dawes, 2006-2009
Distributed under the Boost Software License, Version 1.0. See
www.boost.org/ LICENSE_1_0.txt
diff --git a/include/boost/endian/types.hpp b/include/boost/endian/types.hpp
index 9640be4..7ba6886 100644
--- a/include/boost/endian/types.hpp
+++ b/include/boost/endian/types.hpp
@@ -285,7 +285,7 @@ namespace endian
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
- std::clog << "big, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
+ std::cout << "big, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
# endif
detail::store_big_endian(m_value, val);
}
@@ -295,7 +295,7 @@ namespace endian
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
- std::clog << "big, unaligned, " << n_bits << "-bits, convert(" << detail::load_big_endian(m_value) << ")\n";
+ std::cout << "big, unaligned, " << n_bits << "-bits, convert(" << detail::load_big_endian(m_value) << ")\n";
# endif
return detail::load_big_endian(m_value);
}
@@ -318,7 +318,7 @@ namespace endian
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
- std::clog << "little, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
+ std::cout << "little, unaligned, " << n_bits << "-bits, construct(" << val << ")\n";
# endif
detail::store_little_endian(m_value, val);
}
@@ -328,7 +328,7 @@ namespace endian
{
# ifdef BOOST_ENDIAN_LOG
if ( endian_log )
- std::clog << "little, unaligned, " << n_bits << "-bits, convert(" << detail::load_little_endian(m_value) << ")\n";
+ std::cout << "little, unaligned, " << n_bits << "-bits, convert(" << detail::load_little_endian(m_value) << ")\n";
# endif
return detail::load_little_endian(m_value);
}
@@ -367,9 +367,10 @@ namespace endian
// align::yes specializations; only n_bits == 16/32/64 supported
- template
- class endian
- : cover_operators, T>
+ // aligned big endian specialization
+ template
+ class endian
+ : cover_operators, T>
{
BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
@@ -378,16 +379,66 @@ namespace endian
# ifndef BOOST_ENDIAN_NO_CTORS
endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
explicit endian(T val)
- : m_value(::boost::endian::convert_value(val)) {}
+ {
+# ifdef BOOST_ENDIAN_LOG
+ if ( endian_log )
+ std::cout << "big, aligned, " << n_bits << "-bits, construct(" << val << ")\n";
+# endif
+ m_value = ::boost::endian::big_endian_value(val);
+ }
+
# endif
endian& operator=(T val)
{
- m_value = ::boost::endian::convert_value(val);
+ m_value = ::boost::endian::big_endian_value(val);
return *this;
}
operator T() const
{
- return ::boost::endian::convert_value(m_value);
+# ifdef BOOST_ENDIAN_LOG
+ if ( endian_log )
+ std::cout << "big, aligned, " << n_bits << "-bits, convert(" << ::boost::endian::big_endian_value(m_value) << ")\n";
+# endif
+ return ::boost::endian::big_endian_value(m_value);
+ }
+ const char* data() const {return reinterpret_cast(&m_value);}
+ private:
+ T m_value;
+ };
+
+ // aligned little endian specialization
+ template
+ class endian
+ : cover_operators, T>
+ {
+ BOOST_STATIC_ASSERT( (n_bits/8)*8 == n_bits );
+ BOOST_STATIC_ASSERT( sizeof(T) == n_bits/8 );
+ public:
+ typedef T value_type;
+# ifndef BOOST_ENDIAN_NO_CTORS
+ endian() BOOST_ENDIAN_DEFAULT_CONSTRUCT
+ explicit endian(T val)
+ {
+# ifdef BOOST_ENDIAN_LOG
+ if ( endian_log )
+ std::cout << "little, aligned, " << n_bits << "-bits, construct(" << val << ")\n";
+# endif
+ m_value = ::boost::endian::little_endian_value(val);
+ }
+
+# endif
+ endian& operator=(T val)
+ {
+ m_value = ::boost::endian::little_endian_value(val);
+ return *this;
+ }
+ operator T() const
+ {
+# ifdef BOOST_ENDIAN_LOG
+ if ( endian_log )
+ std::cout << "little, aligned, " << n_bits << "-bits, convert(" << ::boost::endian::little_endian_value(m_value) << ")\n";
+# endif
+ return ::boost::endian::little_endian_value(m_value);
}
const char* data() const {return reinterpret_cast(&m_value);}
private:
diff --git a/test/msvc2012/speed_test/speed_test.vcxproj b/test/msvc2012/speed_test/speed_test.vcxproj
index 63aaece..46d4f83 100644
--- a/test/msvc2012/speed_test/speed_test.vcxproj
+++ b/test/msvc2012/speed_test/speed_test.vcxproj
@@ -60,7 +60,7 @@
true
- "$(TargetDir)\$(TargetName).exe" 1000000
+ "$(TargetDir)\$(TargetName).exe" 1
@@ -80,7 +80,7 @@
true
- "$(TargetDir)\$(TargetName).exe" 1000000000
+ "$(TargetDir)\$(TargetName).exe" 10000000000
diff --git a/test/speed_test.cpp b/test/speed_test.cpp
index 5bb4efc..baecb46 100644
--- a/test/speed_test.cpp
+++ b/test/speed_test.cpp
@@ -8,6 +8,7 @@
//--------------------------------------------------------------------------------------//
//#define BOOST_ENDIAN_NO_INTRINSICS
+//#define BOOST_ENDIAN_LOG
#include
@@ -85,17 +86,57 @@ namespace
//--------------------------------------------------------------------------------------//
- template
- result_type test_inc(T x)
+ template
+ result_type test_add_T_to_T(T x)
{
- cout << "++ a value..." << endl;
+ cout << "Add T to T ..." << endl;
result_type result;
- result.v = 0;
- T y(x);
+ T y(0);
boost::timer::auto_cpu_timer t(places);
for (uint64_t i = 0; i < n; ++i)
{
- ++y;
+ y += x;
+ }
+ t.stop();
+ result.v = static_cast(y);
+ boost::timer::cpu_times times = t.elapsed();
+ result.cpu_time = (times.system + times.user);
+ t.report();
+ return result;
+ }
+
+ struct big_tag {};
+ struct little_tag {};
+
+ template
+ result_type test_add_conditionally_reversed_T_to_T(T x, big_tag)
+ {
+ cout << "add_conditionally_reversed_T_to_T (big)..." << endl;
+ result_type result;
+ T y(0);
+ boost::timer::auto_cpu_timer t(places);
+ for (uint64_t i = 0; i < n; ++i)
+ {
+ y += ::boost::endian::big_endian_value(x);
+ }
+ t.stop();
+ result.v = static_cast(y);
+ boost::timer::cpu_times times = t.elapsed();
+ result.cpu_time = (times.system + times.user);
+ t.report();
+ return result;
+ }
+
+ template
+ result_type test_add_conditionally_reversed_T_to_T(T x, little_tag)
+ {
+ cout << "add_conditionally_reversed_T_to_T (little)..." << endl;
+ result_type result;
+ T y(0);
+ boost::timer::auto_cpu_timer t(places);
+ for (uint64_t i = 0; i < n; ++i)
+ {
+ y += ::boost::endian::little_endian_value(x);
}
t.stop();
result.v = static_cast(y);
@@ -106,18 +147,15 @@ namespace
}
template
- result_type test_rev_inc(T x)
+ result_type test_add_Endian_to_T(EndianT x)
{
- cout << "reverse, then ++, then reverse a value..." << endl;
+ cout << "add_Endian_to_T..." << endl;
result_type result;
- result.v = 0;
- T y(x);
+ T y(0);
boost::timer::auto_cpu_timer t(places);
for (uint64_t i = 0; i < n; ++i)
{
- reverse(y);
- ++y;
- reverse(y);
+ y += x;
}
t.stop();
result.v = static_cast(y);
@@ -127,32 +165,15 @@ namespace
return result;
}
- template
- result_type test_endian_inc(T x)
- {
- cout << "++ an endian value..." << endl;
- result_type result;
- result.v = 0;
- EndianT y(x);
- boost::timer::auto_cpu_timer t(places);
- for (uint64_t i = 0; i < n; ++i)
- {
- ++y;
- }
- t.stop();
- result.v = static_cast(y);
- boost::timer::cpu_times times = t.elapsed();
- result.cpu_time = (times.system + times.user);
- t.report();
- return result;
- }
-
- template
+ template
void test(T x)
{
- test_inc(x);
- test_rev_inc(x);
- test_endian_inc(x);
+ test_add_T_to_T(x);
+ if (Order == order::big)
+ test_add_conditionally_reversed_T_to_T(x, big_tag());
+ else
+ test_add_conditionally_reversed_T_to_T(x, little_tag());
+ test_add_Endian_to_T(EndianT(x));
}
} // unnamed namespace
@@ -165,23 +186,43 @@ int cpp_main(int argc, char* argv[])
cout << "\nbyte swap intrinsics used: " BOOST_ENDIAN_INTRINSIC_MSG << endl;
+ cout << endl << "------------------------------------------------------" << endl;
+
cout << endl << "int16_t, big_16_t" << endl;
- test(0x1122);
+ test(0x1122);
+ cout << endl << "int16_t, big_int16_t" << endl;
+ test(0x1122);
cout << endl << "int16_t, little_16_t" << endl;
- test(0x1122);
+ test(0x1122);
+ cout << endl << "int16_t, little_int16_t" << endl;
+ test(0x1122);
+
+ cout << endl << "------------------------------------------------------" << endl;
cout << endl << "int32_t, big_32_t" << endl;
- test(0x11223344);
+ test(0x11223344);
+ cout << endl << "int32_t, big_int32_t" << endl;
+ test(0x11223344);
cout << endl << "int32_t, little_32_t" << endl;
- test(0x11223344);
+ test(0x11223344);
+ cout << endl << "int32_t, little_int32_t" << endl;
+ test(0x11223344);
+
+ cout << endl << "------------------------------------------------------" << endl;
cout << endl << "int64_t, big_64_t" << endl;
- test(0x1122334455667788);
+ test(0x1122334455667788);
+ cout << endl << "int64_t, big_int64_t" << endl;
+ test(0x1122334455667788);
cout << endl << "int64_t, little_64_t" << endl;
- test(0x1122334455667788);
+ test(0x1122334455667788);
+ cout << endl << "int64_t, little_int64_t" << endl;
+ test(0x1122334455667788);
+
+ cout << endl << "------------------------------------------------------" << endl;
//cout << "float" << endl;
//test(1.2345f);