DAW JSON Link
daw_json_parse_name.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 "version.h"
12
13#include "daw_json_assert.h"
16
17#include <ciso646>
18
19namespace daw::json {
20 inline namespace DAW_JSON_VER {
21 namespace json_details {
22 namespace name::name_parser {
23 /*
24 * end of string " -> name value separating : -> any white space
25 * the string can be escaped too
26 */
27 template<typename ParseState>
28 [[maybe_unused]] static constexpr void
30 parse_state.trim_left( );
31 // TODO: should we check for end
32 daw_json_assert_weak( parse_state.front_checked( ) == ':',
33 ErrorReason::InvalidMemberName, parse_state );
34 parse_state.remove_prefix( );
35 parse_state.trim_left( );
36 }
37
38 template<typename ParseState>
39 [[nodiscard,
40 maybe_unused]] DAW_ATTRIB_INLINE inline constexpr daw::string_view
41 parse_nq( ParseState &parse_state ) {
42 if constexpr( ParseState::allow_escaped_names ) {
43 auto r = skip_string_nq( parse_state );
45 return daw::string_view( std::data( r ), std::size( r ) );
46 } else {
47 char const *const ptr = parse_state.first;
48 if constexpr( ParseState::is_unchecked_input ) {
49 parse_state.template move_to_next_of_unchecked<'"'>( );
50 } else {
51 parse_state.template move_to_next_of_checked<'"'>( );
52 }
53 daw_json_assert_weak( parse_state.is_quotes_checked( ) and
54 *std::prev( parse_state.first ) != '\\',
55 ErrorReason::InvalidString, parse_state );
56 auto result = daw::string_view( ptr, parse_state.first );
57 parse_state.remove_prefix( );
59 return result;
60 }
61 }
62 } // namespace name::name_parser
63
65 daw::string_view current{ };
66 char found_char = 0;
67 };
68 // Paths are specified with dot separators, if the name has a dot in it,
69 // it must be escaped
70 // memberA.memberB.member\.C has 3 parts['memberA', 'memberB', 'member.C']
71 [[nodiscard]] constexpr pop_json_path_result
72 pop_json_path( daw::string_view &path ) {
73 auto result = pop_json_path_result{ };
74 if( path.empty( ) ) {
75 return result;
76 }
77 if( path.front( ) == '.' ) {
78 path.remove_prefix( );
79 }
80 result.current =
81 path.pop_front( [&, in_escape = false]( char c ) mutable {
82 if( in_escape ) {
83 in_escape = false;
84 return false;
85 }
86 switch( c ) {
87 case '\\':
88 in_escape = true;
89 return false;
90 case '.':
91 case '[':
92 case ']':
93 result.found_char = c;
94 return true;
95 default:
96 return false;
97 }
98 } );
99 return result;
100 }
101
102 [[nodiscard]] constexpr bool
103 json_path_compare( daw::string_view json_path_item,
104 daw::string_view member_name ) {
105 if( json_path_item.front( ) == '\\' ) {
106 json_path_item.remove_prefix( );
107 }
108 while( not json_path_item.empty( ) and not member_name.empty( ) ) {
109 if( json_path_item.front( ) != member_name.front( ) ) {
110 return false;
111 }
112 json_path_item.remove_prefix( );
113 if( not json_path_item.empty( ) and
114 json_path_item.front( ) == '\\' ) {
115 json_path_item.remove_prefix( );
116 }
117 member_name.remove_prefix( );
118 }
119 return std::size( json_path_item ) == std::size( member_name );
120 }
121
122 // Get the next member name
123 // Assumes that the current item in stream is a double quote
124 // Ensures that the stream is left at the position of the associated
125 // value(e.g after the colon(:) and trimmed)
126 template<typename ParseState>
127 [[nodiscard]] DAW_ATTRIB_FLATTEN inline constexpr daw::string_view
128 parse_name( ParseState &parse_state ) {
129 daw_json_assert_weak( parse_state.is_quotes_checked( ),
130 ErrorReason::InvalidMemberName, parse_state );
131 parse_state.remove_prefix( );
133 }
134
135 template<typename ParseState>
136 constexpr bool find_range2( ParseState &parse_state,
137 daw::string_view path ) {
138
139 auto pop_result = pop_json_path( path );
140 while( not pop_result.current.empty( ) ) {
141 if( pop_result.found_char == ']' ) {
142 // Array Index
143 daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
144 ErrorReason::InvalidJSONPath, parse_state );
145 parse_state.remove_prefix( );
146 parse_state.trim_left_unchecked( );
147 auto idx = daw::parser::parse_unsigned_int<std::size_t>(
148 pop_result.current );
149
150 while( idx > 0 ) {
151 --idx;
152 (void)skip_value( parse_state );
153 parse_state.trim_left_checked( );
154 if( ( idx > 0 ) & ( parse_state.has_more( ) and
155 ( parse_state.front( ) != ',' ) ) ) {
156 return false;
157 }
158 parse_state.move_next_member_or_end( );
159 }
160 } else {
161 daw_json_assert_weak( parse_state.is_opening_brace_checked( ),
162 ErrorReason::InvalidJSONPath, parse_state );
163 parse_state.remove_prefix( );
164 parse_state.trim_left_unchecked( );
165 auto name = parse_name( parse_state );
166 while( not json_path_compare( pop_result.current, name ) ) {
167 (void)skip_value( parse_state );
168 parse_state.move_next_member_or_end( );
169 if( parse_state.empty( ) or parse_state.front( ) != '"' ) {
170 return false;
171 }
172 name = parse_name( parse_state );
173 }
174 }
175 pop_result = pop_json_path( path );
176 }
177 return true;
178 }
179
180 template<typename ParsePolicy, typename String>
181 [[nodiscard]] constexpr std::pair<bool, ParsePolicy>
182 find_range( String &&str, daw::string_view start_path ) {
183 static_assert( std::is_convertible_v<decltype( std::data( str ) ),
184 typename ParsePolicy::CharT *> );
185
186 auto parse_state =
187 ParsePolicy( std::data( str ), daw::data_end( str ) );
188 parse_state.trim_left_checked( );
189 bool found = true;
190 if( parse_state.has_more( ) and not start_path.empty( ) ) {
191 found = find_range2( parse_state, start_path );
192 }
193 return std::pair<bool, ParsePolicy>( found, parse_state );
194 }
195
196 template<typename ParsePolicy, typename String, typename Allocator>
197 [[nodiscard]] constexpr auto find_range( String &&str,
198 daw::string_view start_path,
199 Allocator &alloc ) {
200 static_assert(
201 std::is_same<char const *, typename ParsePolicy::iterator>::value,
202 "Only char const * ranges are currently supported" );
203 auto parse_state = ParsePolicy::with_allocator(
204 std::data( str ), daw::data_end( str ), alloc );
205 parse_state.trim_left_checked( );
206 if( parse_state.has_more( ) and not start_path.empty( ) ) {
207 if( not find_range2( parse_state, start_path ) ) {
208 return std::pair{ false, parse_state };
209 }
210 }
211 return std::pair{ true, parse_state };
212 }
213 } // namespace json_details
214 } // namespace DAW_JSON_VER
215} // namespace daw::json
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:190
ParseState & parse_state
Definition: daw_json_parse_class.h:182
constexpr DAW_ATTRIB_INLINE daw::string_view parse_nq(ParseState &parse_state)
Definition: daw_json_parse_name.h:41
static constexpr void trim_end_of_name(ParseState &parse_state)
Definition: daw_json_parse_name.h:29
constexpr bool json_path_compare(daw::string_view json_path_item, daw::string_view member_name)
Definition: daw_json_parse_name.h:103
constexpr bool find_range2(ParseState &parse_state, daw::string_view path)
Definition: daw_json_parse_name.h:136
constexpr DAW_ATTRIB_FLATTEN daw::string_view parse_name(ParseState &parse_state)
Definition: daw_json_parse_name.h:128
constexpr ParseState skip_value(ParseState &parse_state)
Definition: daw_json_skip.h:304
constexpr std::pair< bool, ParsePolicy > find_range(String &&str, daw::string_view start_path)
Definition: daw_json_parse_name.h:182
constexpr pop_json_path_result pop_json_path(daw::string_view &path)
Definition: daw_json_parse_name.h:72
constexpr DAW_ATTRIB_FLATINLINE ParseState skip_string_nq(ParseState &parse_state)
Definition: daw_json_skip.h:39
Definition: daw_from_json.h:22
char found_char
Definition: daw_json_parse_name.h:66
daw::string_view current
Definition: daw_json_parse_name.h:65
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16