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