15#include <daw/daw_cpp_feature_check.h>
16#include <daw/daw_span.h>
18#if defined( DAW_HAS_MSVC_LIKE )
25#if defined( DAW_JSON_HAS_SIMD )
27#define DAW_JSON_HAS_SERIALIZE_STRING_SIMD 1
31 namespace json_details::serialize_string_simd {
32 using byte_simd_t = daw::simd::vec<unsigned char>;
33 inline constexpr std::size_t block_size = byte_simd_t::size( );
34 static_assert( block_size <= 64 and
35 ( block_size & ( block_size - 1U ) ) == 0,
36 "Block size must be a power of two no larger than 64" );
39 [[nodiscard]]
inline std::size_t lowest_set_bit( std::uint64_t value ) {
40#if DAW_HAS_BUILTIN( __builtin_ctzll )
41 return static_cast<std::size_t
>( __builtin_ctzll( value ) );
42#elif defined( DAW_HAS_MSVC_LIKE ) and ( defined( _M_X64 ) or defined( _M_ARM64 ) )
44 _BitScanForward64( &index, value );
45 return static_cast<std::size_t
>( index );
47 auto result = std::size_t{ 0 };
48 while( ( value & 1U ) == 0 ) {
60 [[nodiscard]]
inline std::uint64_t
61 escape_mask( std::uintptr_t block_addr,
62 std::uintptr_t first_addr, std::uintptr_t last_addr ) {
64 load_aligned_block<byte_simd_t>( block_addr, first_addr, last_addr );
65 auto const needs_escape =
66 ( block == byte_simd_t(
static_cast<unsigned char>(
'"' ) ) ) |
67 ( block == byte_simd_t(
static_cast<unsigned char>(
'\\' ) ) ) |
68 ( block <= byte_simd_t(
static_cast<unsigned char>( 0x1FU ) ) ) |
69 ( block >= byte_simd_t(
static_cast<unsigned char>( 0x80U ) ) );
70 return needs_escape.to_ullong( );
77 class escape_scanner {
78 std::uintptr_t m_first;
79 std::uintptr_t m_last;
80 std::uintptr_t m_block;
85 escape_scanner(
char const *first,
char const *last )
86 : m_first( reinterpret_cast<
std::uintptr_t>( first ) )
87 , m_last( reinterpret_cast<
std::uintptr_t>( last ) )
88 , m_block( m_first & ~
std::uintptr_t{ block_size - 1U } )
89 , m_mask( escape_mask( m_block, m_first, m_last ) ) {}
93 [[nodiscard]]
char const *next(
char const *pos ) {
94 auto const pos_addr =
reinterpret_cast<std::uintptr_t
>( pos );
95 if( pos_addr - m_block >= block_size ) {
96 m_block = pos_addr &
~std::uintptr_t{ block_size - 1U };
97 m_mask = escape_mask( m_block, m_first, m_last );
99 m_mask &=
~std::uint64_t{ 0 } << ( pos_addr - m_block );
100 while( m_mask == 0 ) {
101 m_block += block_size;
102 if( m_block >= m_last ) {
103 return reinterpret_cast<char const *
>( m_last );
105 m_mask = escape_mask( m_block, m_first, m_last );
107 auto const hit_addr = m_block + lowest_set_bit( m_mask );
108 if( hit_addr >= m_last ) {
109 return reinterpret_cast<char const *
>( m_last );
111 return pos + ( hit_addr - pos_addr );
117 [[nodiscard]]
inline char const *find_next_escape(
char const *first,
119 return escape_scanner( first, last ).next( first );
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.