36 namespace json_details {
37 struct location_info_t {
38 daw::string_view name;
39 char const *first =
nullptr;
40 char const *last =
nullptr;
41 char const *class_first =
nullptr;
42 char const *class_last =
nullptr;
43 std::size_t counter = 0;
45 [[nodiscard]]
constexpr bool missing( )
const {
46 return first ==
nullptr;
49 template<
typename ParseState>
50 constexpr void set_range( ParseState
const &parse_state ) {
51 first = parse_state.first;
52 last = parse_state.last;
53 class_first = parse_state.class_first;
54 class_last = parse_state.class_last;
55 counter = parse_state.counter;
58 template<
typename ParseState>
59 constexpr auto get_range( )
const {
60 using range_t =
typename ParseState::without_allocator_type;
61 return range_t( first, last, class_first, class_last, counter );
69 template<std::
size_t MemberCount,
bool DoFullNameMatch = true>
70 struct locations_info_t {
71 using value_type = location_info_t;
72 using reference = value_type &;
73 using const_reference = value_type
const &;
74 static constexpr bool do_full_name_match = DoFullNameMatch;
76 value_type names[MemberCount];
78 constexpr const_reference operator[]( std::size_t idx )
const {
83 constexpr reference operator[]( std::size_t idx ) {
88 static constexpr std::size_t size( ) {
92 template<
bool expect_
long_
strings, std::
size_t start_pos>
93 [[nodiscard]] DAW_ATTRIB_INLINE
constexpr std::size_t
94 find_name( daw::string_view key )
const {
95 auto const hash = name_hash<expect_long_strings>( key );
96#if defined( DAW_JSON_BUGFIX_MSVC_EVAL_ORDER_002 )
98 for( std::size_t n = 0; n < MemberCount; ++n ) {
100 for( std::size_t n = start_pos; n < MemberCount; ++n ) {
102 if( hashes[n] == hash and names[n].name.size( ) == key.size( ) ) {
103 if constexpr( do_full_name_match ) {
104 if( DAW_UNLIKELY( key != names[n].name ) ) {
116 template<
typename... MemberNames>
117 static DAW_CONSTEVAL
bool do_hashes_collide( ) {
119 name_hash<false>( MemberNames::name )... };
121 daw::sort( std::data( hashes ), daw::data_end( hashes ) );
122 return daw::algorithm::adjacent_find( std::data( hashes ),
123 daw::data_end( hashes ),
127 } ) != daw::data_end( hashes );
131 template<
typename ParseState,
typename... JsonMembers>
133 make_locations_info( ) {
134#if defined( DAW_JSON_ALWAYS_FULL_NAME_MATCH )
135 using do_full_name_match = std::true_type;
137 using do_full_name_match =
138 std::bool_constant<ParseState::force_name_equal_check or
139 do_hashes_collide<JsonMembers...>( )>;
141 return locations_info_t<
sizeof...( JsonMembers ),
142 do_full_name_match::value>{
143 { daw::name_hash<false>( JsonMembers::name )... },
144 { location_info_t{ JsonMembers::name }... } };
156 enum class AllMembersMustExist { yes, no };
158 template<std::size_t pos, AllMembersMustExist must_exist,
159 bool from_start =
false, std::size_t N,
typename ParseState,
161 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr find_result<ParseState>
162 find_class_member( ParseState &parse_state,
163 locations_info_t<N, B> &locations,
164 bool is_nullable, daw::string_view member_name ) {
172 ( not locations[pos].missing( ) ),
173 ( not parse_state.is_closing_brace_checked( ) ) ),
174 missing_member( member_name ),
177 parse_state.trim_left_unchecked( );
178 bool known = not locations[pos].missing( );
180 locations[pos].missing( ),
181 ( not parse_state.empty( ) and parse_state.front( ) !=
'}' ) ) ) {
184 auto const name = parse_name( parse_state );
185 auto const name_pos =
186 locations.template find_name<ParseState::expect_long_strings,
187 ( from_start ? 0 : pos )>( name );
188 if constexpr( must_exist == AllMembersMustExist::yes ) {
190 ErrorReason::UnknownMember,
193#if defined( DAW_JSON_PARSER_DIAGNOSTICS )
194 std::cerr <<
"DEBUG: Unknown member '" << name <<
'\n';
196 if( name_pos >= std::size( locations ) ) {
198 (void)skip_value( parse_state );
199 parse_state.move_next_member_or_end( );
203 if( name_pos == pos ) {
204 locations[pos].set_range( parse_state );
207#if defined( DAW_JSON_PARSER_DIAGNOSTICS )
208 std::cerr <<
"DEBUG: Out of order member '"
209 << locations.names[name_pos].name
210 <<
"' found, looking for '" << locations.names[pos].name
212 << std::abs(
static_cast<long long>( pos ) -
213 static_cast<long long>( name_pos ) )
214 <<
" members ahead in constructor\n";
224 locations[name_pos].set_range( skip_value( parse_state ) );
226 if constexpr( ParseState::is_unchecked_input ) {
227 if( name_pos + 1 < std::size( locations ) ) {
228 parse_state.move_next_member( );
230 parse_state.move_next_member_or_end( );
233 parse_state.move_next_member_or_end( );
237 if( locations[pos].missing( ) ) {
240 if constexpr( ParseState::has_allocator ) {
242 locations[pos].template get_range<ParseState>( ).with_allocator(
246 return find_result<ParseState>{
247 locations[pos].template get_range<ParseState>( ), known };