mirror of
https://github.com/boostorg/uuid.git
synced 2026-01-19 04:42:16 +00:00
Merge pull request #186 from Lastique/feature/from_chars_simd
Add SIMD implementation of `from_chars`
This commit is contained in:
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -116,6 +116,14 @@ jobs:
|
||||
container: ubuntu:24.04
|
||||
install: g++-13-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-13
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
instruction-set: rocketlake
|
||||
cpu-requirements: [ avx512f, avx512cd, avx512vl, avx512dq, avx512bw, avx512vbmi, avx512_vbmi2, avx512_bitalg, bmi1, bmi2 ]
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:24.04
|
||||
install: g++-13-multilib
|
||||
address-model: 32,64
|
||||
- toolset: clang
|
||||
compiler: clang++-3.9
|
||||
cxxstd: "11,14"
|
||||
@@ -254,6 +262,14 @@ jobs:
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-17
|
||||
- toolset: clang
|
||||
compiler: clang++-17
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
instruction-set: rocketlake
|
||||
cpu-requirements: [ avx512f, avx512cd, avx512vl, avx512dq, avx512bw, avx512vbmi, avx512_vbmi2, avx512_bitalg, bmi1, bmi2 ]
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-17
|
||||
- toolset: clang
|
||||
os: macos-14
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
|
||||
@@ -32,15 +32,18 @@ However, there are a few options that can be enabled by defining macros prior to
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/SSE4#SSE4.1[SSE4.1] extensions available in x86 processors.
|
||||
|
||||
|`BOOST_UUID_USE_AVX`
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/Advanced_Vector_Extensions[AVX] extensions available in modern x86 processors.
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/Advanced_Vector_Extensions[AVX] extensions available in x86 processors.
|
||||
|
||||
|`BOOST_UUID_USE_AVX2`
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions_2[AVX2] extensions available in modern x86 processors.
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions_2[AVX2] extensions available in x86 processors.
|
||||
|
||||
|`BOOST_UUID_USE_AVX512_V1`
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/AVX-512[AVX-512] F, VL, CD, BW and DQ extensions available in x86 processors (e.g. in Intel Skylake-X).
|
||||
|
||||
|`BOOST_UUID_USE_AVX10_1`
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/AVX-512[AVX-512] and https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#AVX10[AVX10.1] extensions available in modern x86 processors.
|
||||
When defined by user, this macro indicates support for the full set of instructions defined in AVX10.1. Currently, the library does not require 512-bit vectors and is compatible with CPUs implementing AVX-512F,
|
||||
CD, VL, BW and DQ instruction subsets (i.e. equivalent to Intel Skylake-X), so it may auto-detect and use AVX-512 even if only those subsets are supported.
|
||||
|If defined, enables optimizations for https://en.wikipedia.org/wiki/AVX-512[AVX-512] and https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#AVX10[AVX10.1] extensions available in x86 processors.
|
||||
When defined by user, this macro indicates support for the full set of instructions defined in AVX10.1. When auto-detected by the library, this macro may be defined even when not all AVX10.1 subsets
|
||||
are enabled, but rather when the detected subset is sufficient for the library.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
#include <boost/uuid/detail/static_assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring> // for strlen, wcslen
|
||||
#include <cstring> // for memcpy
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
|
||||
@@ -48,7 +48,11 @@
|
||||
#define BOOST_UUID_USE_AVX2
|
||||
#endif
|
||||
|
||||
#if ((defined(__AVX512F__) && defined(__AVX512VL__) && defined(__AVX512BW__)) || defined(__AVX10_1__)) && !defined(BOOST_UUID_USE_AVX10_1)
|
||||
#if (defined(__AVX512F__) && defined(__AVX512VL__) && defined(__AVX512BW__) && defined(__AVX512DQ__) && defined(__AVX512CD__)) && !defined(BOOST_UUID_USE_AVX512_V1)
|
||||
#define BOOST_UUID_USE_AVX512_V1
|
||||
#endif
|
||||
|
||||
#if ((defined(BOOST_UUID_USE_AVX512_V1) && defined(__AVX512VBMI__)) || defined(__AVX10_1__)) && !defined(BOOST_UUID_USE_AVX10_1)
|
||||
#define BOOST_UUID_USE_AVX10_1
|
||||
#endif
|
||||
|
||||
@@ -66,14 +70,22 @@
|
||||
#define BOOST_UUID_USE_AVX2
|
||||
#endif
|
||||
|
||||
#if ((defined(__AVX512F__) && defined(__AVX512VL__) && defined(__AVX512BW__)) || defined(__AVX10_1__)) && !defined(BOOST_UUID_USE_AVX10_1)
|
||||
#if (defined(__AVX512F__) && defined(__AVX512VL__) && defined(__AVX512BW__) && defined(__AVX512DQ__) && defined(__AVX512CD__)) && !defined(BOOST_UUID_USE_AVX512_V1)
|
||||
#define BOOST_UUID_USE_AVX512_V1
|
||||
#endif
|
||||
|
||||
#if ((defined(BOOST_UUID_USE_AVX512_V1) && defined(__AVX512VBMI__)) || defined(__AVX10_1__)) && !defined(BOOST_UUID_USE_AVX10_1)
|
||||
#define BOOST_UUID_USE_AVX10_1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// More advanced ISA extensions imply less advanced are also available
|
||||
#if !defined(BOOST_UUID_USE_AVX2) && defined(BOOST_UUID_USE_AVX10_1)
|
||||
#if !defined(BOOST_UUID_USE_AVX512_V1) && defined(BOOST_UUID_USE_AVX10_1)
|
||||
#define BOOST_UUID_USE_AVX512_V1
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UUID_USE_AVX2) && defined(BOOST_UUID_USE_AVX512_V1)
|
||||
#define BOOST_UUID_USE_AVX2
|
||||
#endif
|
||||
|
||||
@@ -99,6 +111,7 @@
|
||||
|
||||
#if !defined(BOOST_UUID_NO_SIMD) && \
|
||||
!defined(BOOST_UUID_USE_AVX10_1) && \
|
||||
!defined(BOOST_UUID_USE_AVX512_V1) && \
|
||||
!defined(BOOST_UUID_USE_AVX2) && \
|
||||
!defined(BOOST_UUID_USE_AVX) && \
|
||||
!defined(BOOST_UUID_USE_SSE41) && \
|
||||
|
||||
@@ -7,16 +7,53 @@
|
||||
|
||||
#include <boost/uuid/detail/is_constant_evaluated.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(__has_builtin)
|
||||
#if __has_builtin(__builtin_memcpy)
|
||||
#define BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCPY
|
||||
#endif
|
||||
#if __has_builtin(__builtin_memcmp)
|
||||
#define BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCMP
|
||||
#endif
|
||||
#elif defined(BOOST_GCC)
|
||||
#define BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCPY
|
||||
#define BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCMP
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCPY)
|
||||
#define BOOST_UUID_DETAIL_MEMCPY __builtin_memcpy
|
||||
#else
|
||||
#define BOOST_UUID_DETAIL_MEMCPY std::memcpy
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCMP)
|
||||
#define BOOST_UUID_DETAIL_MEMCMP __builtin_memcmp
|
||||
#else
|
||||
#define BOOST_UUID_DETAIL_MEMCMP std::memcmp
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCPY) || !defined(BOOST_UUID_DETAIL_HAS_BUILTIN_MEMCMP)
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
namespace detail {
|
||||
|
||||
// memcpy
|
||||
|
||||
BOOST_CXX14_CONSTEXPR inline void memcpy_cx( unsigned char* dest, unsigned char const* src, std::size_t n )
|
||||
// Note: The function below is a template to prevent an early check whether the function body can ever be evaluated in the context of a constant expression.
|
||||
// It can't, and that causes compilation errors with clang. The function must still be marked as constexpr to be able to call them in other
|
||||
// functions that are constexpr, even if such calls are never evaluated in a constant expression. Otherwise, gcc 5 through 8 gets upset.
|
||||
|
||||
template< typename = void >
|
||||
BOOST_CXX14_CONSTEXPR BOOST_FORCEINLINE void memcpy( void* dest, void const* src, std::size_t n ) noexcept
|
||||
{
|
||||
BOOST_UUID_DETAIL_MEMCPY( dest, src, n );
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR inline void memcpy_cx( unsigned char* dest, unsigned char const* src, std::size_t n ) noexcept
|
||||
{
|
||||
if( is_constant_evaluated_cx() )
|
||||
{
|
||||
@@ -24,11 +61,11 @@ BOOST_CXX14_CONSTEXPR inline void memcpy_cx( unsigned char* dest, unsigned char
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy( dest, src, n );
|
||||
BOOST_UUID_DETAIL_MEMCPY( dest, src, n );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_UUID_CXX14_CONSTEXPR_RT inline void memcpy_rt( unsigned char* dest, unsigned char const* src, std::size_t n )
|
||||
BOOST_UUID_CXX14_CONSTEXPR_RT inline void memcpy_rt( unsigned char* dest, unsigned char const* src, std::size_t n ) noexcept
|
||||
{
|
||||
if( is_constant_evaluated_rt() )
|
||||
{
|
||||
@@ -36,13 +73,13 @@ BOOST_UUID_CXX14_CONSTEXPR_RT inline void memcpy_rt( unsigned char* dest, unsign
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy( dest, src, n );
|
||||
BOOST_UUID_DETAIL_MEMCPY( dest, src, n );
|
||||
}
|
||||
}
|
||||
|
||||
// memcmp
|
||||
|
||||
BOOST_CXX14_CONSTEXPR inline int memcmp_cx( unsigned char const* s1, unsigned char const* s2, std::size_t n )
|
||||
BOOST_CXX14_CONSTEXPR inline int memcmp_cx( unsigned char const* s1, unsigned char const* s2, std::size_t n ) noexcept
|
||||
{
|
||||
if( is_constant_evaluated_cx() )
|
||||
{
|
||||
@@ -56,11 +93,11 @@ BOOST_CXX14_CONSTEXPR inline int memcmp_cx( unsigned char const* s1, unsigned ch
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::memcmp( s1, s2, n );
|
||||
return BOOST_UUID_DETAIL_MEMCMP( s1, s2, n );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_UUID_CXX14_CONSTEXPR_RT inline int memcmp_rt( unsigned char const* s1, unsigned char const* s2, std::size_t n )
|
||||
BOOST_UUID_CXX14_CONSTEXPR_RT inline int memcmp_rt( unsigned char const* s1, unsigned char const* s2, std::size_t n ) noexcept
|
||||
{
|
||||
if( is_constant_evaluated_rt() )
|
||||
{
|
||||
@@ -74,10 +111,13 @@ BOOST_UUID_CXX14_CONSTEXPR_RT inline int memcmp_rt( unsigned char const* s1, uns
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::memcmp( s1, s2, n );
|
||||
return BOOST_UUID_DETAIL_MEMCMP( s1, s2, n );
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace boost::uuids::detail
|
||||
|
||||
#undef BOOST_UUID_DETAIL_MEMCMP
|
||||
#undef BOOST_UUID_DETAIL_MEMCPY
|
||||
|
||||
#endif // #ifndef BOOST_UUID_DETAIL_CSTRING_INCLUDED
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/uuid/detail/is_constant_evaluated.hpp>
|
||||
#include <boost/uuid/detail/cstring.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
@@ -116,14 +116,14 @@ BOOST_CXX14_CONSTEXPR inline __uint128_t byteswap( __uint128_t x ) noexcept
|
||||
inline std::uint16_t load_native_u16( void const* p ) noexcept
|
||||
{
|
||||
std::uint16_t tmp;
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline std::uint16_t load_little_u16( void const* p ) noexcept
|
||||
{
|
||||
std::uint16_t tmp;
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN
|
||||
|
||||
@@ -144,7 +144,7 @@ BOOST_CXX14_CONSTEXPR inline std::uint16_t load_big_u16( unsigned char const* p
|
||||
}
|
||||
|
||||
std::uint16_t tmp = {};
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_BIG_ENDIAN
|
||||
|
||||
@@ -162,7 +162,7 @@ BOOST_CXX14_CONSTEXPR inline std::uint16_t load_big_u16( unsigned char const* p
|
||||
inline std::uint32_t load_native_u32( void const* p ) noexcept
|
||||
{
|
||||
std::uint32_t tmp;
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ BOOST_CXX14_CONSTEXPR inline std::uint32_t load_little_u32( unsigned char const*
|
||||
}
|
||||
|
||||
std::uint32_t tmp = {};
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN
|
||||
|
||||
@@ -205,7 +205,7 @@ BOOST_CXX14_CONSTEXPR inline std::uint32_t load_big_u32( unsigned char const* p
|
||||
}
|
||||
|
||||
std::uint32_t tmp = {};
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_BIG_ENDIAN
|
||||
|
||||
@@ -223,14 +223,14 @@ BOOST_CXX14_CONSTEXPR inline std::uint32_t load_big_u32( unsigned char const* p
|
||||
inline std::uint64_t load_native_u64( void const* p ) noexcept
|
||||
{
|
||||
std::uint64_t tmp = {};
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline std::uint64_t load_little_u64( void const* p ) noexcept
|
||||
{
|
||||
std::uint64_t tmp;
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN
|
||||
|
||||
@@ -260,7 +260,7 @@ BOOST_CXX14_CONSTEXPR inline std::uint64_t load_big_u64( unsigned char const* p
|
||||
}
|
||||
|
||||
std::uint64_t tmp = {};
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_BIG_ENDIAN
|
||||
|
||||
@@ -280,14 +280,14 @@ BOOST_CXX14_CONSTEXPR inline std::uint64_t load_big_u64( unsigned char const* p
|
||||
inline __uint128_t load_native_u128( void const* p ) noexcept
|
||||
{
|
||||
__uint128_t tmp = {};
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline __uint128_t load_little_u128( void const* p ) noexcept
|
||||
{
|
||||
__uint128_t tmp;
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_LITTLE_ENDIAN
|
||||
|
||||
@@ -303,7 +303,7 @@ inline __uint128_t load_little_u128( void const* p ) noexcept
|
||||
inline __uint128_t load_big_u128( void const* p ) noexcept
|
||||
{
|
||||
__uint128_t tmp = {};
|
||||
std::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
detail::memcpy( &tmp, p, sizeof( tmp ) );
|
||||
|
||||
#if BOOST_UUID_BYTE_ORDER == BOOST_UUID_ORDER_BIG_ENDIAN
|
||||
|
||||
@@ -322,7 +322,7 @@ inline __uint128_t load_big_u128( void const* p ) noexcept
|
||||
|
||||
inline void store_native_u16( void* p, std::uint16_t v ) noexcept
|
||||
{
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_little_u16( void* p, std::uint16_t v ) noexcept
|
||||
@@ -333,7 +333,7 @@ inline void store_little_u16( void* p, std::uint16_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_big_u16( void* p, std::uint16_t v ) noexcept
|
||||
@@ -344,14 +344,14 @@ inline void store_big_u16( void* p, std::uint16_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
// store_*_u32
|
||||
|
||||
inline void store_native_u32( void* p, std::uint32_t v ) noexcept
|
||||
{
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_little_u32( void* p, std::uint32_t v ) noexcept
|
||||
@@ -362,7 +362,7 @@ inline void store_little_u32( void* p, std::uint32_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_big_u32( void* p, std::uint32_t v ) noexcept
|
||||
@@ -373,14 +373,14 @@ inline void store_big_u32( void* p, std::uint32_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
// store_*_u64
|
||||
|
||||
inline void store_native_u64( void* p, std::uint64_t v ) noexcept
|
||||
{
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_little_u64( void* p, std::uint64_t v ) noexcept
|
||||
@@ -391,7 +391,7 @@ inline void store_little_u64( void* p, std::uint64_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_big_u64( void* p, std::uint64_t v ) noexcept
|
||||
@@ -402,7 +402,7 @@ inline void store_big_u64( void* p, std::uint64_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
// store_*_u128
|
||||
@@ -411,7 +411,7 @@ inline void store_big_u64( void* p, std::uint64_t v ) noexcept
|
||||
|
||||
inline void store_native_u128( void* p, __uint128_t v ) noexcept
|
||||
{
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_little_u128( void* p, __uint128_t v ) noexcept
|
||||
@@ -422,7 +422,7 @@ inline void store_little_u128( void* p, __uint128_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
inline void store_big_u128( void* p, __uint128_t v ) noexcept
|
||||
@@ -433,7 +433,7 @@ inline void store_big_u128( void* p, __uint128_t v ) noexcept
|
||||
|
||||
#endif
|
||||
|
||||
std::memcpy( p, &v, sizeof( v ) );
|
||||
detail::memcpy( p, &v, sizeof( v ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,167 +6,33 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/uuid/detail/config.hpp>
|
||||
#include <boost/uuid/detail/is_constant_evaluated.hpp>
|
||||
#include <boost/uuid/detail/from_chars_result.hpp>
|
||||
#include <boost/uuid/detail/from_chars_generic.hpp>
|
||||
#if defined(BOOST_UUID_USE_SSE41)
|
||||
#include <boost/uuid/detail/from_chars_x86.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
namespace detail {
|
||||
|
||||
// 0-9, A-F, a-f are consecutive in both ASCII and EBCDIC
|
||||
|
||||
constexpr char const* from_chars_digits( char const* ) noexcept
|
||||
{
|
||||
return "09AFaf-{}";
|
||||
}
|
||||
|
||||
constexpr wchar_t const* from_chars_digits( wchar_t const* ) noexcept
|
||||
{
|
||||
return L"09AFaf-{}";
|
||||
}
|
||||
|
||||
constexpr char16_t const* from_chars_digits( char16_t const* ) noexcept
|
||||
{
|
||||
return u"09AFaf-{}";
|
||||
}
|
||||
|
||||
constexpr char32_t const* from_chars_digits( char32_t const* ) noexcept
|
||||
{
|
||||
return U"09AFaf-{}";
|
||||
}
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
|
||||
constexpr char8_t const* from_chars_digits( char8_t const* ) noexcept
|
||||
{
|
||||
return u8"09AFaf-{}";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
unsigned char from_chars_digit_value( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
|
||||
if( ch >= digits[ 0 ] && ch <= digits[ 1 ] )
|
||||
{
|
||||
return static_cast<unsigned char>( ch - digits[ 0 ] );
|
||||
}
|
||||
|
||||
if( ch >= digits[ 2 ] && ch <= digits[ 3 ] )
|
||||
{
|
||||
return static_cast<unsigned char>( ch - digits[ 2 ] + 10 );
|
||||
}
|
||||
|
||||
if( ch >= digits[ 4 ] && ch <= digits[ 5 ] )
|
||||
{
|
||||
return static_cast<unsigned char>( ch - digits[ 4 ] + 10 );
|
||||
}
|
||||
|
||||
return 255;
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
bool from_chars_is_dash( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
return ch == digits[ 6 ];
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
bool from_chars_is_opening_brace( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
return ch == digits[ 7 ];
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
bool from_chars_is_closing_brace( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
return ch == digits[ 8 ];
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
enum class from_chars_error
|
||||
{
|
||||
none = 0,
|
||||
|
||||
unexpected_end_of_input,
|
||||
hex_digit_expected,
|
||||
dash_expected,
|
||||
closing_brace_expected,
|
||||
unexpected_extra_input
|
||||
};
|
||||
|
||||
template<class Ch> struct from_chars_result
|
||||
{
|
||||
Ch const* ptr;
|
||||
from_chars_error ec;
|
||||
|
||||
constexpr explicit operator bool() const noexcept { return ec == from_chars_error::none; }
|
||||
};
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
BOOST_UUID_CXX14_CONSTEXPR_RT inline
|
||||
from_chars_result<Ch> from_chars( Ch const* first, Ch const* last, uuid& u ) noexcept
|
||||
{
|
||||
u = {};
|
||||
|
||||
for( std::size_t i = 0; i < 16; ++i )
|
||||
#if defined(BOOST_UUID_USE_SSE41)
|
||||
if( detail::is_constant_evaluated_rt() )
|
||||
{
|
||||
if( first == last )
|
||||
{
|
||||
return { first, from_chars_error::unexpected_end_of_input };
|
||||
}
|
||||
|
||||
unsigned char v1 = detail::from_chars_digit_value( *first );
|
||||
|
||||
if( v1 == 255 )
|
||||
{
|
||||
return { first, from_chars_error::hex_digit_expected };
|
||||
}
|
||||
|
||||
++first;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
return { first, from_chars_error::unexpected_end_of_input };
|
||||
}
|
||||
|
||||
unsigned char v2 = detail::from_chars_digit_value( *first );
|
||||
|
||||
if( v2 == 255 )
|
||||
{
|
||||
return { first, from_chars_error::hex_digit_expected };
|
||||
}
|
||||
|
||||
++first;
|
||||
|
||||
u.data()[ i ] = static_cast<unsigned char>( ( v1 << 4 ) + v2 );
|
||||
|
||||
if( i == 3 || i == 5 || i == 7 || i == 9 )
|
||||
{
|
||||
if( first == last )
|
||||
{
|
||||
return { first, from_chars_error::unexpected_end_of_input };
|
||||
}
|
||||
|
||||
if( !detail::from_chars_is_dash( *first ) )
|
||||
{
|
||||
return { first, from_chars_error::dash_expected };
|
||||
}
|
||||
|
||||
++first;
|
||||
}
|
||||
return detail::from_chars_generic( first, last, u );
|
||||
}
|
||||
|
||||
return { first, from_chars_error::none };
|
||||
else
|
||||
{
|
||||
return detail::from_chars_simd( first, last, u );
|
||||
}
|
||||
#else
|
||||
return detail::from_chars_generic( first, last, u );
|
||||
#endif
|
||||
}
|
||||
|
||||
}} //namespace boost::uuids
|
||||
|
||||
162
include/boost/uuid/detail/from_chars_generic.hpp
Normal file
162
include/boost/uuid/detail/from_chars_generic.hpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#ifndef BOOST_UUID_DETAIL_FROM_CHARS_GENERIC_HPP_INCLUDED
|
||||
#define BOOST_UUID_DETAIL_FROM_CHARS_GENERIC_HPP_INCLUDED
|
||||
|
||||
// Copyright 2025 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/detail/from_chars_result.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_UUID_REPORT_IMPLEMENTATION)
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
BOOST_PRAGMA_MESSAGE( "Using from_chars_generic.hpp" )
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
namespace detail {
|
||||
|
||||
// 0-9, A-F, a-f are consecutive in both ASCII and EBCDIC
|
||||
|
||||
constexpr char const* from_chars_digits( char const* ) noexcept
|
||||
{
|
||||
return "09AFaf-{}";
|
||||
}
|
||||
|
||||
constexpr wchar_t const* from_chars_digits( wchar_t const* ) noexcept
|
||||
{
|
||||
return L"09AFaf-{}";
|
||||
}
|
||||
|
||||
constexpr char16_t const* from_chars_digits( char16_t const* ) noexcept
|
||||
{
|
||||
return u"09AFaf-{}";
|
||||
}
|
||||
|
||||
constexpr char32_t const* from_chars_digits( char32_t const* ) noexcept
|
||||
{
|
||||
return U"09AFaf-{}";
|
||||
}
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
|
||||
constexpr char8_t const* from_chars_digits( char8_t const* ) noexcept
|
||||
{
|
||||
return u8"09AFaf-{}";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
unsigned char from_chars_digit_value( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
|
||||
if( ch >= digits[ 0 ] && ch <= digits[ 1 ] )
|
||||
{
|
||||
return static_cast<unsigned char>( ch - digits[ 0 ] );
|
||||
}
|
||||
|
||||
if( ch >= digits[ 2 ] && ch <= digits[ 3 ] )
|
||||
{
|
||||
return static_cast<unsigned char>( ch - digits[ 2 ] + 10 );
|
||||
}
|
||||
|
||||
if( ch >= digits[ 4 ] && ch <= digits[ 5 ] )
|
||||
{
|
||||
return static_cast<unsigned char>( ch - digits[ 4 ] + 10 );
|
||||
}
|
||||
|
||||
return 255;
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
bool from_chars_is_dash( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
return ch == digits[ 6 ];
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
bool from_chars_is_opening_brace( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
return ch == digits[ 7 ];
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
bool from_chars_is_closing_brace( Ch ch ) noexcept
|
||||
{
|
||||
constexpr Ch const* digits = detail::from_chars_digits( static_cast<Ch const*>( nullptr ) );
|
||||
return ch == digits[ 8 ];
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
BOOST_CXX14_CONSTEXPR inline
|
||||
from_chars_result<Ch> from_chars_generic( Ch const* first, Ch const* last, uuid& u ) noexcept
|
||||
{
|
||||
u = {};
|
||||
|
||||
for( std::size_t i = 0; i < 16; ++i )
|
||||
{
|
||||
if( first == last )
|
||||
{
|
||||
return { first, from_chars_error::unexpected_end_of_input };
|
||||
}
|
||||
|
||||
unsigned char v1 = detail::from_chars_digit_value( *first );
|
||||
|
||||
if( v1 == 255 )
|
||||
{
|
||||
return { first, from_chars_error::hex_digit_expected };
|
||||
}
|
||||
|
||||
++first;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
return { first, from_chars_error::unexpected_end_of_input };
|
||||
}
|
||||
|
||||
unsigned char v2 = detail::from_chars_digit_value( *first );
|
||||
|
||||
if( v2 == 255 )
|
||||
{
|
||||
return { first, from_chars_error::hex_digit_expected };
|
||||
}
|
||||
|
||||
++first;
|
||||
|
||||
u.data()[ i ] = static_cast<unsigned char>( ( v1 << 4 ) + v2 );
|
||||
|
||||
if( i == 3 || i == 5 || i == 7 || i == 9 )
|
||||
{
|
||||
if( first == last )
|
||||
{
|
||||
return { first, from_chars_error::unexpected_end_of_input };
|
||||
}
|
||||
|
||||
if( !detail::from_chars_is_dash( *first ) )
|
||||
{
|
||||
return { first, from_chars_error::dash_expected };
|
||||
}
|
||||
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
return { first, from_chars_error::none };
|
||||
}
|
||||
|
||||
}}} //namespace boost::uuids::detail
|
||||
|
||||
#endif // BOOST_UUID_DETAIL_TO_CHARS_GENERIC_HPP_INCLUDED
|
||||
32
include/boost/uuid/detail/from_chars_result.hpp
Normal file
32
include/boost/uuid/detail/from_chars_result.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef BOOST_UUID_DETAIL_FROM_CHARS_RESULT_HPP_INCLUDED
|
||||
#define BOOST_UUID_DETAIL_FROM_CHARS_RESULT_HPP_INCLUDED
|
||||
|
||||
// Copyright 2025 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
|
||||
enum class from_chars_error
|
||||
{
|
||||
none = 0,
|
||||
|
||||
unexpected_end_of_input,
|
||||
hex_digit_expected,
|
||||
dash_expected,
|
||||
closing_brace_expected,
|
||||
unexpected_extra_input
|
||||
};
|
||||
|
||||
template<class Ch> struct from_chars_result
|
||||
{
|
||||
Ch const* ptr;
|
||||
from_chars_error ec;
|
||||
|
||||
constexpr explicit operator bool() const noexcept { return ec == from_chars_error::none; }
|
||||
};
|
||||
|
||||
}} //namespace boost::uuids
|
||||
|
||||
#endif // BOOST_UUID_DETAIL_FROM_CHARS_RESULT_HPP_INCLUDED
|
||||
952
include/boost/uuid/detail/from_chars_x86.hpp
Normal file
952
include/boost/uuid/detail/from_chars_x86.hpp
Normal file
@@ -0,0 +1,952 @@
|
||||
#ifndef BOOST_UUID_DETAIL_FROM_CHARS_X86_HPP_INCLUDED
|
||||
#define BOOST_UUID_DETAIL_FROM_CHARS_X86_HPP_INCLUDED
|
||||
|
||||
// Copyright 2025 Andrey Semashev
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/uuid/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_UUID_USE_SSE41)
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/detail/endian.hpp>
|
||||
#include <boost/uuid/detail/from_chars_result.hpp>
|
||||
#include <boost/uuid/detail/simd_vector.hpp>
|
||||
|
||||
#if defined(BOOST_UUID_REPORT_IMPLEMENTATION)
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX10_1)
|
||||
BOOST_PRAGMA_MESSAGE( "Using from_chars_x86.hpp, AVX10.1" )
|
||||
|
||||
#elif defined(BOOST_UUID_USE_AVX512_V1)
|
||||
BOOST_PRAGMA_MESSAGE( "Using from_chars_x86.hpp, AVX512v1" )
|
||||
|
||||
#elif defined(BOOST_UUID_USE_AVX)
|
||||
BOOST_PRAGMA_MESSAGE( "Using from_chars_x86.hpp, AVX" )
|
||||
|
||||
#else
|
||||
BOOST_PRAGMA_MESSAGE( "Using from_chars_x86.hpp, SSE4.1" )
|
||||
|
||||
#endif
|
||||
#endif // #if defined(BOOST_UUID_REPORT_IMPLEMENTATION)
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX)
|
||||
#include <immintrin.h>
|
||||
#else
|
||||
#include <smmintrin.h>
|
||||
#endif
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
namespace detail {
|
||||
|
||||
//! Returns the number of trailing zero bits in a non-zero input integer
|
||||
BOOST_FORCEINLINE std::uint32_t countr_zero_nz(std::uint32_t n) noexcept
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_ctz(n);
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
unsigned long index;
|
||||
_BitScanForward(&index, n);
|
||||
return static_cast< std::uint32_t >(index);
|
||||
#else
|
||||
std::uint32_t index = 0u;
|
||||
if ((n & 0xFFFF) == 0u)
|
||||
{
|
||||
n >>= 16u;
|
||||
index += 16u;
|
||||
}
|
||||
if ((n & 0xFF) == 0u)
|
||||
{
|
||||
n >>= 8u;
|
||||
index += 8u;
|
||||
}
|
||||
if ((n & 0xF) == 0u)
|
||||
{
|
||||
n >>= 4u;
|
||||
index += 4u;
|
||||
}
|
||||
if ((n & 0x3) == 0u)
|
||||
{
|
||||
n >>= 2u;
|
||||
index += 2u;
|
||||
}
|
||||
if ((n & 0x1) == 0u)
|
||||
{
|
||||
index += 1u;
|
||||
}
|
||||
return index;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<
|
||||
typename Char,
|
||||
bool IsCharASCIICompatible = ('0' == 0x30 && '9' == 0x39 && 'A' == 0x41 && 'F' == 0x46 && 'a' == 0x61 && 'f' == 0x66 && '-' == 0x2D),
|
||||
bool IsWCharASCIICompatible = (L'0' == 0x30 && L'9' == 0x39 && L'A' == 0x41 && L'F' == 0x46 && L'a' == 0x61 && L'f' == 0x66 && L'-' == 0x2D)
|
||||
>
|
||||
struct from_chars_simd_char_constants
|
||||
{
|
||||
static const simd_vector128< std::uint8_t > mm_expected_dashes;
|
||||
|
||||
static constexpr std::uint8_t char_code2 = 0x61; // 'a' in ASCII
|
||||
static constexpr std::uint8_t char_code2_sub = static_cast< std::uint8_t >(char_code2 - 10u);
|
||||
static constexpr std::uint8_t char_code1 = 0x41; // 'A' in ASCII
|
||||
static constexpr std::uint8_t char_code1_sub = static_cast< std::uint8_t >(char_code1 - 10u);
|
||||
static constexpr std::uint8_t char_code0 = 0x30; // '0' in ASCII
|
||||
static constexpr std::uint8_t char_code0_sub = char_code0;
|
||||
|
||||
static constexpr std::uint32_t char_code_sub =
|
||||
(static_cast< std::uint32_t >(char_code0_sub) << 16u) | (static_cast< std::uint32_t >(char_code1_sub) << 8u) | char_code2_sub;
|
||||
|
||||
static const simd_vector128< std::uint8_t > mm_char_code2_cmp;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code1_cmp;
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
static const simd_vector128< std::uint8_t > mm_char_code2_sub;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code1_sub;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code0_sub;
|
||||
#endif // defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
};
|
||||
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_expected_dashes =
|
||||
{{ 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x2D }}; // 0x2D is '-' in ASCII
|
||||
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code2_cmp =
|
||||
{{
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u)
|
||||
}};
|
||||
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code1_cmp =
|
||||
{{
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u)
|
||||
}};
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code2_sub =
|
||||
{{
|
||||
char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub,
|
||||
char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub
|
||||
}};
|
||||
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code1_sub =
|
||||
{{
|
||||
char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub,
|
||||
char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub
|
||||
}};
|
||||
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_code0_sub =
|
||||
{{
|
||||
char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub,
|
||||
char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub
|
||||
}};
|
||||
|
||||
#endif // defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
struct from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >
|
||||
{
|
||||
static_assert(static_cast< std::int8_t >('0') > -128 && static_cast< std::int8_t >('A') > -128 && static_cast< std::int8_t >('a') > -128,
|
||||
"Boost.UUID: Unsupported char encoding, hexadecimal character codes are expected to be greater than -128");
|
||||
|
||||
static const simd_vector128< std::uint8_t > mm_expected_dashes;
|
||||
|
||||
static constexpr std::uint8_t char_code2 = static_cast< std::uint8_t >
|
||||
(
|
||||
static_cast< std::int8_t >('a') > static_cast< std::int8_t >('A') ?
|
||||
(
|
||||
static_cast< std::int8_t >('a') > static_cast< std::int8_t >('0') ? 'a' : '0'
|
||||
) :
|
||||
(
|
||||
static_cast< std::int8_t >('A') > static_cast< std::int8_t >('0') ? 'A' : '0'
|
||||
)
|
||||
);
|
||||
static constexpr std::uint8_t char_code2_sub = char_code2 == static_cast< std::uint8_t >('0') ?
|
||||
static_cast< std::uint8_t >('0') : static_cast< std::uint8_t >(char_code2 - 10u);
|
||||
|
||||
static constexpr std::uint8_t char_code1 = static_cast< std::uint8_t >
|
||||
(
|
||||
static_cast< std::int8_t >('a') > static_cast< std::int8_t >('A') ?
|
||||
(
|
||||
static_cast< std::int8_t >('a') < static_cast< std::int8_t >('0') ? 'a' : '0'
|
||||
) :
|
||||
(
|
||||
static_cast< std::int8_t >('A') < static_cast< std::int8_t >('0') ? 'A' : '0'
|
||||
)
|
||||
);
|
||||
static constexpr std::uint8_t char_code1_sub = char_code1 == static_cast< std::uint8_t >('0') ?
|
||||
static_cast< std::uint8_t >('0') : static_cast< std::uint8_t >(char_code1 - 10u);
|
||||
|
||||
static constexpr std::uint8_t char_code0 = static_cast< std::uint8_t >
|
||||
(
|
||||
static_cast< std::int8_t >('a') < static_cast< std::int8_t >('A') ?
|
||||
(
|
||||
static_cast< std::int8_t >('a') < static_cast< std::int8_t >('0') ? 'a' : '0'
|
||||
) :
|
||||
(
|
||||
static_cast< std::int8_t >('A') < static_cast< std::int8_t >('0') ? 'A' : '0'
|
||||
)
|
||||
);
|
||||
static constexpr std::uint8_t char_code0_sub = char_code0 == static_cast< std::uint8_t >('0') ?
|
||||
static_cast< std::uint8_t >('0') : static_cast< std::uint8_t >(char_code0 - 10u);
|
||||
|
||||
static constexpr std::uint32_t char_code_sub =
|
||||
(static_cast< std::uint32_t >(char_code0_sub) << 16u) | (static_cast< std::uint32_t >(char_code1_sub) << 8u) | char_code2_sub;
|
||||
|
||||
static const simd_vector128< std::uint8_t > mm_char_code2_cmp;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code1_cmp;
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
static const simd_vector128< std::uint8_t > mm_char_code2_sub;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code1_sub;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code0_sub;
|
||||
#endif // defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
};
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_expected_dashes =
|
||||
{{
|
||||
static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00,
|
||||
0x00, 0x00, static_cast< std::uint8_t >('-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >('-')
|
||||
}};
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code2_cmp =
|
||||
{{
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u)
|
||||
}};
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code1_cmp =
|
||||
{{
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u)
|
||||
}};
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code2_sub =
|
||||
{{
|
||||
char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub,
|
||||
char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub
|
||||
}};
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code1_sub =
|
||||
{{
|
||||
char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub,
|
||||
char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub
|
||||
}};
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_code0_sub =
|
||||
{{
|
||||
char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub,
|
||||
char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub
|
||||
}};
|
||||
|
||||
#endif // defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
struct from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >
|
||||
{
|
||||
static_assert(static_cast< wchar_t >(static_cast< std::uint8_t >(L'0')) == L'0' && static_cast< wchar_t >(static_cast< std::uint8_t >(L'9')) == L'9' &&
|
||||
static_cast< wchar_t >(static_cast< std::uint8_t >(L'a')) == L'a' && static_cast< wchar_t >(static_cast< std::uint8_t >(L'f')) == L'f' &&
|
||||
static_cast< wchar_t >(static_cast< std::uint8_t >(L'-')) == L'-',
|
||||
"Boost.UUID: Unsupported wchar_t encoding, hexadecimal and dash character codes are expected to be representable by a single byte");
|
||||
|
||||
static_assert(static_cast< std::int8_t >(L'0') > -128 && static_cast< std::int8_t >(L'A') > -128 && static_cast< std::int8_t >(L'a') > -128,
|
||||
"Boost.UUID: Unsupported wchar_t encoding, hexadecimal character codes are expected to be greater than -128");
|
||||
|
||||
static const simd_vector128< std::uint8_t > mm_expected_dashes;
|
||||
|
||||
static constexpr std::uint8_t char_code2 = static_cast< std::uint8_t >
|
||||
(
|
||||
static_cast< std::int8_t >(L'a') > static_cast< std::int8_t >(L'A') ?
|
||||
(
|
||||
static_cast< std::int8_t >(L'a') > static_cast< std::int8_t >(L'0') ? L'a' : L'0'
|
||||
) :
|
||||
(
|
||||
static_cast< std::int8_t >(L'A') > static_cast< std::int8_t >(L'0') ? L'A' : L'0'
|
||||
)
|
||||
);
|
||||
static constexpr std::uint8_t char_code2_sub = char_code2 == static_cast< std::uint8_t >(L'0') ?
|
||||
static_cast< std::uint8_t >(L'0') : static_cast< std::uint8_t >(char_code2 - 10u);
|
||||
|
||||
static constexpr std::uint8_t char_code1 = static_cast< std::uint8_t >
|
||||
(
|
||||
static_cast< std::int8_t >(L'a') > static_cast< std::int8_t >(L'A') ?
|
||||
(
|
||||
static_cast< std::int8_t >(L'a') < static_cast< std::int8_t >(L'0') ? L'a' : L'0'
|
||||
) :
|
||||
(
|
||||
static_cast< std::int8_t >(L'A') < static_cast< std::int8_t >(L'0') ? L'A' : L'0'
|
||||
)
|
||||
);
|
||||
static constexpr std::uint8_t char_code1_sub = char_code1 == static_cast< std::uint8_t >(L'0') ?
|
||||
static_cast< std::uint8_t >(L'0') : static_cast< std::uint8_t >(char_code1 - 10u);
|
||||
|
||||
static constexpr std::uint8_t char_code0 = static_cast< std::uint8_t >
|
||||
(
|
||||
static_cast< std::int8_t >(L'a') < static_cast< std::int8_t >(L'A') ?
|
||||
(
|
||||
static_cast< std::int8_t >(L'a') < static_cast< std::int8_t >(L'0') ? L'a' : L'0'
|
||||
) :
|
||||
(
|
||||
static_cast< std::int8_t >(L'A') < static_cast< std::int8_t >(L'0') ? L'A' : L'0'
|
||||
)
|
||||
);
|
||||
static constexpr std::uint8_t char_code0_sub = char_code0 == static_cast< std::uint8_t >(L'0') ?
|
||||
static_cast< std::uint8_t >(L'0') : static_cast< std::uint8_t >(char_code0 - 10u);
|
||||
|
||||
static constexpr std::uint32_t char_code_sub =
|
||||
(static_cast< std::uint32_t >(char_code0_sub) << 16u) | (static_cast< std::uint32_t >(char_code1_sub) << 8u) | char_code2_sub;
|
||||
|
||||
static const simd_vector128< std::uint8_t > mm_char_code2_cmp;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code1_cmp;
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
static const simd_vector128< std::uint8_t > mm_char_code2_sub;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code1_sub;
|
||||
static const simd_vector128< std::uint8_t > mm_char_code0_sub;
|
||||
#endif // defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
};
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_expected_dashes =
|
||||
{{
|
||||
static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00,
|
||||
0x00, 0x00, static_cast< std::uint8_t >(L'-'), 0x00, 0x00, 0x00, 0x00, static_cast< std::uint8_t >(L'-')
|
||||
}};
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code2_cmp =
|
||||
{{
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u),
|
||||
static_cast< std::uint8_t >(char_code2 - 1u), static_cast< std::uint8_t >(char_code2 - 1u)
|
||||
}};
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code1_cmp =
|
||||
{{
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u),
|
||||
static_cast< std::uint8_t >(char_code1 - 1u), static_cast< std::uint8_t >(char_code1 - 1u)
|
||||
}};
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code2_sub =
|
||||
{{
|
||||
char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub,
|
||||
char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub, char_code2_sub
|
||||
}};
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code1_sub =
|
||||
{{
|
||||
char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub,
|
||||
char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub, char_code1_sub
|
||||
}};
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_code0_sub =
|
||||
{{
|
||||
char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub,
|
||||
char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub, char_code0_sub
|
||||
}};
|
||||
|
||||
#endif // defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
|
||||
|
||||
template< typename >
|
||||
struct from_chars_simd_constants
|
||||
{
|
||||
static const simd_vector128< std::uint8_t > mm_dashes_mask;
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX10_1) && defined(BOOST_UUID_FROM_CHARS_X86_USE_VPERMI2B)
|
||||
static const simd_vector128< std::uint8_t > mm_split_half_bytes_pattern1;
|
||||
static const simd_vector128< std::uint8_t > mm_split_half_bytes_pattern2;
|
||||
#else
|
||||
static const simd_vector128< std::uint8_t > mm_split_half_bytes_pattern1;
|
||||
static const simd_vector128< std::uint8_t > mm_split_half_bytes_pattern2;
|
||||
static const simd_vector128< std::uint8_t > mm_split_half_bytes_pattern3;
|
||||
static const simd_vector128< std::uint8_t > mm_split_half_bytes_blend_mask;
|
||||
#endif
|
||||
|
||||
static const simd_vector128< std::uint8_t > mm_F0;
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX) && !defined(BOOST_UUID_USE_AVX512_V1)
|
||||
static const simd_vector128< std::uint8_t > mm_2;
|
||||
#endif
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_dashes_mask =
|
||||
{{ 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF }};
|
||||
#if defined(BOOST_UUID_USE_AVX10_1) && defined(BOOST_UUID_FROM_CHARS_X86_USE_VPERMI2B)
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_split_half_bytes_pattern1 =
|
||||
{{ 0x01, 0x03, 0x05, 0x07, 0x0A, 0x0C, 0x0F, 0x11, 0x00, 0x02, 0x04, 0x06, 0x09, 0x0B, 0x0E, 0x10 }};
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_split_half_bytes_pattern2 =
|
||||
{{ 0x04, 0x06, 0x09, 0x0B, 0x0D, 0x0F, 0x11, 0x13, 0x03, 0x05, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12 }};
|
||||
#else
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_split_half_bytes_pattern1 =
|
||||
{{ 0x01, 0x03, 0x05, 0x07, 0x0A, 0x0C, 0x0F, 0x80, 0x00, 0x02, 0x04, 0x06, 0x09, 0x0B, 0x0E, 0x80 }};
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_split_half_bytes_pattern2 =
|
||||
{{ 0x04, 0x06, 0x09, 0x0B, 0x0D, 0x0F, 0x80, 0x01, 0x03, 0x05, 0x08, 0x0A, 0x0C, 0x0E, 0x80, 0x00 }};
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_split_half_bytes_pattern3 =
|
||||
{{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0x03, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x02 }};
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_split_half_bytes_blend_mask =
|
||||
{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }};
|
||||
#endif
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_F0 =
|
||||
{{ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 }};
|
||||
#if defined(BOOST_UUID_USE_AVX) && !defined(BOOST_UUID_USE_AVX512_V1)
|
||||
template< typename T >
|
||||
const simd_vector128< std::uint8_t > from_chars_simd_constants< T >::mm_2 =
|
||||
{{ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
|
||||
#pragma GCC diagnostic push
|
||||
// array subscript N is outside array bounds of '<array>'
|
||||
// In the partial loads below, masked loads may be used with pointers beyond the input array of characters.
|
||||
// In all such instances, the actual loads are prevented by the generated masks, don't generate
|
||||
// hardware faults and therefore are safe.
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
|
||||
template< typename Char, unsigned int Size = sizeof(Char) >
|
||||
struct from_chars_simd_load_traits;
|
||||
|
||||
template< typename Char >
|
||||
struct from_chars_simd_load_traits< Char, 1u >
|
||||
{
|
||||
static BOOST_FORCEINLINE __m128i load_packed_16(const Char* p) noexcept
|
||||
{
|
||||
return _mm_loadu_si128(reinterpret_cast< const __m128i* >(p));
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE __m128i load_packed_4(const Char* p) noexcept
|
||||
{
|
||||
return _mm_cvtsi32_si128(detail::load_native_u32(p));
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE __m128i load_packed_n(const Char* p, unsigned int n) noexcept
|
||||
{
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
return _mm_maskz_loadu_epi8(_cvtu32_mask16((static_cast< std::uint32_t >(1u) << n) - 1u), p);
|
||||
#else
|
||||
std::uint32_t chars = 0u;
|
||||
p += n;
|
||||
if ((n & 1u) != 0u)
|
||||
{
|
||||
p -= 1;
|
||||
chars = *reinterpret_cast< BOOST_MAY_ALIAS std::uint8_t const* >(p);
|
||||
}
|
||||
|
||||
if ((n & 2u) != 0u)
|
||||
{
|
||||
p -= 2;
|
||||
chars = (chars << 16u) | static_cast< std::uint32_t >(detail::load_native_u16(p));
|
||||
}
|
||||
|
||||
__m128i mm_chars = _mm_cvtsi32_si128(chars);
|
||||
if ((n & 4u) != 0u)
|
||||
{
|
||||
p -= 4;
|
||||
mm_chars = _mm_unpacklo_epi32(_mm_cvtsi32_si128(detail::load_native_u32(p)), mm_chars);
|
||||
}
|
||||
|
||||
if ((n & 8u) != 0u)
|
||||
{
|
||||
p -= 8;
|
||||
mm_chars = _mm_unpacklo_epi64(_mm_loadl_epi64(reinterpret_cast< const __m128i* >(p)), mm_chars);
|
||||
}
|
||||
|
||||
return mm_chars;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Char >
|
||||
struct from_chars_simd_load_traits< Char, 2u >
|
||||
{
|
||||
static BOOST_FORCEINLINE __m128i load_packed_16(const Char* p) noexcept
|
||||
{
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
return _mm256_cvtusepi16_epi8(_mm256_loadu_si256(reinterpret_cast< const __m256i* >(p)));
|
||||
#else
|
||||
return _mm_packus_epi16(_mm_loadu_si128(reinterpret_cast< const __m128i* >(p)), _mm_loadu_si128(reinterpret_cast< const __m128i* >(p + 8)));
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE __m128i load_packed_4(const Char* p) noexcept
|
||||
{
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
return _mm_cvtusepi16_epi8(_mm_loadl_epi64(reinterpret_cast< const __m128i* >(p)));
|
||||
#else
|
||||
return _mm_packus_epi16(_mm_loadl_epi64(reinterpret_cast< const __m128i* >(p)), _mm_setzero_si128());
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE __m128i load_packed_n(const Char* p, unsigned int n) noexcept
|
||||
{
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
return _mm256_cvtusepi16_epi8(_mm256_maskz_loadu_epi16(_cvtu32_mask16((static_cast< std::uint32_t >(1u) << n) - 1u), p));
|
||||
#else
|
||||
__m128i mm_chars1 = _mm_setzero_si128();
|
||||
__m128i mm_chars2 = _mm_setzero_si128();
|
||||
p += n;
|
||||
if ((n & 1u) != 0u)
|
||||
{
|
||||
p -= 1;
|
||||
mm_chars1 = _mm_cvtsi32_si128(detail::load_native_u16(p));
|
||||
}
|
||||
|
||||
if ((n & 2u) != 0u)
|
||||
{
|
||||
p -= 2;
|
||||
mm_chars1 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(detail::load_native_u32(p)), mm_chars1);
|
||||
}
|
||||
|
||||
if ((n & 4u) != 0u)
|
||||
{
|
||||
p -= 4;
|
||||
mm_chars1 = _mm_unpacklo_epi64(_mm_loadl_epi64(reinterpret_cast< const __m128i* >(p)), mm_chars1);
|
||||
}
|
||||
|
||||
if ((n & 8u) != 0u)
|
||||
{
|
||||
p -= 8;
|
||||
mm_chars2 = mm_chars1;
|
||||
mm_chars1 = _mm_loadu_si128(reinterpret_cast< const __m128i* >(p));
|
||||
}
|
||||
|
||||
return _mm_packus_epi16(mm_chars1, mm_chars2);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Char >
|
||||
struct from_chars_simd_load_traits< Char, 4u >
|
||||
{
|
||||
static BOOST_FORCEINLINE __m128i load_packed_16(const Char* p) noexcept
|
||||
{
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
#if defined(BOOST_UUID_TO_FROM_CHARS_X86_USE_ZMM)
|
||||
// Slower than the 256-bit version below on Intel Golden Cove.
|
||||
return _mm512_cvtusepi32_epi8(_mm512_loadu_epi32(p));
|
||||
#else // defined(BOOST_UUID_TO_FROM_CHARS_X86_USE_ZMM)
|
||||
__m128i mm1 = _mm256_cvtusepi32_epi8(_mm256_loadu_si256(reinterpret_cast< const __m256i* >(p)));
|
||||
__m128i mm2 = _mm256_cvtusepi32_epi8(_mm256_loadu_si256(reinterpret_cast< const __m256i* >(p + 8)));
|
||||
return _mm_unpacklo_epi64(mm1, mm2);
|
||||
#endif // defined(BOOST_UUID_TO_FROM_CHARS_X86_USE_ZMM)
|
||||
#else
|
||||
__m128i mm1 = _mm_packus_epi32(_mm_loadu_si128(reinterpret_cast< const __m128i* >(p)), _mm_loadu_si128(reinterpret_cast< const __m128i* >(p + 4)));
|
||||
__m128i mm2 = _mm_packus_epi32(_mm_loadu_si128(reinterpret_cast< const __m128i* >(p + 8)), _mm_loadu_si128(reinterpret_cast< const __m128i* >(p + 12)));
|
||||
return _mm_packus_epi16(mm1, mm2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE __m128i load_packed_4(const Char* p) noexcept
|
||||
{
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
return _mm_cvtusepi32_epi8(_mm_loadu_si128(reinterpret_cast< const __m128i* >(p)));
|
||||
#else
|
||||
__m128i mm1 = _mm_loadu_si128(reinterpret_cast< const __m128i* >(p));
|
||||
__m128i mm2 = _mm_setzero_si128();
|
||||
return _mm_packus_epi16(_mm_packus_epi32(mm1, mm2), mm2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE __m128i load_packed_n(const Char* p, unsigned int n) noexcept
|
||||
{
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
const std::uint32_t mask = (static_cast< std::uint32_t >(1u) << n) - 1u;
|
||||
#if defined(BOOST_UUID_TO_FROM_CHARS_X86_USE_ZMM)
|
||||
// Slower than the 256-bit version below on Intel Golden Cove.
|
||||
return _mm512_cvtusepi32_epi8(_mm512_maskz_loadu_epi32(_cvtu32_mask16(mask), p));
|
||||
#else // defined(BOOST_UUID_TO_FROM_CHARS_X86_USE_ZMM)
|
||||
__m128i mm1 = _mm256_cvtusepi32_epi8(_mm256_maskz_loadu_epi32(_cvtu32_mask8(mask & 0xFF), p));
|
||||
__m128i mm2 = _mm256_cvtusepi32_epi8(_mm256_maskz_loadu_epi32(_cvtu32_mask8(mask >> 8u), p + 8));
|
||||
return _mm_unpacklo_epi64(mm1, mm2);
|
||||
#endif // defined(BOOST_UUID_TO_FROM_CHARS_X86_USE_ZMM)
|
||||
#else
|
||||
__m128i mm_chars1 = _mm_setzero_si128();
|
||||
__m128i mm_chars2 = _mm_setzero_si128();
|
||||
__m128i mm_chars3 = _mm_setzero_si128();
|
||||
__m128i mm_chars4 = _mm_setzero_si128();
|
||||
p += n;
|
||||
if ((n & 1u) != 0u)
|
||||
{
|
||||
p -= 1;
|
||||
mm_chars1 = _mm_cvtsi32_si128(detail::load_native_u32(p));
|
||||
}
|
||||
|
||||
if ((n & 2u) != 0u)
|
||||
{
|
||||
p -= 2;
|
||||
mm_chars1 = _mm_unpacklo_epi64(_mm_loadl_epi64(reinterpret_cast< const __m128i* >(p)), mm_chars1);
|
||||
}
|
||||
|
||||
if ((n & 4u) != 0u)
|
||||
{
|
||||
p -= 4;
|
||||
mm_chars2 = mm_chars1;
|
||||
mm_chars1 = _mm_loadu_si128(reinterpret_cast< const __m128i* >(p));
|
||||
}
|
||||
|
||||
if ((n & 8u) != 0u)
|
||||
{
|
||||
p -= 8;
|
||||
mm_chars4 = mm_chars3;
|
||||
mm_chars3 = mm_chars2;
|
||||
mm_chars1 = _mm_loadu_si128(reinterpret_cast< const __m128i* >(p));
|
||||
mm_chars2 = _mm_loadu_si128(reinterpret_cast< const __m128i* >(p + 4));
|
||||
}
|
||||
mm_chars1 = _mm_packus_epi32(mm_chars1, mm_chars2);
|
||||
mm_chars3 = _mm_packus_epi32(mm_chars3, mm_chars4);
|
||||
return _mm_packus_epi16(mm_chars1, mm_chars3);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Converts a string of 36 hexadecimal UUID characters in `mm_charsN` (with the last 4 characters in the lowest 32 bits of `mm_chars3`)
|
||||
* to a 16-byte binary value and, if successful, stores it into `data`. If not successful, stores the failure character position
|
||||
* to `end_pos` and error code to `ec`.
|
||||
*/
|
||||
BOOST_FORCEINLINE void from_chars_simd_core
|
||||
(
|
||||
__m128i mm_chars1, __m128i mm_chars2, __m128i mm_chars3,
|
||||
__m128i const& mm_expected_dashes,
|
||||
__m128i const& mm_char_code1_cmp,
|
||||
__m128i const& mm_char_code2_cmp,
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
__m128i const& mm_char_code0_sub,
|
||||
__m128i const& mm_char_code1_sub,
|
||||
__m128i const& mm_char_code2_sub,
|
||||
#else
|
||||
std::uint32_t char_code_sub,
|
||||
#endif
|
||||
std::uint8_t* data, unsigned int& end_pos, from_chars_error& ec
|
||||
)
|
||||
{
|
||||
using constants = uuids::detail::from_chars_simd_constants< void >;
|
||||
|
||||
// mm_chars1 mm_chars2 mm_chars3
|
||||
// |01234567-89ab-cd|ef-0123-456789ab|cdefXXXXXXXXXXXX|
|
||||
//
|
||||
// Check if dashes are in the expected positions
|
||||
{
|
||||
// mm_dashes
|
||||
// |-89ab-cdef-0123-|
|
||||
__m128i mm_dashes = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(mm_chars1), _mm_castsi128_pd(mm_chars2), _MM_SHUFFLE2(0, 1)));
|
||||
if (BOOST_UNLIKELY(!_mm_test_all_zeros(_mm_xor_si128(mm_dashes, mm_expected_dashes), constants::mm_dashes_mask)))
|
||||
{
|
||||
// Some of the dashes are missing
|
||||
mm_dashes = _mm_and_si128(mm_dashes, constants::mm_dashes_mask);
|
||||
std::uint32_t dash_mask = _mm_movemask_epi8(_mm_cmpeq_epi8(mm_dashes, mm_expected_dashes));
|
||||
unsigned int pos = detail::countr_zero_nz(~dash_mask) + 8u;
|
||||
if (pos < end_pos)
|
||||
{
|
||||
end_pos = pos;
|
||||
ec = from_chars_error::dash_expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the dashes, deinterleave low and high half-byte digit characters
|
||||
#if defined(BOOST_UUID_USE_AVX10_1) && defined(BOOST_UUID_FROM_CHARS_X86_USE_VPERMI2B)
|
||||
// Note: This code path is disabled by default, unless BOOST_UUID_FROM_CHARS_X86_USE_VPERMI2B is defined, because vpermi2b/vpermt2b
|
||||
// instructions are slow on Intel Golden Cove and older microarchitectures, making the alternative version below faster.
|
||||
// This code path may still be beneficial on AMD CPUs or when Intel optimizes vpermi2b/vpermt2b.
|
||||
// mm_chars1: |02468ace13579bdf|
|
||||
// mm_chars2: |02468ace13579bdf|
|
||||
mm_chars1 = _mm_permutex2var_epi8(mm_chars1, constants::mm_split_half_bytes_pattern1, mm_chars2);
|
||||
mm_chars2 = _mm_permutex2var_epi8(mm_chars2, constants::mm_split_half_bytes_pattern2, mm_chars3);
|
||||
#else
|
||||
// mm_chars1: |02468acZ13579bdZ|
|
||||
// mm_chars2: |02468aZe13579bZf|
|
||||
// mm_chars3: |ZZZZZZceZZZZZZdf|
|
||||
mm_chars1 = _mm_shuffle_epi8(mm_chars1, constants::mm_split_half_bytes_pattern1);
|
||||
mm_chars2 = _mm_shuffle_epi8(mm_chars2, constants::mm_split_half_bytes_pattern2);
|
||||
mm_chars3 = _mm_shuffle_epi8(mm_chars3, constants::mm_split_half_bytes_pattern3);
|
||||
|
||||
// mm_chars1: |02468ace13579bdf|
|
||||
// mm_chars2: |02468ace13579bdf|
|
||||
// Avoid using vpblendvb, which is slow on Intel
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
mm_chars1 = _mm_ternarylogic_epi64(mm_chars1, mm_chars2, constants::mm_split_half_bytes_blend_mask, 0xD8); // (_MM_TERNLOG_A & ~_MM_TERNLOG_C) | (_MM_TERNLOG_B & _MM_TERNLOG_C)
|
||||
#elif defined(BOOST_UUID_USE_AVX)
|
||||
mm_chars1 = _mm_or_si128(mm_chars1, _mm_and_si128(mm_chars2, constants::mm_split_half_bytes_blend_mask));
|
||||
#else
|
||||
mm_chars1 = _mm_blendv_epi8(mm_chars1, mm_chars2, constants::mm_split_half_bytes_blend_mask);
|
||||
#endif
|
||||
mm_chars2 = _mm_blend_epi16(mm_chars2, mm_chars3, 0x88);
|
||||
#endif
|
||||
|
||||
// Group half-byte digits
|
||||
__m128i mm_lo = _mm_unpacklo_epi64(mm_chars1, mm_chars2);
|
||||
__m128i mm_hi = _mm_unpackhi_epi64(mm_chars1, mm_chars2);
|
||||
|
||||
// Convert characters to 8-bit integers. The algorithm is basically as follows:
|
||||
//
|
||||
// - Order the '0'-'9', 'A'-'F' and 'a'-'f' groups of characters in the order of increasing their character code values. From them, pick the two with
|
||||
// the highest character codes. E.g. in ASCII, that would be 'A'-'F' and 'a'-'f'. This is handled at compile time in from_chars_simd_char_constants.
|
||||
// - Let mm_char_code2_cmp be a vector of the smallest character code of the second picked group minus 1 (i.e. 'a' - 1), and mm_char_code1_cmp - that
|
||||
// of the first picked group ('A' - 1).
|
||||
// - Compare the input hex characters for being greater than mm_char_code2_cmp and mm_char_code1_cmp. This gives the masks where the input contains
|
||||
// hexadecimal characters of the two greatest character groups, with the mask for mm_char_code1_cmp always including the one for mm_char_code2_cmp.
|
||||
// Call those masks mm_char_code1_mask and mm_char_code2_mask.
|
||||
// - For each of the three groups of characters, have a corresponding vector of subtrahends, such that when it is subtracted from the input character codes,
|
||||
// the characters in the group are mapped onto the corresponding value in the range 0-15. I.e. these would be '0', 'A' + 10 and 'a' + 10. Those are called
|
||||
// mm_char_code0_sub, mm_char_code1_sub and mm_char_code2_sub, corresponding to the ordered list of groups of characters.
|
||||
// - Combine the subtrahends such that for elements where mm_char_code2_mask is non-zero, mm_char_code2_sub is used, otherwise where
|
||||
// mm_char_code1_mask is non-zero, mm_char_code1_sub is used, otherwise mm_char_code0_sub is used.
|
||||
// - Subtract the combined subtrahends from the input character codes.
|
||||
//
|
||||
// The result will be a vector of bytes, where the values 0-15 correspond the hexadecimal characters on input.
|
||||
//
|
||||
// Note that there is one caveat due to the fact that there are only signed byte comparisons until AVX-512. This is a problem if the character encoding has
|
||||
// hexadecimal character codes with the highest bit set to 1. This is handled in from_chars_simd_char_constants by constructing mm_char_code1 and
|
||||
// mm_char_code2 in such a way that signed comparisons work as described. We also use signed comparisons in AVX-512 to reuse the same constants.
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
__mmask16 k_char_code2_mask_lo = _mm_cmpgt_epi8_mask(mm_lo, mm_char_code2_cmp);
|
||||
__mmask16 k_char_code2_mask_hi = _mm_cmpgt_epi8_mask(mm_hi, mm_char_code2_cmp);
|
||||
|
||||
__mmask16 k_char_code1_mask_lo = _mm_cmpgt_epi8_mask(mm_lo, mm_char_code1_cmp);
|
||||
__mmask16 k_char_code1_mask_hi = _mm_cmpgt_epi8_mask(mm_hi, mm_char_code1_cmp);
|
||||
|
||||
__m128i mm_char_code_sub_lo = _mm_mask_blend_epi8(k_char_code2_mask_lo, mm_char_code1_sub, mm_char_code2_sub);
|
||||
__m128i mm_char_code_sub_hi = _mm_mask_blend_epi8(k_char_code2_mask_hi, mm_char_code1_sub, mm_char_code2_sub);
|
||||
|
||||
mm_char_code_sub_lo = _mm_mask_blend_epi8(k_char_code1_mask_lo, mm_char_code0_sub, mm_char_code_sub_lo);
|
||||
mm_char_code_sub_hi = _mm_mask_blend_epi8(k_char_code1_mask_hi, mm_char_code0_sub, mm_char_code_sub_hi);
|
||||
#elif defined(BOOST_UUID_USE_AVX)
|
||||
// Unlike the legacy SSE4.1 pblendvb instruction, the VEX-coded vpblendvb is slow on Intel. Use a different approach:
|
||||
// - Each vpcmpgtb produces a mask, where 0 indicates false and -1 - true.
|
||||
// - mm_char_code1_mask_* always overlaps with the corresponding mm_char_code2_mask_*, which means adding them
|
||||
// produces a vector where 0 means none of the vpcmpgtb matched the value, -1 - where mm_char_code1_mask_* matched
|
||||
// and -2 - where mm_char_code2_mask_* matched.
|
||||
// - Shift that mask to the positive range by adding 2.
|
||||
// - Use it as a pattern for vpshufb to place one of the 3 lowest bytes in char_code_sub to the positions corresponding
|
||||
// to the matched characters. This will be the mm_char_code_sub_* subtrahends.
|
||||
__m128i mm_char_code2_mask_lo = _mm_cmpgt_epi8(mm_lo, mm_char_code2_cmp);
|
||||
__m128i mm_char_code2_mask_hi = _mm_cmpgt_epi8(mm_hi, mm_char_code2_cmp);
|
||||
|
||||
__m128i mm_char_code1_mask_lo = _mm_cmpgt_epi8(mm_lo, mm_char_code1_cmp);
|
||||
__m128i mm_char_code1_mask_hi = _mm_cmpgt_epi8(mm_hi, mm_char_code1_cmp);
|
||||
|
||||
__m128i mm_char_code_pattern_lo = _mm_add_epi8(mm_char_code1_mask_lo, mm_char_code2_mask_lo);
|
||||
__m128i mm_char_code_pattern_hi = _mm_add_epi8(mm_char_code1_mask_hi, mm_char_code2_mask_hi);
|
||||
|
||||
mm_char_code_pattern_lo = _mm_add_epi8(mm_char_code_pattern_lo, constants::mm_2);
|
||||
mm_char_code_pattern_hi = _mm_add_epi8(mm_char_code_pattern_hi, constants::mm_2);
|
||||
|
||||
const __m128i mm_char_code_sub = _mm_cvtsi32_si128(char_code_sub);
|
||||
__m128i mm_char_code_sub_lo = _mm_shuffle_epi8(mm_char_code_sub, mm_char_code_pattern_lo);
|
||||
__m128i mm_char_code_sub_hi = _mm_shuffle_epi8(mm_char_code_sub, mm_char_code_pattern_hi);
|
||||
#else
|
||||
__m128i mm_char_code2_mask_lo = _mm_cmpgt_epi8(mm_lo, mm_char_code2_cmp);
|
||||
__m128i mm_char_code2_mask_hi = _mm_cmpgt_epi8(mm_hi, mm_char_code2_cmp);
|
||||
|
||||
__m128i mm_char_code1_mask_lo = _mm_cmpgt_epi8(mm_lo, mm_char_code1_cmp);
|
||||
__m128i mm_char_code1_mask_hi = _mm_cmpgt_epi8(mm_hi, mm_char_code1_cmp);
|
||||
|
||||
__m128i mm_char_code_sub_lo = _mm_blendv_epi8(mm_char_code1_sub, mm_char_code2_sub, mm_char_code2_mask_lo);
|
||||
__m128i mm_char_code_sub_hi = _mm_blendv_epi8(mm_char_code1_sub, mm_char_code2_sub, mm_char_code2_mask_hi);
|
||||
|
||||
mm_char_code_sub_lo = _mm_blendv_epi8(mm_char_code0_sub, mm_char_code_sub_lo, mm_char_code1_mask_lo);
|
||||
mm_char_code_sub_hi = _mm_blendv_epi8(mm_char_code0_sub, mm_char_code_sub_hi, mm_char_code1_mask_hi);
|
||||
#endif
|
||||
|
||||
mm_lo = _mm_sub_epi8(mm_lo, mm_char_code_sub_lo);
|
||||
mm_hi = _mm_sub_epi8(mm_hi, mm_char_code_sub_hi);
|
||||
|
||||
// Check hexadecimal character validity. Proper hexadecimal characters always convert to values of 0-15 and any other characters convert
|
||||
// to values outside that range. Which means if the upper 4 bits of a resulting integer are non-zero then the corresponding character was invalid.
|
||||
if (BOOST_LIKELY(_mm_test_all_zeros(_mm_or_si128(mm_lo, mm_hi), constants::mm_F0)))
|
||||
{
|
||||
if (BOOST_LIKELY(ec == from_chars_error::none))
|
||||
{
|
||||
__m128i mm = _mm_or_si128(mm_lo, _mm_slli_epi32(mm_hi, 4));
|
||||
_mm_storeu_si128(reinterpret_cast< __m128i* >(data), mm);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some of the hex digits are invalid
|
||||
const __m128i mm_0 = _mm_setzero_si128();
|
||||
__m128i mm_hi_bits_lo = _mm_and_si128(mm_lo, constants::mm_F0);
|
||||
__m128i mm_hi_bits_hi = _mm_and_si128(mm_hi, constants::mm_F0);
|
||||
mm_hi_bits_lo = _mm_cmpeq_epi8(mm_hi_bits_lo, mm_0);
|
||||
mm_hi_bits_hi = _mm_cmpeq_epi8(mm_hi_bits_hi, mm_0);
|
||||
|
||||
std::uint32_t digits_mask_lo = _mm_movemask_epi8(mm_hi_bits_lo);
|
||||
std::uint32_t digits_mask_hi = _mm_movemask_epi8(mm_hi_bits_hi);
|
||||
|
||||
unsigned int pos_lo = detail::countr_zero_nz(~digits_mask_lo) * 2u + 1u;
|
||||
unsigned int pos_hi = detail::countr_zero_nz(~digits_mask_hi) * 2u;
|
||||
unsigned int pos = pos_lo < pos_hi ? pos_lo : pos_hi;
|
||||
if (pos >= 8u)
|
||||
{
|
||||
unsigned int dash_count = (pos - 4u) / 4u;
|
||||
if (dash_count > 4u)
|
||||
dash_count = 4u;
|
||||
pos += dash_count;
|
||||
}
|
||||
|
||||
if (pos < end_pos)
|
||||
{
|
||||
end_pos = pos;
|
||||
ec = from_chars_error::hex_digit_expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Char >
|
||||
BOOST_FORCEINLINE from_chars_result< Char > from_chars_simd(const Char* begin, const Char* end, uuid& u) noexcept
|
||||
{
|
||||
static_assert(sizeof(Char) == 1u || sizeof(Char) == 2u || sizeof(Char) == 4u, "Boost.UUID: Unsupported output character type for from_chars");
|
||||
|
||||
using char_constants = uuids::detail::from_chars_simd_char_constants< Char >;
|
||||
|
||||
unsigned int end_pos = 36u;
|
||||
from_chars_error ec = from_chars_error::none;
|
||||
__m128i mm_chars1, mm_chars2, mm_chars3;
|
||||
if (BOOST_LIKELY((end - begin) >= 36))
|
||||
{
|
||||
mm_chars1 = from_chars_simd_load_traits< Char >::load_packed_16(begin);
|
||||
mm_chars2 = from_chars_simd_load_traits< Char >::load_packed_16(begin + 16);
|
||||
mm_chars3 = from_chars_simd_load_traits< Char >::load_packed_4(begin + 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
end_pos = static_cast< unsigned int >(end - begin);
|
||||
ec = from_chars_error::unexpected_end_of_input;
|
||||
|
||||
const Char* p = begin;
|
||||
unsigned int n = static_cast< unsigned int >(end - begin);
|
||||
if (n >= 16u)
|
||||
{
|
||||
mm_chars1 = from_chars_simd_load_traits< Char >::load_packed_16(p);
|
||||
p += 16;
|
||||
n -= 16u;
|
||||
}
|
||||
else
|
||||
{
|
||||
mm_chars1 = from_chars_simd_load_traits< Char >::load_packed_n(p, n);
|
||||
p += n;
|
||||
n = 0u;
|
||||
}
|
||||
|
||||
if (n >= 16u)
|
||||
{
|
||||
mm_chars2 = from_chars_simd_load_traits< Char >::load_packed_16(p);
|
||||
p += 16;
|
||||
n -= 16u;
|
||||
}
|
||||
else
|
||||
{
|
||||
mm_chars2 = from_chars_simd_load_traits< Char >::load_packed_n(p, n);
|
||||
p += n;
|
||||
n = 0u;
|
||||
}
|
||||
|
||||
mm_chars3 = from_chars_simd_load_traits< Char >::load_packed_n(p, n);
|
||||
}
|
||||
|
||||
from_chars_simd_core
|
||||
(
|
||||
mm_chars1, mm_chars2, mm_chars3,
|
||||
char_constants::mm_expected_dashes,
|
||||
char_constants::mm_char_code1_cmp,
|
||||
char_constants::mm_char_code2_cmp,
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) || !defined(BOOST_UUID_USE_AVX)
|
||||
char_constants::mm_char_code0_sub,
|
||||
char_constants::mm_char_code1_sub,
|
||||
char_constants::mm_char_code2_sub,
|
||||
#else
|
||||
char_constants::char_code_sub,
|
||||
#endif
|
||||
u.data(), end_pos, ec
|
||||
);
|
||||
|
||||
return { begin + end_pos, ec };
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace uuids
|
||||
} // namespace boost
|
||||
|
||||
#endif // defined(BOOST_UUID_USE_SSE41)
|
||||
|
||||
#endif // BOOST_UUID_DETAIL_FROM_CHARS_X86_HPP_INCLUDED
|
||||
49
include/boost/uuid/detail/simd_vector.hpp
Normal file
49
include/boost/uuid/detail/simd_vector.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef BOOST_UUID_DETAIL_SIMD_VECTOR_HPP_INCLUDED
|
||||
#define BOOST_UUID_DETAIL_SIMD_VECTOR_HPP_INCLUDED
|
||||
|
||||
// Copyright 2025 Andrey Semashev
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
namespace detail {
|
||||
|
||||
//! A helper to define vector constants
|
||||
template< typename T, unsigned int ByteSize >
|
||||
union simd_vector
|
||||
{
|
||||
static_assert(((ByteSize - 1u) & ByteSize) == 0u, "Boost.UUID: ByteSize must be a power of two in simd_vector");
|
||||
|
||||
BOOST_MAY_ALIAS T elements[ByteSize / sizeof(T)];
|
||||
alignas(ByteSize) unsigned char bytes[ByteSize];
|
||||
|
||||
template<
|
||||
typename Vector,
|
||||
typename = typename std::enable_if< sizeof(Vector) <= ByteSize >::type
|
||||
>
|
||||
BOOST_FORCEINLINE operator Vector () const noexcept { return get< Vector >(); }
|
||||
|
||||
template< typename Vector >
|
||||
BOOST_FORCEINLINE typename std::enable_if< sizeof(Vector) <= ByteSize, Vector >::type get() const noexcept
|
||||
{
|
||||
using vector_type = typename std::remove_cv< typename std::remove_reference< Vector >::type >::type;
|
||||
return *reinterpret_cast< const vector_type* >(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
using simd_vector128 = simd_vector< T, 16u >;
|
||||
template< typename T >
|
||||
using simd_vector256 = simd_vector< T, 32u >;
|
||||
template< typename T >
|
||||
using simd_vector512 = simd_vector< T, 64u >;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace uuids
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UUID_DETAIL_SIMD_VECTOR_HPP_INCLUDED
|
||||
@@ -5,7 +5,7 @@
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/uuid/detail/from_chars.hpp>
|
||||
#include <boost/uuid/detail/from_chars_result.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/detail/endian.hpp>
|
||||
#include <boost/uuid/detail/simd_vector.hpp>
|
||||
|
||||
#if defined(BOOST_UUID_REPORT_IMPLEMENTATION)
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX10_1)
|
||||
BOOST_PRAGMA_MESSAGE( "Using to_chars_x86.hpp, AVX10.1" )
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
BOOST_PRAGMA_MESSAGE( "Using to_chars_x86.hpp, AVX512v1" )
|
||||
|
||||
#elif defined(BOOST_UUID_USE_AVX2)
|
||||
BOOST_PRAGMA_MESSAGE( "Using to_chars_x86.hpp, AVX2" )
|
||||
@@ -49,16 +51,16 @@ template<
|
||||
>
|
||||
struct to_chars_simd_char_constants
|
||||
{
|
||||
alignas(16) static const std::uint8_t mm_char_table[16];
|
||||
alignas(16) static const std::uint8_t mm_char_dash[16];
|
||||
static const simd_vector128< std::uint8_t > mm_char_table;
|
||||
static const simd_vector128< std::uint8_t > mm_char_dash;
|
||||
};
|
||||
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
alignas(16) const std::uint8_t to_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_table[16] =
|
||||
{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 }; // 0123456789abcdef in ASCII
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_table =
|
||||
{{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 }}; // 0123456789abcdef in ASCII
|
||||
template< typename Char, bool IsCharASCIICompatible, bool IsWCharASCIICompatible >
|
||||
alignas(16) const std::uint8_t to_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_dash[16] =
|
||||
{ 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D }; // ---------------- in ASCII
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_char_constants< Char, IsCharASCIICompatible, IsWCharASCIICompatible >::mm_char_dash =
|
||||
{{ 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D }}; // ---------------- in ASCII
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
struct to_chars_simd_char_constants< char, false, IsWCharASCIICompatible >
|
||||
@@ -67,26 +69,26 @@ struct to_chars_simd_char_constants< char, false, IsWCharASCIICompatible >
|
||||
static_assert(static_cast< std::uint8_t >('-') < static_cast< std::uint8_t >('0') && static_cast< std::uint8_t >('-') < static_cast< std::uint8_t >('a'),
|
||||
"Boost.UUID: Unsupported char encoding, '-' character code is expected to be less than any hexadecimal characters");
|
||||
|
||||
alignas(16) static const std::uint8_t mm_char_table[16];
|
||||
alignas(16) static const std::uint8_t mm_char_dash[16];
|
||||
static const simd_vector128< std::uint8_t > mm_char_table;
|
||||
static const simd_vector128< std::uint8_t > mm_char_dash;
|
||||
};
|
||||
|
||||
template< bool IsWCharASCIICompatible >
|
||||
alignas(16) const std::uint8_t to_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_table[16] =
|
||||
{
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_table =
|
||||
{{
|
||||
static_cast< std::uint8_t >('0'), static_cast< std::uint8_t >('1'), static_cast< std::uint8_t >('2'), static_cast< std::uint8_t >('3'),
|
||||
static_cast< std::uint8_t >('4'), static_cast< std::uint8_t >('5'), static_cast< std::uint8_t >('6'), static_cast< std::uint8_t >('7'),
|
||||
static_cast< std::uint8_t >('8'), static_cast< std::uint8_t >('9'), static_cast< std::uint8_t >('a'), static_cast< std::uint8_t >('b'),
|
||||
static_cast< std::uint8_t >('c'), static_cast< std::uint8_t >('d'), static_cast< std::uint8_t >('e'), static_cast< std::uint8_t >('f')
|
||||
};
|
||||
}};
|
||||
template< bool IsWCharASCIICompatible >
|
||||
alignas(16) const std::uint8_t to_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_dash[16] =
|
||||
{
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_char_constants< char, false, IsWCharASCIICompatible >::mm_char_dash =
|
||||
{{
|
||||
static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'),
|
||||
static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'),
|
||||
static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'),
|
||||
static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-'), static_cast< std::uint8_t >('-')
|
||||
};
|
||||
}};
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
struct to_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >
|
||||
@@ -100,44 +102,44 @@ struct to_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >
|
||||
static_assert(static_cast< std::uint8_t >(L'-') < static_cast< std::uint8_t >(L'0') && static_cast< std::uint8_t >(L'-') < static_cast< std::uint8_t >(L'a'),
|
||||
"Boost.UUID: Unsupported wchar_t encoding, L'-' character code is expected to be less than any hexadecimal characters");
|
||||
|
||||
alignas(16) static const std::uint8_t mm_char_table[16];
|
||||
alignas(16) static const std::uint8_t mm_char_dash[16];
|
||||
static const simd_vector128< std::uint8_t > mm_char_table;
|
||||
static const simd_vector128< std::uint8_t > mm_char_dash;
|
||||
};
|
||||
|
||||
template< bool IsCharASCIICompatible >
|
||||
alignas(16) const std::uint8_t to_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_table[16] =
|
||||
{
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_table =
|
||||
{{
|
||||
static_cast< std::uint8_t >(L'0'), static_cast< std::uint8_t >(L'1'), static_cast< std::uint8_t >(L'2'), static_cast< std::uint8_t >(L'3'),
|
||||
static_cast< std::uint8_t >(L'4'), static_cast< std::uint8_t >(L'5'), static_cast< std::uint8_t >(L'6'), static_cast< std::uint8_t >(L'7'),
|
||||
static_cast< std::uint8_t >(L'8'), static_cast< std::uint8_t >(L'9'), static_cast< std::uint8_t >(L'a'), static_cast< std::uint8_t >(L'b'),
|
||||
static_cast< std::uint8_t >(L'c'), static_cast< std::uint8_t >(L'd'), static_cast< std::uint8_t >(L'e'), static_cast< std::uint8_t >(L'f')
|
||||
};
|
||||
}};
|
||||
template< bool IsCharASCIICompatible >
|
||||
alignas(16) const std::uint8_t to_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_dash[16] =
|
||||
{
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_char_constants< wchar_t, IsCharASCIICompatible, false >::mm_char_dash =
|
||||
{{
|
||||
static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'),
|
||||
static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'),
|
||||
static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'),
|
||||
static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-'), static_cast< std::uint8_t >(L'-')
|
||||
};
|
||||
}};
|
||||
|
||||
template< typename >
|
||||
struct to_chars_simd_constants
|
||||
{
|
||||
alignas(16) static const std::uint8_t mm_15[16];
|
||||
alignas(16) static const std::uint8_t mm_shuffle_pattern1[16];
|
||||
alignas(16) static const std::uint8_t mm_shuffle_pattern2[16];
|
||||
static const simd_vector128< std::uint8_t > mm_0F;
|
||||
static const simd_vector128< std::uint8_t > mm_shuffle_pattern1;
|
||||
static const simd_vector128< std::uint8_t > mm_shuffle_pattern2;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
alignas(16) const std::uint8_t to_chars_simd_constants< T >::mm_15[16] =
|
||||
{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F };
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_constants< T >::mm_0F =
|
||||
{{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }};
|
||||
template< typename T >
|
||||
alignas(16) const std::uint8_t to_chars_simd_constants< T >::mm_shuffle_pattern1[16] =
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x80, 0x08, 0x09, 0x0A, 0x0B, 0x80, 0x0C, 0x0D };
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_constants< T >::mm_shuffle_pattern1 =
|
||||
{{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x80, 0x08, 0x09, 0x0A, 0x0B, 0x80, 0x0C, 0x0D }};
|
||||
template< typename T >
|
||||
alignas(16) const std::uint8_t to_chars_simd_constants< T >::mm_shuffle_pattern2[16] =
|
||||
{ 0x00, 0x01, 0x80, 0x02, 0x03, 0x04, 0x05, 0x80, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D };
|
||||
const simd_vector128< std::uint8_t > to_chars_simd_constants< T >::mm_shuffle_pattern2 =
|
||||
{{ 0x00, 0x01, 0x80, 0x02, 0x03, 0x04, 0x05, 0x80, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D }};
|
||||
|
||||
//! Converts UUID to a string of 36 characters, where first 32 craracters are returned in mm_chars1 and mm_chars2 and the last 4 in the highest 32 bits of mm_chars3
|
||||
BOOST_FORCEINLINE void to_chars_simd_core
|
||||
@@ -147,15 +149,14 @@ BOOST_FORCEINLINE void to_chars_simd_core
|
||||
__m128i& mm_chars1, __m128i& mm_chars2, __m128i& mm_chars3
|
||||
) noexcept
|
||||
{
|
||||
__m128i const& mm_15 = *reinterpret_cast< const __m128i* >(uuids::detail::to_chars_simd_constants< void >::mm_15);
|
||||
__m128i const& mm_shuffle_pattern1 = *reinterpret_cast< const __m128i* >(uuids::detail::to_chars_simd_constants< void >::mm_shuffle_pattern1);
|
||||
__m128i const& mm_shuffle_pattern2 = *reinterpret_cast< const __m128i* >(uuids::detail::to_chars_simd_constants< void >::mm_shuffle_pattern2);
|
||||
using constants = uuids::detail::to_chars_simd_constants< void >;
|
||||
|
||||
__m128i mm_input = uuids::detail::load_unaligned_si128(data);
|
||||
__m128i mm_input = _mm_loadu_si128(reinterpret_cast< const __m128i* >(data));
|
||||
|
||||
// Split half-bytes
|
||||
__m128i mm_input_hi = _mm_and_si128(_mm_srli_epi32(mm_input, 4), mm_15);
|
||||
__m128i mm_input_lo = _mm_and_si128(mm_input, mm_15);
|
||||
__m128i const& mm_0F = constants::mm_0F;
|
||||
__m128i mm_input_hi = _mm_and_si128(_mm_srli_epi32(mm_input, 4), mm_0F);
|
||||
__m128i mm_input_lo = _mm_and_si128(mm_input, mm_0F);
|
||||
|
||||
// Stringize each of the halves
|
||||
mm_input_hi = _mm_shuffle_epi8(mm_char_table, mm_input_hi);
|
||||
@@ -171,23 +172,31 @@ BOOST_FORCEINLINE void to_chars_simd_core
|
||||
// |01234567-89ab-cd|ef-0123-456789ab|
|
||||
//
|
||||
// Note that the last "cdef" characters are already available at the end of mm_2
|
||||
mm_chars1 = _mm_shuffle_epi8(mm_1, mm_shuffle_pattern1);
|
||||
mm_chars2 = _mm_shuffle_epi8(_mm_alignr_epi8(mm_2, mm_1, 14), mm_shuffle_pattern2);
|
||||
mm_chars1 = _mm_shuffle_epi8(mm_1, constants::mm_shuffle_pattern1);
|
||||
mm_chars2 = _mm_shuffle_epi8(_mm_alignr_epi8(mm_2, mm_1, 14), constants::mm_shuffle_pattern2);
|
||||
|
||||
mm_chars1 = _mm_max_epu8(mm_chars1, mm_char_dash);
|
||||
mm_chars2 = _mm_max_epu8(mm_chars2, mm_char_dash);
|
||||
mm_chars3 = mm_2;
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
// conditional expression is constant
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
|
||||
template< typename Char >
|
||||
BOOST_FORCEINLINE Char* to_chars_simd(uuid const& u, Char* out) noexcept
|
||||
{
|
||||
using char_constants = uuids::detail::to_chars_simd_char_constants< Char >;
|
||||
|
||||
__m128i mm_chars1, mm_chars2, mm_chars3;
|
||||
uuids::detail::to_chars_simd_core
|
||||
(
|
||||
u.data,
|
||||
*reinterpret_cast< const __m128i* >(uuids::detail::to_chars_simd_char_constants< Char >::mm_char_table),
|
||||
*reinterpret_cast< const __m128i* >(uuids::detail::to_chars_simd_char_constants< Char >::mm_char_dash),
|
||||
u.data(),
|
||||
char_constants::mm_char_table,
|
||||
char_constants::mm_char_dash,
|
||||
mm_chars1, mm_chars2, mm_chars3
|
||||
);
|
||||
|
||||
@@ -197,9 +206,9 @@ BOOST_FORCEINLINE Char* to_chars_simd(uuid const& u, Char* out) noexcept
|
||||
_mm_storeu_si128(reinterpret_cast< __m128i* >(out), mm_chars1);
|
||||
_mm_storeu_si128(reinterpret_cast< __m128i* >(out + 16), mm_chars2);
|
||||
#if defined(BOOST_UUID_USE_SSE41)
|
||||
*reinterpret_cast< BOOST_MAY_ALIAS std::uint32_t* >(out + 32) = _mm_extract_epi32(mm_chars3, 3);
|
||||
detail::store_native_u32(out + 32, _mm_extract_epi32(mm_chars3, 3));
|
||||
#else
|
||||
*reinterpret_cast< BOOST_MAY_ALIAS std::uint32_t* >(out + 32) = _mm_cvtsi128_si32(_mm_srli_si128(mm_chars3, 12));
|
||||
detail::store_native_u32(out + 32, _mm_cvtsi128_si32(_mm_srli_si128(mm_chars3, 12)));
|
||||
#endif
|
||||
}
|
||||
else BOOST_IF_CONSTEXPR (sizeof(Char) == 2u)
|
||||
@@ -215,7 +224,7 @@ BOOST_FORCEINLINE Char* to_chars_simd(uuid const& u, Char* out) noexcept
|
||||
_mm_storeu_si128(reinterpret_cast< __m128i* >(out + 24), _mm_unpackhi_epi8(mm_chars2, mm_0));
|
||||
#endif
|
||||
#if defined(BOOST_UUID_USE_SSE41) && (defined(__x86_64__) || defined(_M_X64))
|
||||
*reinterpret_cast< BOOST_MAY_ALIAS std::uint64_t* >(out + 32) = _mm_extract_epi64(_mm_unpackhi_epi8(mm_chars3, mm_0), 1);
|
||||
detail::store_native_u64(out + 32, _mm_extract_epi64(_mm_unpackhi_epi8(mm_chars3, mm_0), 1));
|
||||
#else
|
||||
_mm_storeh_pd(reinterpret_cast< BOOST_MAY_ALIAS double* >(out + 32), _mm_castsi128_pd(_mm_unpackhi_epi8(mm_chars3, mm_0)));
|
||||
#endif
|
||||
@@ -223,7 +232,7 @@ BOOST_FORCEINLINE Char* to_chars_simd(uuid const& u, Char* out) noexcept
|
||||
else
|
||||
{
|
||||
const __m128i mm_0 = _mm_setzero_si128();
|
||||
#if 0 && defined(BOOST_UUID_USE_AVX10_1)
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1) && defined(BOOST_UUID_TO_FROM_CHARS_X86_USE_ZMM)
|
||||
// Slower than the AVX2 version below on Intel Golden Cove. Perhaps, it will become beneficial on newer microarchitectures.
|
||||
_mm512_storeu_epi32(out, _mm512_cvtepu8_epi32(mm_chars1));
|
||||
_mm512_storeu_epi32(out + 16, _mm512_cvtepu8_epi32(mm_chars2));
|
||||
@@ -252,6 +261,10 @@ BOOST_FORCEINLINE Char* to_chars_simd(uuid const& u, Char* out) noexcept
|
||||
return out + 36;
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace uuids
|
||||
} // namespace boost
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
#if defined(BOOST_UUID_REPORT_IMPLEMENTATION)
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX10_1)
|
||||
BOOST_PRAGMA_MESSAGE( "Using uuid_x86.ipp, AVX10.1" )
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
BOOST_PRAGMA_MESSAGE( "Using uuid_x86.ipp, AVX512v1" )
|
||||
|
||||
#elif defined(BOOST_UUID_USE_SSE41)
|
||||
BOOST_PRAGMA_MESSAGE( "Using uuid_x86.ipp, SSE4.1" )
|
||||
@@ -38,7 +38,7 @@ BOOST_PRAGMA_MESSAGE( "Using uuid_x86.ipp, SSE2" )
|
||||
#endif // #if defined(BOOST_UUID_REPORT_IMPLEMENTATION)
|
||||
|
||||
// MSVC does not always have immintrin.h (at least, not up to MSVC 10), so include the appropriate header for each instruction set
|
||||
#if defined(BOOST_UUID_USE_AVX10_1)
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
#include <immintrin.h>
|
||||
#elif defined(BOOST_UUID_USE_SSE41)
|
||||
#include <smmintrin.h>
|
||||
@@ -52,15 +52,10 @@ namespace boost {
|
||||
namespace uuids {
|
||||
namespace detail {
|
||||
|
||||
BOOST_FORCEINLINE __m128i load_unaligned_si128(const std::uint8_t* p) noexcept
|
||||
{
|
||||
return _mm_loadu_si128(reinterpret_cast< const __m128i* >(p));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE void compare(uuid const& lhs, uuid const& rhs, std::uint32_t& cmp, std::uint32_t& rcmp) noexcept
|
||||
{
|
||||
__m128i mm_left = uuids::detail::load_unaligned_si128(lhs.data);
|
||||
__m128i mm_right = uuids::detail::load_unaligned_si128(rhs.data);
|
||||
__m128i mm_left = _mm_loadu_si128(reinterpret_cast< const __m128i* >(lhs.data()));
|
||||
__m128i mm_right = _mm_loadu_si128(reinterpret_cast< const __m128i* >(rhs.data()));
|
||||
|
||||
// To emulate lexicographical_compare behavior we have to perform two comparisons - the forward and reverse one.
|
||||
// Then we know which bytes are equivalent and which ones are different, and for those different the comparison results
|
||||
@@ -77,7 +72,7 @@ BOOST_FORCEINLINE void compare(uuid const& lhs, uuid const& rhs, std::uint32_t&
|
||||
// with another XOR to the comparison results.
|
||||
// 3. Until AVX-512, there is only pcmpgtb instruction that compares for "greater" relation, so we swap the arguments to get what we need.
|
||||
|
||||
#if defined(BOOST_UUID_USE_AVX10_1)
|
||||
#if defined(BOOST_UUID_USE_AVX512_V1)
|
||||
|
||||
__mmask16 k_cmp = _mm_cmplt_epu8_mask(mm_left, mm_right);
|
||||
__mmask16 k_rcmp = _mm_cmplt_epu8_mask(mm_right, mm_left);
|
||||
@@ -85,7 +80,7 @@ BOOST_FORCEINLINE void compare(uuid const& lhs, uuid const& rhs, std::uint32_t&
|
||||
cmp = static_cast< std::uint32_t >(_cvtmask16_u32(k_cmp));
|
||||
rcmp = static_cast< std::uint32_t >(_cvtmask16_u32(k_rcmp));
|
||||
|
||||
#else // defined(BOOST_UUID_USE_AVX10_1)
|
||||
#else // defined(BOOST_UUID_USE_AVX512_V1)
|
||||
|
||||
const __m128i mm_signs_mask = _mm_xor_si128(mm_left, mm_right);
|
||||
|
||||
@@ -97,7 +92,7 @@ BOOST_FORCEINLINE void compare(uuid const& lhs, uuid const& rhs, std::uint32_t&
|
||||
cmp = static_cast< std::uint32_t >(_mm_movemask_epi8(mm_cmp));
|
||||
rcmp = static_cast< std::uint32_t >(_mm_movemask_epi8(mm_rcmp));
|
||||
|
||||
#endif // defined(BOOST_UUID_USE_AVX10_1)
|
||||
#endif // defined(BOOST_UUID_USE_AVX512_V1)
|
||||
|
||||
cmp = (cmp - 1u) ^ cmp;
|
||||
rcmp = (rcmp - 1u) ^ rcmp;
|
||||
@@ -113,8 +108,8 @@ BOOST_UUID_CXX14_CONSTEXPR_RT inline bool operator== (uuid const& lhs, uuid cons
|
||||
}
|
||||
else
|
||||
{
|
||||
__m128i mm_left = uuids::detail::load_unaligned_si128(lhs.data);
|
||||
__m128i mm_right = uuids::detail::load_unaligned_si128(rhs.data);
|
||||
__m128i mm_left = _mm_loadu_si128(reinterpret_cast< const __m128i* >(lhs.data()));
|
||||
__m128i mm_right = _mm_loadu_si128(reinterpret_cast< const __m128i* >(rhs.data()));
|
||||
|
||||
#if defined(BOOST_UUID_USE_SSE41)
|
||||
__m128i mm = _mm_xor_si128(mm_left, mm_right);
|
||||
|
||||
@@ -33,11 +33,17 @@ boost_test(TYPE run SOURCES test_io.cpp LINK_LIBRARIES Boost::lexical_cast Boost
|
||||
boost_test(TYPE run SOURCES test_io.cpp LINK_LIBRARIES Boost::lexical_cast Boost::predef COMPILE_DEFINITIONS BOOST_UUID_NO_SIMD=1 BOOST_UUID_REPORT_IMPLEMENTATION=1 NAME test_io_no_simd)
|
||||
boost_test(TYPE run SOURCES test_io_2.cpp COMPILE_DEFINITIONS BOOST_UUID_REPORT_IMPLEMENTATION=1)
|
||||
boost_test(TYPE run SOURCES test_io_2.cpp COMPILE_DEFINITIONS BOOST_UUID_NO_SIMD=1 BOOST_UUID_REPORT_IMPLEMENTATION=1 NAME test_io_2_no_simd)
|
||||
|
||||
boost_test(TYPE run SOURCES test_to_chars.cpp COMPILE_DEFINITIONS BOOST_UUID_REPORT_IMPLEMENTATION=1)
|
||||
boost_test(TYPE run SOURCES test_to_chars.cpp COMPILE_DEFINITIONS BOOST_UUID_NO_SIMD=1 BOOST_UUID_REPORT_IMPLEMENTATION=1 NAME test_to_chars_no_simd)
|
||||
boost_test(TYPE run SOURCES test_to_chars_2.cpp COMPILE_DEFINITIONS BOOST_UUID_REPORT_IMPLEMENTATION=1)
|
||||
boost_test(TYPE run SOURCES test_to_chars_2.cpp COMPILE_DEFINITIONS BOOST_UUID_NO_SIMD=1 BOOST_UUID_REPORT_IMPLEMENTATION=1 NAME test_to_chars_2_no_simd)
|
||||
|
||||
boost_test(TYPE run SOURCES test_from_chars.cpp COMPILE_DEFINITIONS BOOST_UUID_REPORT_IMPLEMENTATION=1)
|
||||
boost_test(TYPE run SOURCES test_from_chars.cpp COMPILE_DEFINITIONS BOOST_UUID_NO_SIMD=1 BOOST_UUID_REPORT_IMPLEMENTATION=1 NAME test_from_chars_no_simd)
|
||||
boost_test(TYPE run SOURCES test_from_chars_2.cpp COMPILE_DEFINITIONS BOOST_UUID_REPORT_IMPLEMENTATION=1)
|
||||
boost_test(TYPE run SOURCES test_from_chars_2.cpp COMPILE_DEFINITIONS BOOST_UUID_NO_SIMD=1 BOOST_UUID_REPORT_IMPLEMENTATION=1 NAME test_from_chars_2_no_simd)
|
||||
|
||||
boost_test(TYPE run SOURCES test_uuid_clock.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES test_nil_generator.cpp)
|
||||
@@ -91,4 +97,9 @@ boost_test(TYPE compile SOURCES test_uuid_cx.cpp)
|
||||
boost_test(TYPE run SOURCES test_string_generator_cx.cpp)
|
||||
boost_test(TYPE run SOURCES test_constants_cx.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES test_to_chars_cx.cpp LINK_LIBRARIES Boost::array)
|
||||
|
||||
boost_test(TYPE run SOURCES test_from_chars_cx.cpp)
|
||||
boost_test(TYPE run SOURCES test_from_chars_cx2.cpp)
|
||||
|
||||
boost_test(TYPE run SOURCES quick.cpp)
|
||||
|
||||
@@ -100,8 +100,10 @@ run test_to_chars.cpp : : : <define>BOOST_UUID_NO_SIMD <define>BOOST_UUID_REPORT
|
||||
run test_to_chars_2.cpp : : : <define>BOOST_UUID_REPORT_IMPLEMENTATION ;
|
||||
run test_to_chars_2.cpp : : : <define>BOOST_UUID_NO_SIMD <define>BOOST_UUID_REPORT_IMPLEMENTATION : test_to_chars_2_no_simd ;
|
||||
|
||||
run test_from_chars.cpp ;
|
||||
run test_from_chars_2.cpp ;
|
||||
run test_from_chars.cpp : : : <define>BOOST_UUID_REPORT_IMPLEMENTATION ;
|
||||
run test_from_chars.cpp : : : <define>BOOST_UUID_NO_SIMD <define>BOOST_UUID_REPORT_IMPLEMENTATION : test_from_chars_no_simd ;
|
||||
run test_from_chars_2.cpp : : : <define>BOOST_UUID_REPORT_IMPLEMENTATION ;
|
||||
run test_from_chars_2.cpp : : : <define>BOOST_UUID_NO_SIMD <define>BOOST_UUID_REPORT_IMPLEMENTATION : test_from_chars_2_no_simd ;
|
||||
|
||||
# test uuid_clock
|
||||
|
||||
|
||||
@@ -33,6 +33,30 @@ int main()
|
||||
test( U"", 0, from_chars_error::unexpected_end_of_input );
|
||||
test( u8"", 0, from_chars_error::unexpected_end_of_input );
|
||||
|
||||
test( "0", 1, from_chars_error::unexpected_end_of_input );
|
||||
test( L"0", 1, from_chars_error::unexpected_end_of_input );
|
||||
test( u"0", 1, from_chars_error::unexpected_end_of_input );
|
||||
test( U"0", 1, from_chars_error::unexpected_end_of_input );
|
||||
test( u8"0", 1, from_chars_error::unexpected_end_of_input );
|
||||
|
||||
test( "01", 2, from_chars_error::unexpected_end_of_input );
|
||||
test( L"01", 2, from_chars_error::unexpected_end_of_input );
|
||||
test( u"01", 2, from_chars_error::unexpected_end_of_input );
|
||||
test( U"01", 2, from_chars_error::unexpected_end_of_input );
|
||||
test( u8"01", 2, from_chars_error::unexpected_end_of_input );
|
||||
|
||||
test( "01234567-89aB-cDeF-0123-456789AbCd", 34, from_chars_error::unexpected_end_of_input );
|
||||
test( L"01234567-89aB-cDeF-0123-456789AbCd", 34, from_chars_error::unexpected_end_of_input );
|
||||
test( u"01234567-89aB-cDeF-0123-456789AbCd", 34, from_chars_error::unexpected_end_of_input );
|
||||
test( U"01234567-89aB-cDeF-0123-456789AbCd", 34, from_chars_error::unexpected_end_of_input );
|
||||
test( u8"01234567-89aB-cDeF-0123-456789AbCd", 34, from_chars_error::unexpected_end_of_input );
|
||||
|
||||
test( "01234567-89aB-cDeF-0123-456789AbCdE", 35, from_chars_error::unexpected_end_of_input );
|
||||
test( L"01234567-89aB-cDeF-0123-456789AbCdE", 35, from_chars_error::unexpected_end_of_input );
|
||||
test( u"01234567-89aB-cDeF-0123-456789AbCdE", 35, from_chars_error::unexpected_end_of_input );
|
||||
test( U"01234567-89aB-cDeF-0123-456789AbCdE", 35, from_chars_error::unexpected_end_of_input );
|
||||
test( u8"01234567-89aB-cDeF-0123-456789AbCdE", 35, from_chars_error::unexpected_end_of_input );
|
||||
|
||||
test( "@", 0, from_chars_error::hex_digit_expected );
|
||||
test( L"@", 0, from_chars_error::hex_digit_expected );
|
||||
test( u"@", 0, from_chars_error::hex_digit_expected );
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
using namespace boost::uuids;
|
||||
|
||||
template<class Ch, std::size_t N>
|
||||
BOOST_CXX14_CONSTEXPR uuid uuid_from_string( Ch const (&str)[ N ] )
|
||||
BOOST_UUID_CXX14_CONSTEXPR_RT uuid uuid_from_string( Ch const (&str)[ N ] )
|
||||
{
|
||||
Ch const* first = str;
|
||||
Ch const* last = first + N - 1;
|
||||
@@ -22,7 +22,7 @@ BOOST_CXX14_CONSTEXPR uuid uuid_from_string( Ch const (&str)[ N ] )
|
||||
return u;
|
||||
}
|
||||
|
||||
#define TEST(str) { BOOST_CXX14_CONSTEXPR auto u = uuid_from_string(str); BOOST_TEST_EQ(u, expected); }
|
||||
#define TEST(str) { BOOST_UUID_CXX14_CONSTEXPR_RT auto u = uuid_from_string(str); BOOST_TEST_EQ(u, expected); }
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ struct test_result
|
||||
};
|
||||
|
||||
template<class Ch, std::size_t N>
|
||||
BOOST_CXX14_CONSTEXPR test_result test( Ch const (&str)[ N ] )
|
||||
BOOST_UUID_CXX14_CONSTEXPR_RT test_result test( Ch const (&str)[ N ] )
|
||||
{
|
||||
Ch const* first = str;
|
||||
Ch const* last = first + N - 1;
|
||||
@@ -28,7 +28,7 @@ BOOST_CXX14_CONSTEXPR test_result test( Ch const (&str)[ N ] )
|
||||
return { r.ptr - first, r.ec };
|
||||
}
|
||||
|
||||
#define TEST(Str, Pos, Ec) { BOOST_CXX14_CONSTEXPR auto r = test(Str); BOOST_TEST_EQ(Pos, r.pos); BOOST_TEST_EQ(static_cast<int>(Ec), static_cast<int>(r.ec)); }
|
||||
#define TEST(Str, Pos, Ec) { BOOST_UUID_CXX14_CONSTEXPR_RT auto r = test(Str); BOOST_TEST_EQ(Pos, r.pos); BOOST_TEST_EQ(static_cast<int>(Ec), static_cast<int>(r.ec)); }
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user