DAW JSON Link
daw_json_find_path.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_json_event_parser.h"
12 #include "daw_json_link_types.h"
13 #include "impl/daw_json_assert.h"
14 #include "impl/version.h"
15 
16 #include <daw/daw_algorithm.h>
17 #include <daw/daw_move.h>
18 #include <daw/daw_utility.h>
19 #include <daw/iterator/daw_reverse_iterator.h>
20 
21 #include <algorithm>
22 #include <iterator>
23 #include <numeric>
24 #include <string>
25 #include <string_view>
26 #include <vector>
27 
28 namespace daw::json {
29  inline namespace DAW_JSON_VER {
30  class json_path_node;
31 
32  [[nodiscard]] inline std::vector<json_path_node>
33  find_json_path_stack_to( char const *parse_location,
34  char const *doc_start );
35 
37  std::string_view m_name{ };
38  char const *m_value_start = nullptr;
39  long long m_index = -1;
41 
42  friend std::vector<json_path_node>
43  find_json_path_stack_to( char const *parse_location,
44  char const *doc_start );
45 
46  constexpr json_path_node( ) = default;
47  constexpr json_path_node( JsonBaseParseTypes Type, std::string_view Name,
48  long long Index, char const *ValueStart )
49  : m_name( Name )
50  , m_value_start( ValueStart )
51  , m_index( Index )
52  , m_type( Type ) {}
53 
54  public:
56  [[nodiscard]] constexpr JsonBaseParseTypes type( ) const {
57  return m_type;
58  }
59 
61  [[nodiscard]] constexpr std::string_view name( ) const {
62  return m_name;
63  }
64 
66  [[nodiscard]] constexpr long long index( ) const {
67  return m_index;
68  }
69 
71  [[nodiscard]] constexpr char const *value_start( ) const {
72  return m_value_start;
73  }
74  };
75 
80  [[nodiscard]] inline std::string
81  to_json_path_string( std::vector<json_path_node> const &path_stack ) {
82  return daw::algorithm::accumulate(
83  std::data( path_stack ), daw::data_end( path_stack ), std::string{ },
84  []( auto &&state, json_path_node const &sv ) mutable {
85  if( sv.index( ) >= 0 ) {
86  state += "[" + std::to_string( sv.index( ) ) + "]";
87  } else if( not sv.name( ).empty( ) ) {
88  state += "." + static_cast<std::string>( sv.name( ) );
89  }
90  return DAW_FWD( state );
91  } );
92  }
93 
98  [[nodiscard]] inline std::vector<json_path_node>
99  find_json_path_stack_to( char const *parse_location,
100  char const *doc_start ) {
101  if( parse_location == nullptr or doc_start == nullptr ) {
102  return { };
103  }
104  if( std::less<>{ }( parse_location, doc_start ) ) {
105  return { };
106  }
107 
108  struct handler_t {
109  char const *first;
110  char const *last;
111  std::vector<json_path_node> parse_stack{ };
112 
113  // This is for when we throw after array/class end, but before the next
114  // value starts
115  std::optional<json_path_node> last_popped{ };
116  json_path_node state{ };
117 
118  JsonBaseParseTypes child_of( ) {
119  if( parse_stack.empty( ) ) {
121  }
122  return parse_stack.back( ).type( );
123  }
124 
125  [[nodiscard]] bool handle_on_value( json_pair jp ) {
126  if( auto const range = jp.value.get_raw_state( );
127  range.empty( ) or last <= std::data( range ) ) {
128  return false;
129  }
130  if( auto const t = child_of( ); t == JsonBaseParseTypes::Class ) {
131  state.m_name = *jp.name;
132  state.m_index = -1;
133  } else if( t == JsonBaseParseTypes::Array ) {
134  state.m_name = { };
135  state.m_index++;
136  } else {
137  state.m_name = { };
138  state.m_index = -1;
139  }
140  state.m_value_start = jp.value.get_raw_state( ).first;
141  state.m_type = jp.value.type( );
142  last_popped = std::nullopt;
143  return true;
144  }
145 
146  [[nodiscard]] bool handle_on_array_start( json_value const & ) {
147  parse_stack.push_back( state );
148  state = { };
149  return true;
150  }
151 
152  [[nodiscard]] bool handle_on_array_end( ) {
153  if( not parse_stack.empty( ) ) {
154  last_popped = parse_stack.back( );
155  state = parse_stack.back( );
156  parse_stack.pop_back( );
157  }
158  return true;
159  }
160 
161  [[nodiscard]] bool handle_on_class_start( json_value const & ) {
162  parse_stack.push_back( state );
163  state = { };
164  return true;
165  }
166 
167  [[nodiscard]] bool handle_on_class_end( ) {
168  if( not parse_stack.empty( ) ) {
169  last_popped = parse_stack.back( );
170  state = parse_stack.back( );
171  parse_stack.pop_back( );
172  }
173  return true;
174  }
175 
176  [[nodiscard]] bool handle_on_number( json_value jv ) {
177  auto sv = std::string_view( );
178 #if defined( DAW_USE_EXCEPTIONS )
179  try {
180 #endif
181  sv = jv.get_string_view( );
182 #if defined( DAW_USE_EXCEPTIONS )
183  } catch( json_exception const & ) {
184  parse_stack.push_back( state );
185  return false;
186  }
187 #endif
188  if( std::data( sv ) <= last and last <= daw::data_end( sv ) ) {
189  parse_stack.push_back( state );
190  return false;
191  }
192  return true;
193  }
194 
195  [[nodiscard]] bool handle_on_bool( json_value jv ) {
196  auto sv = std::string_view( );
197 #if defined( DAW_USE_EXCEPTIONS )
198  try {
199 #endif
200  sv = jv.get_string_view( );
201 #if defined( DAW_USE_EXCEPTIONS )
202  } catch( json_exception const & ) {
203  parse_stack.push_back( state );
204  return false;
205  }
206 #endif
207  if( std::data( sv ) <= last and last <= daw::data_end( sv ) ) {
208  parse_stack.push_back( state );
209  return false;
210  }
211  return true;
212  }
213 
214  [[nodiscard]] bool handle_on_string( json_value jv ) {
215  auto sv = std::string_view( );
216 #if defined( DAW_USE_EXCEPTIONS )
217  try {
218 #endif
219  sv = jv.get_string_view( );
220 #if defined( DAW_USE_EXCEPTIONS )
221  } catch( json_exception const & ) {
222  parse_stack.push_back( state );
223  return false;
224  }
225 #endif
226  if( std::data( sv ) <= last and last <= daw::data_end( sv ) ) {
227  parse_stack.push_back( state );
228  return false;
229  }
230  return true;
231  }
232 
233  [[nodiscard]] bool handle_on_null( json_value jv ) {
234  auto sv = std::string_view( );
235 #if defined( DAW_USE_EXCEPTIONS )
236  try {
237 #endif
238  sv = jv.get_string_view( );
239 #if defined( DAW_USE_EXCEPTIONS )
240  } catch( json_exception const & ) {
241  parse_stack.push_back( state );
242  return false;
243  }
244 #endif
245  if( std::data( sv ) <= last and last <= daw::data_end( sv ) ) {
246  parse_stack.push_back( state );
247  return false;
248  }
249  return true;
250  }
251  } handler{ doc_start, parse_location + 1 };
252 
253 #if defined( DAW_USE_EXCEPTIONS )
254  try {
255 #endif
256  json_event_parser( doc_start, handler );
257 #if defined( DAW_USE_EXCEPTIONS )
258  } catch( json_exception const & ) {
259  // Ignoring because we are only looking for the stack leading up to this
260  // and it may have come from an error
261  }
262 #endif
263  if( handler.last_popped ) {
264  handler.parse_stack.push_back( *handler.last_popped );
265  }
266  return DAW_MOVE( handler.parse_stack );
267  }
268 
269  [[nodiscard]] inline std::vector<json_path_node>
270  find_json_path_stack_to( json_exception const &jex,
271  char const *doc_start ) {
272  return find_json_path_stack_to( jex.parse_location( ), doc_start );
273  }
274 
275  [[nodiscard]] inline std::string
276  find_json_path_to( char const *parse_location, char const *doc_start ) {
277  return to_json_path_string(
278  find_json_path_stack_to( parse_location, doc_start ) );
279  }
280 
281  [[nodiscard]] inline std::string
282  find_json_path_to( json_exception const &jex, char const *doc_start ) {
283  return to_json_path_string(
284  find_json_path_stack_to( jex.parse_location( ), doc_start ) );
285  }
286 
287  [[nodiscard]] constexpr std::size_t
288  find_line_number_of( char const *doc_pos, char const *doc_start ) {
289  daw_json_assert( doc_pos != nullptr and doc_start != nullptr,
290  ErrorReason::UnexpectedEndOfData );
291  daw_json_assert( std::less<>{ }( doc_start, doc_pos ),
292  ErrorReason::UnexpectedEndOfData );
293 
294  return daw::algorithm::accumulate( doc_start, doc_pos, std::size_t{ },
295  []( std::size_t count, char c ) {
296  if( c == '\n' ) {
297  return count + 1;
298  }
299  return count;
300  } );
301  }
302 
303  [[nodiscard]] constexpr std::size_t
304  find_line_number_of( json_path_node const &node, char const *doc_start ) {
305  return find_line_number_of( node.value_start( ), doc_start );
306  }
307 
308  [[nodiscard]] constexpr std::size_t
309  find_column_number_of( char const *doc_pos, char const *doc_start ) {
310  daw_json_assert( doc_pos != nullptr and doc_start != nullptr,
311  ErrorReason::UnexpectedEndOfData );
312  daw_json_assert( std::less<>{ }( doc_start, doc_pos ),
313  ErrorReason::UnexpectedEndOfData );
314 
315  auto first = daw::reverse_iterator<char const *>( doc_pos );
316  auto last = daw::reverse_iterator<char const *>( doc_start );
317  auto pos =
318  std::distance( first, daw::algorithm::find( first, last, '\n' ) );
319  daw_json_assert( pos >= 0, ErrorReason::Unknown );
320  return static_cast<std::size_t>( pos );
321  }
322 
323  [[nodiscard]] constexpr std::size_t
324  find_column_number_of( json_path_node const &node, char const *doc_start ) {
325  return find_column_number_of( node.value_start( ), doc_start );
326  }
327  } // namespace DAW_JSON_VER
328 } // namespace daw::json
Definition: daw_json_value.h:316
constexpr std::string_view get_string_view() const
Definition: daw_json_value.h:444
Definition: daw_json_find_path.h:36
constexpr JsonBaseParseTypes type() const
What type of value is represented.
Definition: daw_json_find_path.h:56
constexpr std::string_view name() const
The member name, only value for submembers of Class types.
Definition: daw_json_find_path.h:61
constexpr char const * value_start() const
The beginning of the value's data in JSON document.
Definition: daw_json_find_path.h:71
constexpr long long index() const
The element index, only valid for elements of Array types.
Definition: daw_json_find_path.h:66
friend std::vector< json_path_node > find_json_path_stack_to(char const *parse_location, char const *doc_start)
Get the json_path_nodes representing the path to the nearest value's position in the document.
Definition: daw_json_find_path.h:99
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:178
constexpr handler_result_holder handle_on_null(Handler &&handler, basic_json_value< ParseState > &jv)
Definition: daw_json_event_parser.h:295
constexpr handler_result_holder handle_on_array_end(Handler &&handler)
Definition: daw_json_event_parser.h:218
constexpr handler_result_holder handle_on_string(Handler &&handler, basic_json_value< ParseState > &jv)
Definition: daw_json_event_parser.h:280
constexpr handler_result_holder handle_on_class_start(Handler &&handler, basic_json_value< ParseState > jv)
Definition: daw_json_event_parser.h:228
constexpr handler_result_holder handle_on_bool(Handler &&handler, basic_json_value< ParseState > jv)
Definition: daw_json_event_parser.h:266
constexpr handler_result_holder handle_on_class_end(Handler &&handler)
Definition: daw_json_event_parser.h:241
constexpr handler_result_holder handle_on_value(Handler &&handler, basic_json_pair< ParseState > p)
Definition: daw_json_event_parser.h:193
constexpr handler_result_holder handle_on_number(Handler &&handler, basic_json_value< ParseState > &jv)
Definition: daw_json_event_parser.h:251
constexpr handler_result_holder handle_on_array_start(Handler &&handler, basic_json_value< ParseState > jv)
Definition: daw_json_event_parser.h:205
constexpr std::string_view to_string(JsonBaseParseTypes pt)
Definition: daw_json_enums.h:50
std::string to_json_path_string(std::vector< json_path_node > const &path_stack)
Convert a json_path_node stack to a JSON Path string.
Definition: daw_json_find_path.h:81
constexpr std::size_t find_column_number_of(char const *doc_pos, char const *doc_start)
Definition: daw_json_find_path.h:309
constexpr std::size_t find_line_number_of(char const *doc_pos, char const *doc_start)
Definition: daw_json_find_path.h:288
JsonBaseParseTypes
Definition: daw_json_enums.h:40
constexpr void json_event_parser(basic_json_value< ParseState > jvalue, Handler &&handler)
Definition: daw_json_event_parser.h:366
std::string find_json_path_to(char const *parse_location, char const *doc_start)
Definition: daw_json_find_path.h:276
std::vector< json_path_node > find_json_path_stack_to(char const *parse_location, char const *doc_start)
Get the json_path_nodes representing the path to the nearest value's position in the document.
Definition: daw_json_find_path.h:99
Definition: daw_from_json.h:22
Definition: daw_json_value.h:41
std::optional< std::string_view > name
Definition: daw_json_value.h:42
basic_json_value< ParseState > value
Definition: daw_json_value.h:43
#define DAW_JSON_VER
Definition: version.h:11