diff --git a/include/boost/endian/buffers.hpp b/include/boost/endian/buffers.hpp index d8be041..51fe4f8 100644 --- a/include/boost/endian/buffers.hpp +++ b/include/boost/endian/buffers.hpp @@ -37,13 +37,9 @@ #include #include #include +#include #include #include -#include -#include -#include -#include -#include #include #include #include @@ -221,65 +217,6 @@ namespace endian namespace detail { - // Unrolled loops for loading and storing streams of bytes. - - template ::value > - struct unrolled_byte_loops - { - typedef unrolled_byte_loops next; - - // shifting a negative number is flagged by -fsanitize=undefined - // so use the corresponding unsigned type for the shifts - - typedef typename boost::conditional< - boost::is_integral::value, - boost::make_unsigned, boost::type_identity >::type::type U; - - static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT - { return static_cast(*(bytes - 1) | (static_cast(next::load_big(bytes - 1)) << 8)); } - static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT - { return static_cast(*bytes | (static_cast(next::load_little(bytes + 1)) << 8)); } - - static void store_big(unsigned char* bytes, T value) BOOST_NOEXCEPT - { - *(bytes - 1) = static_cast(value); - next::store_big(bytes - 1, static_cast(static_cast(value) >> 8)); - } - static void store_little(unsigned char* bytes, T value) BOOST_NOEXCEPT - { - *bytes = static_cast(value); - next::store_little(bytes + 1, static_cast(static_cast(value) >> 8)); - } - }; - - template - struct unrolled_byte_loops - { - static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT - { return *(bytes - 1); } - static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT - { return *bytes; } - static void store_big(unsigned char* bytes, T value) BOOST_NOEXCEPT - { *(bytes - 1) = static_cast(value); } - static void store_little(unsigned char* bytes, T value) BOOST_NOEXCEPT - { *bytes = static_cast(value); } - - }; - - template - struct unrolled_byte_loops - { - static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT - { return *reinterpret_cast(bytes - 1); } - static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT - { return *reinterpret_cast(bytes); } - static void store_big(unsigned char* bytes, T value) BOOST_NOEXCEPT - { *(bytes - 1) = static_cast(value); } - static void store_little(unsigned char* bytes, T value) BOOST_NOEXCEPT - { *bytes = static_cast(value); } - }; - template inline T load_big_endian(const void* bytes) BOOST_NOEXCEPT @@ -298,37 +235,14 @@ namespace endian inline void store_big_endian(void* bytes, T value) BOOST_NOEXCEPT { -# if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) - // All major x86 compilers elide this test and optimize out memcpy - // (the x86 architecture allows unaligned loads, but -fsanitize=undefined does not) - if (sizeof(T) == n_bytes) - { - endian::native_to_big_inplace(value); - std::memcpy( bytes, &value, sizeof(T) ); - return; - } -# endif - unrolled_byte_loops::store_big - (static_cast(bytes) + n_bytes, value); + endian::endian_store( value, static_cast( bytes ) ); } template inline void store_little_endian(void* bytes, T value) BOOST_NOEXCEPT { -# if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) - // All major x86 compilers elide this test and optimize out memcpy - // (the x86 architecture allows unaligned loads, but -fsanitize=undefined does not) - if (sizeof(T) == n_bytes) - { - // if we ever extend the #ifdef to non-x86: - // endian::native_to_little_inplace(value); - std::memcpy( bytes, &value, sizeof(T) ); - return; - } -# endif - unrolled_byte_loops::store_little - (static_cast(bytes), value); + endian::endian_store( value, static_cast( bytes ) ); } } // namespace detail diff --git a/include/boost/endian/detail/endian_load.hpp b/include/boost/endian/detail/endian_load.hpp index 323ce5e..c292e77 100644 --- a/include/boost/endian/detail/endian_load.hpp +++ b/include/boost/endian/detail/endian_load.hpp @@ -6,6 +6,7 @@ // Distributed under the Boost Software License, Version 1.0. // http://www.boost.org/LICENSE_1_0.txt +#include #include #include #include @@ -34,30 +35,6 @@ inline T endian_load( unsigned char const * p ) BOOST_NOEXCEPT namespace detail { -template struct integral_by_size -{ -}; - -template<> struct integral_by_size<1> -{ - typedef uint8_t type; -}; - -template<> struct integral_by_size<2> -{ - typedef uint16_t type; -}; - -template<> struct integral_by_size<4> -{ - typedef uint32_t type; -}; - -template<> struct integral_by_size<8> -{ - typedef uint64_t type; -}; - // same endianness, same size template struct endian_load_impl diff --git a/include/boost/endian/detail/endian_store.hpp b/include/boost/endian/detail/endian_store.hpp new file mode 100644 index 0000000..33501b6 --- /dev/null +++ b/include/boost/endian/detail/endian_store.hpp @@ -0,0 +1,197 @@ +#ifndef BOOST_ENDIAN_DETAIL_ENDIAN_STORE_HPP_INCLUDED +#define BOOST_ENDIAN_DETAIL_ENDIAN_STORE_HPP_INCLUDED + +// Copyright 2019 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +namespace boost +{ +namespace endian +{ + +namespace detail +{ + +template struct endian_store_impl +{ +}; + +} // namespace detail + +template +inline void endian_store( T const & v, unsigned char * p ) BOOST_NOEXCEPT +{ + return detail::endian_store_impl()( v, p ); +} + +namespace detail +{ + +// same endianness, same size + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + std::memcpy( p, &v, N ); + } +}; + +// same size, reverse endianness + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + typename integral_by_size::type tmp; + std::memcpy( &tmp, &v, N ); + + endian_reverse_inplace( tmp ); + + std::memcpy( p, &tmp, N ); + } +}; + +// truncating store 4 -> 3 + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 4 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[0]; + p[1] = tmp[1]; + p[2] = tmp[2]; + } +}; + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 4 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[1]; + p[1] = tmp[2]; + p[2] = tmp[3]; + } +}; + +// truncating store 8 -> 5 + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 8 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[0]; + p[1] = tmp[1]; + p[2] = tmp[2]; + p[3] = tmp[3]; + p[4] = tmp[4]; + } +}; + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 8 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[3]; + p[1] = tmp[4]; + p[2] = tmp[5]; + p[3] = tmp[6]; + p[4] = tmp[7]; + } +}; + +// truncating store 8 -> 6 + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 8 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[0]; + p[1] = tmp[1]; + p[2] = tmp[2]; + p[3] = tmp[3]; + p[4] = tmp[4]; + p[5] = tmp[5]; + } +}; + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 8 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[2]; + p[1] = tmp[3]; + p[2] = tmp[4]; + p[3] = tmp[5]; + p[4] = tmp[6]; + p[5] = tmp[7]; + } +}; + +// truncating store 8 -> 7 + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 8 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[0]; + p[1] = tmp[1]; + p[2] = tmp[2]; + p[3] = tmp[3]; + p[4] = tmp[4]; + p[5] = tmp[5]; + p[6] = tmp[6]; + } +}; + +template struct endian_store_impl +{ + inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT + { + unsigned char tmp[ 8 ]; + endian::endian_store( v, tmp ); + + p[0] = tmp[1]; + p[1] = tmp[2]; + p[2] = tmp[3]; + p[3] = tmp[4]; + p[4] = tmp[5]; + p[5] = tmp[6]; + p[6] = tmp[7]; + } +}; + +} // namespace detail + +} // namespace endian +} // namespace boost + +#endif // BOOST_ENDIAN_DETAIL_ENDIAN_STORE_HPP_INCLUDED diff --git a/include/boost/endian/detail/integral_by_size.hpp b/include/boost/endian/detail/integral_by_size.hpp new file mode 100644 index 0000000..b0fd885 --- /dev/null +++ b/include/boost/endian/detail/integral_by_size.hpp @@ -0,0 +1,47 @@ +#ifndef BOOST_ENDIAN_DETAIL_INTEGRAL_BY_SIZE_HPP_INCLUDED +#define BOOST_ENDIAN_DETAIL_INTEGRAL_BY_SIZE_HPP_INCLUDED + +// Copyright 2019 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include + +namespace boost +{ +namespace endian +{ +namespace detail +{ + +template struct integral_by_size +{ +}; + +template<> struct integral_by_size<1> +{ + typedef uint8_t type; +}; + +template<> struct integral_by_size<2> +{ + typedef uint16_t type; +}; + +template<> struct integral_by_size<4> +{ + typedef uint32_t type; +}; + +template<> struct integral_by_size<8> +{ + typedef uint64_t type; +}; + +} // namespace detail +} // namespace endian +} // namespace boost + +#endif // BOOST_ENDIAN_DETAIL_INTEGRAL_BY_SIZE_HPP_INCLUDED