DAW JSON Link
daw_json_location_info.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#include "daw_murmur3.h"
12#include "version.h"
13
14#include <daw/daw_consteval.h>
15#include <daw/daw_likely.h>
16#include <daw/daw_sort_n.h>
17#include <daw/daw_string_view.h>
18#include <daw/daw_uint_buffer.h>
19
20#include <ciso646>
21#include <cstddef>
22
23#if defined( DAW_JSON_PARSER_DIAGNOSTICS )
24#include <cmath>
25#include <iostream>
26#endif
27
28namespace daw::json {
29 inline namespace DAW_JSON_VER {
30 namespace json_details {
31 template<bool FullNameMatch, typename CharT>
33 daw::string_view name;
34 CharT *first = nullptr;
35 CharT *last = nullptr;
36 CharT *class_first = nullptr;
37 CharT *class_last = nullptr;
38 std::size_t counter = 0;
39
40 [[maybe_unused, nodiscard]] inline constexpr bool missing( ) const {
41 return first == nullptr;
42 }
43
44 template<typename ParseState>
45 constexpr void set_range( ParseState const &parse_state ) {
46 first = parse_state.first;
47 last = parse_state.last;
48 class_first = parse_state.class_first;
49 class_last = parse_state.class_last;
50 counter = parse_state.counter;
51 }
52
53 template<typename ParseState>
54 constexpr auto get_range( template_param<ParseState> ) const {
55 using range_t = typename ParseState::without_allocator_type;
56 auto result = range_t( first, last, class_first, class_last );
57 result.counter = counter;
58 return result;
59 }
60 };
61
62 template<typename CharT>
63 struct location_info_t<false, CharT> {
64 CharT *first = nullptr;
65 CharT *last = nullptr;
66 CharT *class_first = nullptr;
67 CharT *class_last = nullptr;
68 std::size_t counter = 0;
69
70 [[maybe_unused, nodiscard]] inline constexpr bool missing( ) const {
71 return first == nullptr;
72 }
73
74 template<typename ParseState>
75 constexpr void set_range( ParseState const &parse_state ) {
76 first = parse_state.first;
77 last = parse_state.last;
78 class_first = parse_state.class_first;
79 class_last = parse_state.class_last;
80 counter = parse_state.counter;
81 }
82
83 template<typename ParseState>
84 constexpr auto get_range( template_param<ParseState> ) const {
85 // Not copying allocator as it may contain state that needs copying in
86 using range_t = typename ParseState::without_allocator_type;
87 auto result = range_t( first, last, class_first, class_last );
88 result.counter = counter;
89 return result;
90 }
91 };
92
93 /***
94 * Contains an array of member location_info mapped in a json_class
95 * @tparam MemberCount Number of mapped members from json_class
96 */
97 template<std::size_t MemberCount, typename CharT,
98 bool DoFullNameMatch = true>
103 static constexpr bool do_full_name_match = DoFullNameMatch;
104 daw::UInt32 hashes[MemberCount];
105 value_type names[MemberCount];
106
107 constexpr const_reference operator[]( std::size_t idx ) const {
108 daw_json_assert( idx < MemberCount, ErrorReason::NumberOutOfRange );
109 return names[idx];
110 }
111
112 constexpr reference operator[]( std::size_t idx ) {
113 daw_json_assert( idx < MemberCount, ErrorReason::NumberOutOfRange );
114 return names[idx];
115 }
116
117 static constexpr std::size_t size( ) {
118 return MemberCount;
119 }
120
121 template<bool expect_long_strings, std::size_t start_pos>
122 DAW_ATTRIB_INLINE [[nodiscard]] inline constexpr std::size_t
123 find_name( daw::template_vals_t<start_pos>,
124 daw::string_view key ) const {
125 UInt32 const hash = name_hash<expect_long_strings>( key );
126#if defined( _MSC_VER ) and not defined( __clang__ )
127 // MSVC has a bug where the list initialization isn't sequenced in
128 // order of appearance.
129 (void)start_pos;
130 for( std::size_t n = 0; n < MemberCount; ++n ) {
131#else
132 for( std::size_t n = start_pos; n < MemberCount; ++n ) {
133#endif
134 if( hashes[n] == hash ) {
135 if constexpr( do_full_name_match ) {
136 if( DAW_UNLIKELY( key != names[n].name ) ) {
137 continue;
138 }
139 }
140 return n;
141 }
142 }
143 return MemberCount;
144 }
145 };
146
147 // Should never be called outside a consteval context
148 template<typename... MemberNames>
149 inline DAW_CONSTEVAL bool do_hashes_collide( ) {
150 daw::UInt32 hashes[sizeof...( MemberNames )]{
151 name_hash<false>( MemberNames::name )... };
152
153 daw::sort( std::data( hashes ), daw::data_end( hashes ) );
154 return daw::algorithm::adjacent_find( std::data( hashes ),
155 daw::data_end( hashes ),
156 []( UInt32 l, UInt32 r ) {
157 return l == r;
158 } ) != daw::data_end( hashes );
159 }
160#if defined( _MSC_VER ) and not defined( __clang__ )
161#define DAW_JSON_MAKE_LOC_INFO_CONSTEVAL constexpr
162#else
163#define DAW_JSON_MAKE_LOC_INFO_CONSTEVAL DAW_CONSTEVAL
164#endif
165 // Should never be called outside a consteval context
166 template<typename ParseState, typename... JsonMembers>
167 DAW_ATTRIB_FLATINLINE inline DAW_JSON_MAKE_LOC_INFO_CONSTEVAL auto
169 using CharT = typename ParseState::CharT;
170#if defined( DAW_JSON_PARSER_DIAGNOSTICS ) or \
171 ( defined( __MSC_VER ) and not defined( __clang__ ) )
172 constexpr bool do_full_name_match = true;
173 return locations_info_t<sizeof...( JsonMembers ), CharT,
175 { daw::name_hash<false>( JsonMembers::name )... },
177 JsonMembers::name }... } };
178#else
179 // DAW
180 constexpr bool do_full_name_match =
181 ParseState::force_name_equal_check or
182 do_hashes_collide<JsonMembers...>( );
183 if constexpr( do_full_name_match ) {
184 return locations_info_t<sizeof...( JsonMembers ), CharT,
186 { daw::name_hash<false>( JsonMembers::name )... },
188 JsonMembers::name }... } };
189 } else {
190 return locations_info_t<sizeof...( JsonMembers ), CharT,
192 { daw::name_hash<false>( JsonMembers::name )... }, {} };
193 }
194#endif
195 }
196
197 /***
198 * Get the position from already seen JSON members or move the parser
199 * forward until we reach the end of the class or the member.
200 * @tparam N Number of members in json_class
201 * @tparam ParseState see IteratorRange
202 * @param locations members location and names
203 * @param parse_state Current JSON data
204 * @return IteratorRange with begin( ) being start of value
205 */
206 enum class AllMembersMustExist { yes, no };
207 template<std::size_t pos, AllMembersMustExist must_exist,
208 bool from_start = false, std::size_t N, typename ParseState,
209 bool B, typename CharT>
210 [[nodiscard]] inline constexpr std::pair<ParseState, bool>
213 bool is_nullable, daw::string_view member_name ) {
214
215 // silencing gcc9 warning as these are selectively used
216 (void)is_nullable;
217 (void)member_name;
218
219 daw_json_assert_weak( is_nullable | ( not locations[pos].missing( ) ) |
220 ( not parse_state.is_closing_brace_checked( ) ),
221 missing_member( member_name ), parse_state );
222
223 parse_state.trim_left_unchecked( );
224 bool known = not locations[pos].missing( );
225 while( locations[pos].missing( ) & ( parse_state.front( ) != '}' ) ) {
226 // TODO: fully unescape name
227 // parse_name checks if we have more and are quotes
228 auto const name = parse_name( parse_state );
229 auto const name_pos =
230 locations.template find_name<ParseState::expect_long_strings>(
231 template_vals<( from_start ? 0 : pos )>, name );
232 if constexpr( must_exist == AllMembersMustExist::yes ) {
233 daw_json_assert_weak( name_pos < std::size( locations ),
234 ErrorReason::UnknownMember, parse_state );
235 } else {
236#if defined( DAW_JSON_PARSER_DIAGNOSTICS )
237 std::cerr << "DEBUG: Unknown member '" << name << '\n';
238#endif
239 if( name_pos >= std::size( locations ) ) {
240 // This is not a member we are concerned with
241 (void)skip_value( parse_state );
242 parse_state.move_next_member_or_end( );
243 continue;
244 }
245 }
246 if( name_pos == pos ) {
247 locations[pos].set_range( parse_state );
248 break;
249 } else {
250#if defined( DAW_JSON_PARSER_DIAGNOSTICS )
251 std::cerr << "DEBUG: Out of order member '"
252 << locations.names[name_pos].name
253 << "' found, looking for '" << locations.names[pos].name
254 << ". It is "
255 << std::abs( static_cast<long long>( pos ) -
256 static_cast<long long>( name_pos ) )
257 << " members ahead in constructor\n";
258#endif
259 // We are out of order, store position for later
260 // OLDTODO: use type knowledge to speed up skip
261 // OLDTODO: on skipped classes see if way to store
262 // member positions so that we don't have to
263 // re-parse them after
264 // RESULT: storing preparsed is slower, don't try 3 times
265 // it also limits the type of things we can parse potentially
266 // Using locations to switch on BaseType is slower too
267 locations[name_pos].set_range( skip_value( parse_state ) );
268
269 if constexpr( ParseState::is_unchecked_input ) {
270 if( name_pos + 1 < std::size( locations ) ) {
271 parse_state.move_next_member( );
272 } else {
273 parse_state.move_next_member_or_end( );
274 }
275 } else {
276 parse_state.move_next_member_or_end( );
277 }
278 }
279 }
280 if( locations[pos].missing( ) ) {
281 known = true;
282 }
283 if constexpr( ParseState::has_allocator ) {
284 return std::pair<ParseState, bool>{
285 locations[pos]
286 .get_range( template_arg<ParseState> )
287 .with_allocator( parse_state ),
288 known };
289 } else {
290 return std::pair<ParseState, bool>{
291 locations[pos].get_range( template_arg<ParseState> ), known };
292 }
293 }
294 } // namespace json_details
295 } // namespace DAW_JSON_VER
296} // namespace daw::json
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:190
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:179
#define DAW_JSON_MAKE_LOC_INFO_CONSTEVAL
Definition: daw_json_location_info.h:163
ParseState & parse_state
Definition: daw_json_parse_class.h:182
constexpr DAW_ATTRIB_FLATTEN daw::string_view parse_name(ParseState &parse_state)
Definition: daw_json_parse_name.h:128
DAW_ATTRIB_FLATINLINE DAW_JSON_MAKE_LOC_INFO_CONSTEVAL auto make_locations_info()
Definition: daw_json_location_info.h:168
constexpr ParseState skip_value(ParseState &parse_state)
Definition: daw_json_skip.h:304
DAW_CONSTEVAL bool do_hashes_collide()
Definition: daw_json_location_info.h:149
constexpr std::pair< ParseState, bool > find_class_member(ParseState &parse_state, locations_info_t< N, CharT, B > &locations, bool is_nullable, daw::string_view member_name)
Definition: daw_json_location_info.h:211
AllMembersMustExist
Definition: daw_json_location_info.h:206
Definition: daw_from_json.h:22
constexpr bool missing() const
Definition: daw_json_location_info.h:70
constexpr void set_range(ParseState const &parse_state)
Definition: daw_json_location_info.h:75
constexpr auto get_range(template_param< ParseState >) const
Definition: daw_json_location_info.h:84
Definition: daw_json_location_info.h:32
constexpr auto get_range(template_param< ParseState >) const
Definition: daw_json_location_info.h:54
constexpr void set_range(ParseState const &parse_state)
Definition: daw_json_location_info.h:45
std::size_t counter
Definition: daw_json_location_info.h:38
constexpr bool missing() const
Definition: daw_json_location_info.h:40
CharT * class_last
Definition: daw_json_location_info.h:37
CharT * first
Definition: daw_json_location_info.h:34
CharT * class_first
Definition: daw_json_location_info.h:36
daw::string_view name
Definition: daw_json_location_info.h:33
CharT * last
Definition: daw_json_location_info.h:35
Definition: daw_json_location_info.h:99
value_type names[MemberCount]
Definition: daw_json_location_info.h:105
constexpr reference operator[](std::size_t idx)
Definition: daw_json_location_info.h:112
static constexpr std::size_t size()
Definition: daw_json_location_info.h:117
static constexpr bool do_full_name_match
Definition: daw_json_location_info.h:103
value_type const & const_reference
Definition: daw_json_location_info.h:102
daw::UInt32 hashes[MemberCount]
Definition: daw_json_location_info.h:104
constexpr DAW_ATTRIB_INLINE std::size_t find_name(daw::template_vals_t< start_pos >, daw::string_view key) const
Definition: daw_json_location_info.h:123
constexpr const_reference operator[](std::size_t idx) const
Definition: daw_json_location_info.h:107
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16