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