DAW JSON Link
Loading...
Searching...
No Matches
daw_json_serialize_string_simd.h
Go to the documentation of this file.
1// Copyright (c) Darrell Wright
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// Official repository: https://github.com/beached/daw_json_link
7//
8
9#pragma once
10
12
14
15#include <daw/daw_cpp_feature_check.h>
16#include <daw/daw_span.h>
17
18#if defined( DAW_HAS_MSVC_LIKE )
19#include <intrin.h>
20#endif
21
22#include <cstddef>
23#include <cstdint>
24
25#if defined( DAW_JSON_HAS_SIMD )
26
27#define DAW_JSON_HAS_SERIALIZE_STRING_SIMD 1
28
29namespace daw::json {
30 inline namespace DAW_JSON_VER {
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" );
37
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 ) )
43 unsigned long index;
44 _BitScanForward64( &index, value );
45 return static_cast<std::size_t>( index );
46#else
47 auto result = std::size_t{ 0 };
48 while( ( value & 1U ) == 0 ) {
49 value >>= 1U;
50 ++result;
51 }
52 return result;
53#endif
54 }
55
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 ) {
63 auto const block =
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( );
71 }
72
77 class escape_scanner {
78 std::uintptr_t m_first;
79 std::uintptr_t m_last;
80 std::uintptr_t m_block;
81 std::uint64_t m_mask;
82
83 public:
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 ) ) {}
90
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 );
98 }
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 );
104 }
105 m_mask = escape_mask( m_block, m_first, m_last );
106 }
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 );
110 }
111 return pos + ( hit_addr - pos_addr );
112 }
113 };
114
117 [[nodiscard]] inline char const *find_next_escape( char const *first,
118 char const *last ) {
119 return escape_scanner( first, last ).next( first );
120 }
121 } // namespace json_details::serialize_string_simd
122 } // namespace DAW_JSON_VER
123} // namespace daw::json
124
125
126#endif
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.
Definition version.h:20