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

Members

@@ -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);