diff --git a/include/boost/endian/converters.hpp b/include/boost/endian/converters.hpp index cee53f0..5c6a677 100644 --- a/include/boost/endian/converters.hpp +++ b/include/boost/endian/converters.hpp @@ -1,4 +1,4 @@ -// boost/endian/conversion.hpp -------------------------------------------------------// +// boost/endian/converters.hpp -------------------------------------------------------// // Copyright Beman Dawes 2010, 2011 @@ -8,9 +8,10 @@ #ifndef BOOST_ENDIAN_CONVERTERS_HPP #define BOOST_ENDIAN_CONVERTERS_HPP -#include "boost/config.hpp" +#include #include #include +#include #include #include @@ -62,7 +63,7 @@ namespace endian // compile-time generic byte order conversion template - inline T convert_bytes(T from) BOOST_NOEXCEPT; + /*inline*/ T convert_bytes(T from) BOOST_NOEXCEPT; // runtime actual byte-order determination inline BOOST_SCOPED_ENUM(order) actual_order(BOOST_SCOPED_ENUM(order) o) BOOST_NOEXCEPT; @@ -74,58 +75,84 @@ namespace endian BOOST_SCOPED_ENUM(order) to_order) BOOST_NOEXCEPT; //----------------------------------- implementation -----------------------------------// -// -- reverse_bytes implementation approach suggested by tymofey, with avoidance of +// -- reverse_bytes portable approach suggested by tymofey, with avoidance of // undefined behavior as suggested by Giovanni Piero Deretta, and a further // refinement suggested by Pyry Jahkola. +// -- reverse_bytes intrinsic approach suggested by David Stone, who privided his +// Boost licensed macro implementation. inline int16_t reverse_bytes(int16_t x) BOOST_NOEXCEPT { +# ifdef BOOST_ENDIAN_NO_INTRINSICS return (static_cast(x) << 8) | (static_cast(x) >> 8); +# else + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(static_cast(x)); +# endif } inline int32_t reverse_bytes(int32_t x) BOOST_NOEXCEPT { +# ifdef BOOST_ENDIAN_NO_INTRINSICS uint32_t step16; step16 = static_cast(x) << 16 | static_cast(x) >> 16; return ((static_cast(step16) << 8) & 0xff00ff00) | ((static_cast(step16) >> 8) & 0x00ff00ff); +# else + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(static_cast(x)); +# endif } inline int64_t reverse_bytes(int64_t x) BOOST_NOEXCEPT { +# ifdef BOOST_ENDIAN_NO_INTRINSICS uint64_t step32, step16; step32 = static_cast(x) << 32 | static_cast(x) >> 32; step16 = (step32 & 0x0000FFFF0000FFFF) << 16 | (step32 & 0xFFFF0000FFFF0000) >> 16; return static_cast((step16 & 0x00FF00FF00FF00FF) << 8 | (step16 & 0xFF00FF00FF00FF00) >> 8); +# else + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(static_cast(x)); +# endif } inline uint16_t reverse_bytes(uint16_t x) BOOST_NOEXCEPT { +# ifdef BOOST_ENDIAN_NO_INTRINSICS return (x << 8) | (x >> 8); +# else + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2(x); +# endif } - inline uint32_t reverse_bytes(uint32_t x) BOOST_NOEXCEPT + inline uint32_t reverse_bytes(uint32_t x) BOOST_NOEXCEPT { +# ifdef BOOST_ENDIAN_NO_INTRINSICS uint32_t step16; step16 = x << 16 | x >> 16; return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff); +# else + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(x); +# endif } inline uint64_t reverse_bytes(uint64_t x) BOOST_NOEXCEPT { +# ifdef BOOST_ENDIAN_NO_INTRINSICS uint64_t step32, step16; step32 = x << 32 | x >> 32; step16 = (step32 & 0x0000FFFF0000FFFF) << 16 | (step32 & 0xFFFF0000FFFF0000) >> 16; return (step16 & 0x00FF00FF00FF00FF) << 8 | (step16 & 0xFF00FF00FF00FF00) >> 8; +# else + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8(x); +# endif } // general reverse_bytes function template implementation approach using std::reverse @@ -161,6 +188,62 @@ namespace endian # endif } + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return x;} + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return x;} + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return x;} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return x;} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return x;} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return x;} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return x;} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return x;} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return x;} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return x;} + + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int16_t convert_bytes(int16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint16_t convert_bytes(uint16_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int32_t convert_bytes(int32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint32_t convert_bytes(uint32_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline int64_t convert_bytes(int64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + template<> inline uint64_t convert_bytes(uint64_t x) BOOST_NOEXCEPT {return reverse_bytes(x);} + inline BOOST_SCOPED_ENUM(order) actual_order(BOOST_SCOPED_ENUM(order) o) BOOST_NOEXCEPT { return o != order::native ? o : diff --git a/include/boost/endian/detail/intrinsic.hpp b/include/boost/endian/detail/intrinsic.hpp new file mode 100644 index 0000000..63f6c72 --- /dev/null +++ b/include/boost/endian/detail/intrinsic.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2012 David Stone +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://www.boost.org/libs/endian/ for documentation. + +#ifndef BOOST_ENDIAN_INTRINSIC_HPP +#define BOOST_ENDIAN_INTRINSIC_HPP + +#ifndef BOOST_DETAIL_ENDIAN_HPP +# include +#endif +#ifndef BOOST_CSTDINT_HPP +# include +#endif + + +#undef BOOST_ENDIAN_NO_INTRINSICS +#undef BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2 +#undef BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4 +#undef BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8 + +#if (defined __GNUC__ || defined __clang__) + #include + #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2 bswap_16 + #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4 bswap_32 + #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8 bswap_64 +#elif defined _MSC_VER + #include + #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_2 _byteswap_ushort + #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4 _byteswap_ulong + #define BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_8 _byteswap_uint64 +#else + #define BOOST_ENDIAN_NO_INTRINSICS +#endif + +#endif BOOST_ENDIAN_INTRINSIC_HPP diff --git a/test/benchmark.cpp b/test/benchmark.cpp index 3e66c9a..cd09ff1 100644 --- a/test/benchmark.cpp +++ b/test/benchmark.cpp @@ -35,6 +35,7 @@ namespace #endif typedef boost::timer::nanosecond_type nanosecond_t; + nanosecond_t benchmark(timee_func timee, const char* msg, nanosecond_t overhead = 0) { @@ -58,7 +59,7 @@ namespace t.stop(); times = t.elapsed(); cpu_time = (times.system + times.user) - overhead; - const long double sec = 1000000.0L; + const long double sec = 1000000000.0L; cout.setf(std::ios_base::fixed, std::ios_base::floatfield); cout.precision(places); cout << msg << " " << cpu_time / sec << endl; @@ -131,6 +132,11 @@ namespace | (static_cast(x) >> 24); } + inline int32_t by_return_intrinsic(int32_t x) + { + return BOOST_ENDIAN_INTRINSIC_BYTE_SWAP_4(static_cast(x)); + } + inline int32_t by_return_pyry(int32_t x) { uint32_t step16; @@ -146,42 +152,48 @@ namespace | ((x >> 8) & 0x0000ff00); } - int32_t modify_noop(int32_t x) + inline int32_t modify_noop(int32_t x) { int32_t v(x); return v; } - int32_t modify_in_place(int32_t x) + inline int32_t modify_in_place(int32_t x) { int32_t v(x); in_place(v); return v; } - int32_t modify_by_return(int32_t x) + inline int32_t modify_by_return(int32_t x) { int32_t v(x); return by_return(v); } - int32_t modify_by_return_pyry(int32_t x) + inline int32_t modify_by_return_pyry(int32_t x) { int32_t v(x); return by_return_pyry(v); } - void non_modify_assign(int32_t x, int32_t& y) + inline int32_t modify_by_return_intrinsic(int32_t x) + { + int32_t v(x); + return by_return_intrinsic(v); + } + + inline void non_modify_assign(int32_t x, int32_t& y) { y = x; } - void non_modify_two_operand(int32_t x, int32_t& y) + inline void non_modify_two_operand(int32_t x, int32_t& y) { two_operand(x, y); } - void non_modify_by_return(int32_t x, int32_t& y) + inline void non_modify_by_return(int32_t x, int32_t& y) { y = by_return(x); } @@ -198,9 +210,10 @@ int main(int argc, char * argv[]) #ifndef BOOST_TWO_ARG overhead = benchmark(modify_noop, "modify no-op"); - benchmark(modify_in_place, "modify in place", overhead); - benchmark(modify_by_return, "modify by return", overhead); - benchmark(modify_by_return_pyry, "modify by return", overhead); + benchmark(modify_in_place, "modify in place"/*, overhead*/); + benchmark(modify_by_return, "modify by return"/*, overhead*/); + benchmark(modify_by_return_pyry, "modify by return_pyry"/*, overhead*/); + benchmark(modify_by_return_intrinsic, "modify by return_intrinsic"/*, overhead*/); #else overhead = benchmark(non_modify_assign, "non_modify_assign "); benchmark(non_modify_two_operand, "non_modify_two_operand", overhead); diff --git a/test/converter_test.cpp b/test/converter_test.cpp index 9a2c186..af53bc6 100644 --- a/test/converter_test.cpp +++ b/test/converter_test.cpp @@ -21,7 +21,7 @@ namespace void test_reverse_bytes() { - std::cout << "test_reorder...\n"; + std::cout << "test_reverse_bytes...\n"; boost::int64_t i64 = 0x0102030405060708LL; BOOST_TEST_EQ(be::reverse_bytes(i64), 0x0807060504030201LL); @@ -59,7 +59,7 @@ namespace BOOST_TEST_EQ(be::reverse_bytes(ui16), 0x0201); BOOST_TEST_EQ(be::reverse_bytes(be::reverse_bytes(ui16)), ui16); - std::cout << " test_reorder complete\n"; + std::cout << " test_reverse_bytes complete\n"; } const boost::int64_t ni64 = 0x0102030405060708LL; @@ -118,7 +118,7 @@ namespace void test_conditional_reverse_bytes() { - std::cout << "test_conditional_reorder...\n"; + std::cout << "test_conditional_reverse_bytes...\n"; BOOST_TEST_EQ(be::big(ni64), bi64); BOOST_TEST_EQ(be::big(ni32), bi32); @@ -147,8 +147,23 @@ namespace BOOST_TEST_EQ(be::little(be::little(nui64)), nui64); BOOST_TEST_EQ(be::little(be::little(nui32)), nui32); BOOST_TEST_EQ(be::little(be::little(nui16)), nui16); + std::cout << " test_conditional_reverse_bytes complete\n"; - std::cout << " test_conditional_reorder complete\n"; + } + + void test_compile_time_convert_bytes() + { + std::cout << "test_compile_time_convert_bytes...\n"; + + BOOST_TEST_EQ((be::convert_bytes(bi32)), li32); + + std::cout << " test_compile_time_convert_bytes complete\n"; + } + + void test_runtime_convert_bytes() + { + std::cout << "test_runtime_convert_bytes...\n"; + std::cout << " test_runtime_convert_bytes complete\n"; } } // unnamed namespace @@ -158,6 +173,7 @@ int cpp_main(int, char * []) std::cerr << std::hex; test_reverse_bytes(); test_conditional_reverse_bytes(); + test_compile_time_convert_bytes(); return ::boost::report_errors(); } diff --git a/test/endian_test.cpp b/test/endian_test.cpp index ccd6633..c68c551 100644 --- a/test/endian_test.cpp +++ b/test/endian_test.cpp @@ -122,27 +122,28 @@ namespace if ( memcmp( v.c, "\10\7\6\5\4\3\2\1", 8) == 0 ) { cout << "This machine is little-endian.\n"; - # ifdef BOOST_BIG_INTEGER_OPERATORS - cout << "yet boost/detail/endian.hpp defines BOOST_BIG_INTEGER_OPERATORS.\n" - "You must fix boost/detail/endian.hpp for boost/endian.hpp to work correctly.\n" - "Please report the fix to the Boost mailing list.\n"; + # ifndef BOOST_LITTLE_ENDIAN + cout << "yet boost/detail/endian.hpp does not define BOOST_LITTLE_ENDIAN.\n" + "This must be fixed for the Boost Endian library to work correctly on this system.\n" + "Please report this problem to the Boost mailing list.\n"; exit(1); # endif } else if ( memcmp( v.c, "\1\2\3\4\5\6\7\10", 8) == 0 ) { cout << "This machine is big-endian.\n"; - # ifdef BOOST_LITTLE_INTEGER_OPERATORS - cout << "yet boost/detail/endian.hpp defines BOOST__LITTLE_INTEGER_OPERATORS.\n" - "You must fix boost/detail/endian.hpp for boost/endian.hpp to work correctly.\n" - "Please report the fix to the Boost mailing list.\n"; + # ifndef BOOST_BIG_ENDIAN + cout << "yet boost/detail/endian.hpp does not define BOOST_BIG_ENDIAN.\n" + "This must be fixed for the Boost Endian library to work correctly on this system.\n" + "Please report this problem to the Boost mailing list.\n"; exit(1); # endif } else { cout << "This machine is neither strict big-endian nor strict little-endian\n" - "You must modify boost/endian.hpp for it to work correctly.\n"; + "The Boost Endian library must be revised to work correctly on this system.\n"; + "Please report this problem to the Boost mailing list.\n"; exit(1); } cout << "That should not matter and is presented for your information only.\n"; diff --git a/test/msvc2012/benchmark/benchmark.vcxproj b/test/msvc2012/benchmark/benchmark.vcxproj index 08ed3b5..814bf2c 100644 --- a/test/msvc2012/benchmark/benchmark.vcxproj +++ b/test/msvc2012/benchmark/benchmark.vcxproj @@ -87,7 +87,7 @@ true - "$(TargetDir)\$(TargetName).exe" + "$(TargetDir)\$(TargetName).exe" 10000 Executing test... diff --git a/test/msvc2012/endian.sln b/test/msvc2012/endian.sln index cc263da..bcb0992 100644 --- a/test/msvc2012/endian.sln +++ b/test/msvc2012/endian.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual C++ Express 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "endian_test", "endian_test\endian_test.vcxproj", "{74C201F3-8308-40BE-BC0F-24974DEAF405}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "endian_in_union_test", "endian_in_union_test\endian_in_union_test.vcxproj", "{3926C6DC-9D1E-4227-BEF5-81F5EC621A75}" @@ -34,9 +34,7 @@ Global {A0060A5B-673C-4AD8-BD08-A5C643B1A1CB}.Release|Win32.ActiveCfg = Release|Win32 {A0060A5B-673C-4AD8-BD08-A5C643B1A1CB}.Release|Win32.Build.0 = Release|Win32 {8420E151-B23B-4651-B526-6AB11EF1E278}.Debug|Win32.ActiveCfg = Debug|Win32 - {8420E151-B23B-4651-B526-6AB11EF1E278}.Debug|Win32.Build.0 = Debug|Win32 {8420E151-B23B-4651-B526-6AB11EF1E278}.Release|Win32.ActiveCfg = Release|Win32 - {8420E151-B23B-4651-B526-6AB11EF1E278}.Release|Win32.Build.0 = Release|Win32 {8638A3D8-D121-40BF-82E5-127F1B1B2CB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8638A3D8-D121-40BF-82E5-127F1B1B2CB2}.Debug|Win32.Build.0 = Debug|Win32 {8638A3D8-D121-40BF-82E5-127F1B1B2CB2}.Release|Win32.ActiveCfg = Release|Win32