DAW JSON Link
Loading...
Searching...
No Matches
daw_json_parse_array_sse42_iterator.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
11#if not defined( DAW_ALLOW_SSE42 )
12#error "This should not be included when SSE4.2 is not enabled"
13#endif
14
16
21
22#include <daw/daw_attributes.h>
23#include <daw/daw_not_null.h>
24
25#include <emmintrin.h>
26#include <nmmintrin.h>
27#include <smmintrin.h>
28#include <tmmintrin.h>
29#include <wmmintrin.h>
30#include <xmmintrin.h>
31#if defined( DAW_HAS_MSVC_LIKE )
32#include <intrin.h>
33#endif
34
35#include <type_traits>
36
37namespace daw::json {
38 inline namespace DAW_JSON_VER {
39 namespace json_details {
40 template<typename ParseState, bool /*KnownBounds*/>
41 struct json_parse_array_sse42_iterator_base {
42 using iterator_category = std::input_iterator_tag;
43 using difference_type = std::ptrdiff_t;
44 static constexpr bool has_counter = false;
45
46 ParseState *parse_state = nullptr;
47 };
48
49 template<typename ParseState>
50 struct json_parse_array_sse42_iterator_base<ParseState, true> {
51 using iterator_category = std::input_iterator_tag;
52 using difference_type = std::ptrdiff_t;
53 static constexpr bool has_counter = true;
54
55 daw::not_null<ParseState *> parse_state;
56 difference_type counter = 0;
57
58 explicit constexpr json_parse_array_sse42_iterator_base(
59 daw::not_null<ParseState *> pd ) noexcept
60 : parse_state( pd )
61 , counter( static_cast<difference_type>( pd->counter ) ) {}
62
63 constexpr difference_type
64 operator-( json_parse_array_sse42_iterator_base const &rhs ) const {
65 // rhs is the iterator with the parser in it. We should know how many
66 // items are in play because we already counted them in the skip_array
67 // call.
68
69 return rhs.counter;
70 }
71 };
72
73 template<typename JsonMember, typename ParseState, bool KnownBounds>
74 struct json_parse_array_sse42_iterator
75 : json_parse_array_sse42_iterator_base<
76 ParseState, can_be_random_iterator_v<KnownBounds>> {
77
78 using base = json_parse_array_sse42_iterator_base<
79 ParseState, can_be_random_iterator_v<KnownBounds>>;
80
81 using iterator_category = typename base::iterator_category;
82 using element_t = typename JsonMember::json_element_t;
83 using value_type = json_result_t<element_t>;
84 using reference = value_type;
85 using pointer = arrow_proxy<value_type>;
86 using parse_state_t = ParseState;
87 using difference_type = typename base::difference_type;
88 using size_type = std::size_t;
89
90 json_parse_array_sse42_iterator( ) = default;
91#if defined( DAW_JSON_USE_FULL_DEBUG_ITERATORS )
92 // This code requires C++ 20 to be useful in a constant expression as it
93 // requires a non-trivial destructor
94 json_parse_array_sse42_iterator(
95 json_parse_array_sse42_iterator const & ) = default;
96
97 json_parse_array_sse42_iterator &
98 operator=( json_parse_array_sse42_iterator const & ) = default;
99
100 json_parse_array_sse42_iterator( json_parse_array_sse42_iterator && ) =
101 default;
102
103 json_parse_array_sse42_iterator &
104 operator=( json_parse_array_sse42_iterator && ) = default;
105
106 DAW_JSON_CPP20_CX_DTOR ~json_parse_array_sse42_iterator( ) {
107 if constexpr( base::has_counter ) {
108 daw_json_assert_weak( base::counter == 0,
109 ErrorReason::AttemptToAccessPastEndOfValue );
110 }
111 }
112#endif
113
114 private:
115 struct masks_t {
116 std::uint32_t array_boundaries_mask = 0;
117 std::uint32_t whitespace_mask = 0;
118 };
119
120 static auto get_masks( daw::not_null<char const *> ptr ) {
121 static constexpr std::size_t sse_array_boundaries_sz = 2;
122 static auto const sse_array_boundaries = uload16_char_data_simd(
123 ( std::array<char, 16>{ ',', ']' } ).data( ) );
124 static constexpr std::size_t sse_whitespace_sz = 4;
125 static auto const sse_whitespace = uload16_char_data_simd(
126 ( std::array<char, 16>{ ' ', '\t', '\n', '\r' } ).data( ) );
127
128 auto const text_chunk = uload16_char_data_simd( ptr );
129 auto const array_boundaries_mask_reg = _mm_cmpestrm(
130 sse_array_boundaries,
131 sse_array_boundaries_sz,
132 text_chunk,
133 16,
134 _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK );
135 auto const whitespace_mask_reg = _mm_cmpestrm(
136 sse_whitespace,
137 sse_whitespace_sz,
138 text_chunk,
139 16,
140 _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK );
141
142 return masks_t{ static_cast<std::uint32_t>(
143 _mm_extract_epi16( array_boundaries_mask_reg, 0 ) ),
144 static_cast<std::uint32_t>(
145 _mm_extract_epi16( whitespace_mask_reg, 0 ) ) };
146 }
147
148 masks_t m_masks{ };
149 std::size_t m_first_offset = 0;
150
151 public:
152 explicit json_parse_array_sse42_iterator( parse_state_t &r )
153 : base{ &r } {
154 if( DAW_UNLIKELY( base::parse_state->front( ) == ']' ) ) {
155 if constexpr( not KnownBounds ) {
156 // Cleanup at end of value
157 base::parse_state->remove_prefix( );
158 base::parse_state->trim_left_checked( );
159 // Ensure we are equal to default
160 }
161 base::parse_state = nullptr;
162 }
163 // Do initial scan to build SIMD state
164 if( base::parse_state->size( ) < 16 ) {
165 return;
166 }
167 m_masks = get_mask( base::parse_state->first );
168 if( m_masks.array_boundaries_mask != 0 ) {}
169 }
170
171 [[noreturn]] DAW_ATTRIB_NOINLINE value_type operator*( ) const {
172 DAW_UNLIKELY_BRANCH
173 // This is hear to satisfy indirectly_readable
174 daw_json_error( true, ErrorReason::UnexpectedEndOfData );
175 }
176
177 DAW_ATTRIB_INLINE constexpr value_type operator*( ) {
178 daw_json_assert_weak( base::parse_state and
179 base::parse_state->has_more( ),
180 ErrorReason::UnexpectedEndOfData,
181 *base::parse_state );
182
183 return parse_value<element_t, false, element_t::expected_type>(
184 *base::parse_state );
185 }
186
187 DAW_ATTRIB_INLINE constexpr json_parse_array_sse42_iterator &
188 operator++( ) {
189 daw_json_assert_weak( base::parse_state,
190 ErrorReason::UnexpectedEndOfData,
191 *base::parse_state );
192 base::parse_state->trim_left( );
193
195 base::parse_state->has_more( ) and
196 base::parse_state->is_at_next_array_element( ),
197 ErrorReason::UnexpectedEndOfData,
198 *base::parse_state );
199
200 base::parse_state->move_next_member_or_end( );
201 daw_json_assert_weak( base::parse_state->has_more( ),
202 ErrorReason::UnexpectedEndOfData,
203 *base::parse_state );
204 if( base::parse_state->front( ) == ']' ) {
205#if not defined( NDEBUG )
206 if constexpr( base::has_counter ) {
207 daw_json_assert_weak( base::counter == 0,
208 ErrorReason::AttemptToAccessPastEndOfValue,
209 *base::parse_state );
210 }
211#endif
212 if constexpr( not KnownBounds ) {
213 // Cleanup at end of value
214 base::parse_state->remove_prefix( );
215 base::parse_state->trim_left_checked( );
216 // Ensure we are equal to default
217 }
218 base::parse_state = nullptr;
219 } else {
220#if not defined( NDEBUG )
221 if constexpr( base::has_counter ) {
222 daw_json_assert_weak( base::counter > 0,
223 ErrorReason::AttemptToAccessPastEndOfValue,
224 *base::parse_state );
225 --base::counter;
226 }
227#endif
228 }
229 return *this;
230 }
231
232 DAW_ATTRIB_INLINE constexpr void operator++( int ) {
233 (void)operator++( );
234 }
235
236 friend inline constexpr bool
237 operator==( json_parse_array_sse42_iterator const &lhs,
238 json_parse_array_sse42_iterator const &rhs ) {
239 return lhs.parse_state == rhs.parse_state;
240 }
241
242 friend inline constexpr bool
243 operator!=( json_parse_array_sse42_iterator const &lhs,
244 json_parse_array_sse42_iterator const &rhs ) {
245 return not( lhs == rhs );
246 }
247
248 constexpr json_parse_array_sse42_iterator &begin( ) {
249 return *this;
250 }
251
252 constexpr json_parse_array_sse42_iterator end( ) const {
253 return { };
254 }
255 };
256 } // namespace json_details
257 } // namespace DAW_JSON_VER
258} // namespace daw::json
#define daw_json_assert_weak(Bool,...)
Assert that Bool is true when in Checked Input mode If false pass rest of args to daw_json_error.
#define DAW_JSON_CPP20_CX_DTOR
DAW_ATTRIB_NOINLINE void daw_json_error(bool b, ErrorReason reason)
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20