mirror of
https://github.com/boostorg/endian.git
synced 2025-08-03 14:34:33 +02:00
Add endian_store, use it in buffers.hpp
This commit is contained in:
@@ -37,13 +37,9 @@
|
|||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/config/workaround.hpp>
|
#include <boost/config/workaround.hpp>
|
||||||
#include <boost/predef/other/endian.h>
|
#include <boost/predef/other/endian.h>
|
||||||
|
#include <boost/endian/detail/endian_store.hpp>
|
||||||
#include <boost/endian/detail/endian_load.hpp>
|
#include <boost/endian/detail/endian_load.hpp>
|
||||||
#include <boost/endian/conversion.hpp>
|
#include <boost/endian/conversion.hpp>
|
||||||
#include <boost/type_traits/is_signed.hpp>
|
|
||||||
#include <boost/type_traits/make_unsigned.hpp>
|
|
||||||
#include <boost/type_traits/conditional.hpp>
|
|
||||||
#include <boost/type_traits/is_integral.hpp>
|
|
||||||
#include <boost/type_traits/type_identity.hpp>
|
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
#include <boost/core/scoped_enum.hpp>
|
#include <boost/core/scoped_enum.hpp>
|
||||||
@@ -221,65 +217,6 @@ namespace endian
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
// Unrolled loops for loading and storing streams of bytes.
|
|
||||||
|
|
||||||
template <typename T, std::size_t n_bytes,
|
|
||||||
bool sign=boost::is_signed<T>::value >
|
|
||||||
struct unrolled_byte_loops
|
|
||||||
{
|
|
||||||
typedef unrolled_byte_loops<T, n_bytes - 1, sign> 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<T>::value,
|
|
||||||
boost::make_unsigned<T>, boost::type_identity<T> >::type::type U;
|
|
||||||
|
|
||||||
static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT
|
|
||||||
{ return static_cast<T>(*(bytes - 1) | (static_cast<U>(next::load_big(bytes - 1)) << 8)); }
|
|
||||||
static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT
|
|
||||||
{ return static_cast<T>(*bytes | (static_cast<U>(next::load_little(bytes + 1)) << 8)); }
|
|
||||||
|
|
||||||
static void store_big(unsigned char* bytes, T value) BOOST_NOEXCEPT
|
|
||||||
{
|
|
||||||
*(bytes - 1) = static_cast<unsigned char>(value);
|
|
||||||
next::store_big(bytes - 1, static_cast<T>(static_cast<U>(value) >> 8));
|
|
||||||
}
|
|
||||||
static void store_little(unsigned char* bytes, T value) BOOST_NOEXCEPT
|
|
||||||
{
|
|
||||||
*bytes = static_cast<unsigned char>(value);
|
|
||||||
next::store_little(bytes + 1, static_cast<T>(static_cast<U>(value) >> 8));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct unrolled_byte_loops<T, 1, false>
|
|
||||||
{
|
|
||||||
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<unsigned char>(value); }
|
|
||||||
static void store_little(unsigned char* bytes, T value) BOOST_NOEXCEPT
|
|
||||||
{ *bytes = static_cast<unsigned char>(value); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct unrolled_byte_loops<T, 1, true>
|
|
||||||
{
|
|
||||||
static T load_big(const unsigned char* bytes) BOOST_NOEXCEPT
|
|
||||||
{ return *reinterpret_cast<const signed char*>(bytes - 1); }
|
|
||||||
static T load_little(const unsigned char* bytes) BOOST_NOEXCEPT
|
|
||||||
{ return *reinterpret_cast<const signed char*>(bytes); }
|
|
||||||
static void store_big(unsigned char* bytes, T value) BOOST_NOEXCEPT
|
|
||||||
{ *(bytes - 1) = static_cast<unsigned char>(value); }
|
|
||||||
static void store_little(unsigned char* bytes, T value) BOOST_NOEXCEPT
|
|
||||||
{ *bytes = static_cast<unsigned char>(value); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, std::size_t n_bytes>
|
template <typename T, std::size_t n_bytes>
|
||||||
inline
|
inline
|
||||||
T load_big_endian(const void* bytes) BOOST_NOEXCEPT
|
T load_big_endian(const void* bytes) BOOST_NOEXCEPT
|
||||||
@@ -298,37 +235,14 @@ namespace endian
|
|||||||
inline
|
inline
|
||||||
void store_big_endian(void* bytes, T value) BOOST_NOEXCEPT
|
void store_big_endian(void* bytes, T value) BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
# if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
|
endian::endian_store<T, n_bytes, order::big>( value, static_cast<unsigned char*>( bytes ) );
|
||||||
// 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<T, n_bytes>::store_big
|
|
||||||
(static_cast<unsigned char*>(bytes) + n_bytes, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t n_bytes>
|
template <typename T, std::size_t n_bytes>
|
||||||
inline
|
inline
|
||||||
void store_little_endian(void* bytes, T value) BOOST_NOEXCEPT
|
void store_little_endian(void* bytes, T value) BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
# if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
|
endian::endian_store<T, n_bytes, order::little>( value, static_cast<unsigned char*>( bytes ) );
|
||||||
// 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<T, n_bytes>::store_little
|
|
||||||
(static_cast<unsigned char*>(bytes), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// http://www.boost.org/LICENSE_1_0.txt
|
// http://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
|
#include <boost/endian/detail/integral_by_size.hpp>
|
||||||
#include <boost/endian/conversion.hpp>
|
#include <boost/endian/conversion.hpp>
|
||||||
#include <boost/type_traits/is_signed.hpp>
|
#include <boost/type_traits/is_signed.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@@ -34,30 +35,6 @@ inline T endian_load( unsigned char const * p ) BOOST_NOEXCEPT
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
template<std::size_t N> 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
|
// same endianness, same size
|
||||||
|
|
||||||
template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O> struct endian_load_impl<T, N, O, N, O>
|
template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O> struct endian_load_impl<T, N, O, N, O>
|
||||||
|
197
include/boost/endian/detail/endian_store.hpp
Normal file
197
include/boost/endian/detail/endian_store.hpp
Normal file
@@ -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 <boost/endian/detail/integral_by_size.hpp>
|
||||||
|
#include <boost/endian/conversion.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace endian
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class T, std::size_t N1, BOOST_SCOPED_ENUM(order) O1, std::size_t N2, BOOST_SCOPED_ENUM(order) O2> struct endian_store_impl
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) Order>
|
||||||
|
inline void endian_store( T const & v, unsigned char * p ) BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
return detail::endian_store_impl<T, sizeof(T), endian::order::native, N, Order>()( v, p );
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// same endianness, same size
|
||||||
|
|
||||||
|
template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O> struct endian_store_impl<T, N, O, N, O>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
std::memcpy( p, &v, N );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// same size, reverse endianness
|
||||||
|
|
||||||
|
template<class T, std::size_t N, BOOST_SCOPED_ENUM(order) O1, BOOST_SCOPED_ENUM(order) O2> struct endian_store_impl<T, N, O1, N, O2>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
typename integral_by_size<N>::type tmp;
|
||||||
|
std::memcpy( &tmp, &v, N );
|
||||||
|
|
||||||
|
endian_reverse_inplace( tmp );
|
||||||
|
|
||||||
|
std::memcpy( p, &tmp, N );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// truncating store 4 -> 3
|
||||||
|
|
||||||
|
template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 3, order::little>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 4 ];
|
||||||
|
endian::endian_store<T, 4, order::little>( v, tmp );
|
||||||
|
|
||||||
|
p[0] = tmp[0];
|
||||||
|
p[1] = tmp[1];
|
||||||
|
p[2] = tmp[2];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 4, Order, 3, order::big>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 4 ];
|
||||||
|
endian::endian_store<T, 4, order::big>( v, tmp );
|
||||||
|
|
||||||
|
p[0] = tmp[1];
|
||||||
|
p[1] = tmp[2];
|
||||||
|
p[2] = tmp[3];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// truncating store 8 -> 5
|
||||||
|
|
||||||
|
template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 5, order::little>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 8 ];
|
||||||
|
endian::endian_store<T, 8, order::little>( v, tmp );
|
||||||
|
|
||||||
|
p[0] = tmp[0];
|
||||||
|
p[1] = tmp[1];
|
||||||
|
p[2] = tmp[2];
|
||||||
|
p[3] = tmp[3];
|
||||||
|
p[4] = tmp[4];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 5, order::big>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 8 ];
|
||||||
|
endian::endian_store<T, 8, order::big>( 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<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 6, order::little>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 8 ];
|
||||||
|
endian::endian_store<T, 8, order::little>( 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<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 6, order::big>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 8 ];
|
||||||
|
endian::endian_store<T, 8, order::big>( 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<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 7, order::little>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 8 ];
|
||||||
|
endian::endian_store<T, 8, order::little>( 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<class T, BOOST_SCOPED_ENUM(order) Order> struct endian_store_impl<T, 8, Order, 7, order::big>
|
||||||
|
{
|
||||||
|
inline void operator()( T const & v, unsigned char * p ) const BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
unsigned char tmp[ 8 ];
|
||||||
|
endian::endian_store<T, 8, order::big>( 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
|
47
include/boost/endian/detail/integral_by_size.hpp
Normal file
47
include/boost/endian/detail/integral_by_size.hpp
Normal file
@@ -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 <boost/cstdint.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace endian
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<std::size_t N> 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
|
Reference in New Issue
Block a user