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 
19 namespace 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
29  trim_end_of_name( ParseState &parse_state ) {
30  parse_state.trim_left( );
31  // TODO: should we check for end
32  daw_json_assert_weak( parse_state.front( ) == ':',
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:189
ParseState & parse_state
Definition: daw_json_parse_class.h:201
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:298
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
Definition: version.h:11