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
12#include "daw_json_link_types.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
28namespace 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:320
constexpr std::string_view get_string_view() const
Definition: daw_json_value.h:452
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 char const * value_start() const
The beginning of the value's data in JSON document.
Definition: daw_json_find_path.h:71
constexpr std::string_view name() const
The member name, only value for submembers of Class types.
Definition: daw_json_find_path.h:61
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:179
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:63
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
The fundamental JSON types.
Definition: daw_json_enums.h:53
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:42
std::optional< std::string_view > name
Definition: daw_json_value.h:43
basic_json_value< ParseState > value
Definition: daw_json_value.h:44
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16