rapidyaml  0.16.0
parseandemitYAML,anddoitfast
parse.cpp
Go to the documentation of this file.
1 #include "c4/yml/parse.hpp"
2 
3 #ifndef C4_YML_NODE_HPP_
4 #include "c4/yml/node.hpp"
5 #endif
6 #ifndef C4_YML_PARSE_ENGINE_HPP_
8 #endif
9 #ifndef C4_YML_PARSE_ENGINE_DEF_HPP_
11 #endif
12 #ifndef C4_YML_EVENT_HANDLER_TREE_HPP_
14 #endif
15 
16 
17 //-----------------------------------------------------------------------------
18 
19 namespace c4 {
20 namespace yml {
21 
22 
23 // instantiate the parser class
24 template class RYML_EXPORT ParseEngine<EventHandlerTree>;
25 
26 
27 namespace {
28 // so many things can go wrong...
29 void check_(Tree *tree)
30 {
31  if C4_UNLIKELY(!tree)
32  RYML_ERR_BASIC_("null tree");
33  if C4_UNLIKELY(tree->empty())
34  tree->reserve();
35 }
36 void check_(NodeRef &node)
37 {
38  check_(node.tree());
39  if C4_UNLIKELY(node.id() == NONE)
40  RYML_ERR_VISIT_CB_(node.tree()->m_callbacks, node.tree(), node.id(), "invalid node");
41  node.create();
42 }
43 void check_(Parser *parser)
44 {
45  if C4_UNLIKELY(!parser)
46  RYML_ERR_BASIC_("null parser");
47  if C4_UNLIKELY(!parser->m_evt_handler)
48  // the parser callbacks are from the handler. do not use parser->callbacks()
49  RYML_ERR_BASIC_("null handler");
50 }
51 void check_(Parser *parser, Tree *tree)
52 {
53  if C4_UNLIKELY(!parser && !tree)
54  {
55  RYML_ERR_BASIC_("null parser and tree");
56  }
57  else if C4_UNLIKELY(!parser)
58  {
59  RYML_ERR_BASIC_CB_(tree->callbacks(), "null parser");
60  }
61  else if C4_UNLIKELY(!tree)
62  {
63  if C4_UNLIKELY(!parser->m_evt_handler)
64  RYML_ERR_BASIC_("null tree and handler");
65  else
66  RYML_ERR_BASIC_CB_(parser->callbacks(), "null tree");
67  }
68  if C4_UNLIKELY(!parser->m_evt_handler)
69  {
70  RYML_ERR_BASIC_("null handler");
71  }
72  if C4_UNLIKELY(tree->empty())
73  {
74  tree->reserve();
75  }
76 }
77 void check_(Parser *parser, NodeRef &node)
78 {
79  check_(parser, node.tree());
80  check_(node);
81 }
82 void checksrc_(Tree *tree, csubstr src)
83 {
84  if C4_UNLIKELY(src.len && !src.str)
85  RYML_ERR_BASIC_CB_(tree->callbacks(), "null source buffer");
86 }
87 substr cpsrc_(Tree *tree, csubstr src)
88 {
89  checksrc_(tree, src);
90  return tree->copy_to_arena(src);
91 }
92 // helpers: check and copy to arena
93 substr checkcp_(Tree *tree, csubstr src)
94 {
95  check_(tree);
96  return cpsrc_(tree, src);
97 }
98 substr checkcp_(NodeRef &node, csubstr src)
99 {
100  check_(node);
101  return cpsrc_(node.tree(), src);
102 }
103 substr checkcp_(Parser *parser, Tree *tree, csubstr src)
104 {
105  check_(parser, tree);
106  return cpsrc_(tree, src);
107 }
108 substr checkcp_(Parser *parser, NodeRef &node, csubstr src)
109 {
110  check_(parser, node);
111  return cpsrc_(node.tree(), src);
112 }
113 using Handler = Parser::handler_type;
114 struct TmpParser
115 {
116  Handler handler;
118  // assumes checks above were done prior to instantiation
119  TmpParser(ParserOptions const& opts={})
121  , parser(&handler, opts)
122  {
123  }
124  TmpParser(Tree* tree, ParserOptions const& opts={})
125  : handler(tree->callbacks())
126  , parser(&handler, opts)
127  {
128  }
129  TmpParser(NodeRef &node, ParserOptions const& opts={})
130  : handler(node.tree()->callbacks())
131  , parser(&handler, opts)
132  {
133  }
134 };
135 // assumes checks above were done prior to calling
136 C4_ALWAYS_INLINE void reset_handler_(Parser *parser, Tree *tree, id_type node_id)
137 {
138  RYML_ASSERT_BASIC_(parser); // LCOV_EXCL_LINE lcov weirdly fails here
139  RYML_ASSERT_BASIC_(parser->m_evt_handler);
140  RYML_ASSERT_BASIC_(tree);
141  if C4_UNLIKELY(node_id == NONE || node_id >= tree->capacity())
142  RYML_ERR_VISIT_CB_(tree->m_callbacks, tree, node_id, "invalid node");
143  parser->m_evt_handler->reset(tree, node_id);
144  RYML_ASSERT_BASIC_(parser->m_evt_handler->m_tree == tree);
145 }
146 // assumes checks above were done prior to calling
147 void parse_yaml_(Parser *parser, csubstr filename, substr yaml, Tree *tree, id_type node_id)
148 {
149  reset_handler_(parser, tree, node_id);
150  checksrc_(tree, yaml);
151  parser->parse_in_place_ev(filename, yaml);
152 }
153 // assumes checks above were done prior to calling
154 void parse_json_(Parser *parser, csubstr filename, substr json, Tree *tree, id_type node_id)
155 {
156  reset_handler_(parser, tree, node_id);
157  checksrc_(tree, json);
158  parser->parse_json_in_place_ev(filename, json);
159 }
160 } // namespace
161 
162 
163 
164 // this is vertically aligned to highlight the parameter differences.
165 void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *tree, id_type node_id) { check_(parser, tree); parse_yaml_(parser, filename, yaml, tree, node_id); }
166 void parse_in_place(Parser *parser, substr yaml, Tree *tree, id_type node_id) { check_(parser, tree); parse_yaml_(parser, {} , yaml, tree, node_id); }
167 void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *tree ) { check_(parser, tree); parse_yaml_(parser, filename, yaml, tree, tree->root_id()); }
168 void parse_in_place(Parser *parser, substr yaml, Tree *tree ) { check_(parser, tree); parse_yaml_(parser, {} , yaml, tree, tree->root_id()); }
169 void parse_in_place(Parser *parser, csubstr filename, substr yaml, NodeRef node ) { check_(parser, node); parse_yaml_(parser, filename, yaml, node.tree(), node.id()); }
170 void parse_in_place(Parser *parser, substr yaml, NodeRef node ) { check_(parser, node); parse_yaml_(parser, {} , yaml, node.tree(), node.id()); }
171 Tree parse_in_place(Parser *parser, csubstr filename, substr yaml ) { check_(parser); Tree tree(parser->callbacks()); parse_yaml_(parser, filename, yaml, &tree, tree.root_id()); return tree; }
172 Tree parse_in_place(Parser *parser, substr yaml ) { check_(parser); Tree tree(parser->callbacks()); parse_yaml_(parser, {} , yaml, &tree, tree.root_id()); return tree; }
173 
174 // this is vertically aligned to highlight the parameter differences.
175 void parse_in_place(csubstr filename, substr yaml, Tree *tree, id_type node_id, ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, filename, yaml, tree, node_id); }
176 void parse_in_place( substr yaml, Tree *tree, id_type node_id, ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, {} , yaml, tree, node_id); }
177 void parse_in_place(csubstr filename, substr yaml, Tree *tree , ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, filename, yaml, tree, tree->root_id()); }
178 void parse_in_place( substr yaml, Tree *tree , ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, {} , yaml, tree, tree->root_id()); }
179 void parse_in_place(csubstr filename, substr yaml, NodeRef node , ParserOptions const& opts) { check_(node); TmpParser tmp(node, opts); parse_yaml_(&tmp.parser, filename, yaml, node.tree(), node.id()); }
180 void parse_in_place( substr yaml, NodeRef node , ParserOptions const& opts) { check_(node); TmpParser tmp(node, opts); parse_yaml_(&tmp.parser, {} , yaml, node.tree(), node.id()); }
181 Tree parse_in_place(csubstr filename, substr yaml , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; parse_yaml_(&tmp.parser, filename, yaml, &tree, tree.root_id()); return tree; }
182 Tree parse_in_place( substr yaml , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; parse_yaml_(&tmp.parser, {} , yaml, &tree, tree.root_id()); return tree; }
183 
184 
185 
186 // this is vertically aligned to highlight the parameter differences.
187 void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *tree, id_type node_id) { check_(parser, tree); parse_json_(parser, filename, json, tree, node_id); }
188 void parse_json_in_place(Parser *parser, substr json, Tree *tree, id_type node_id) { check_(parser, tree); parse_json_(parser, {} , json, tree, node_id); }
189 void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *tree ) { check_(parser, tree); parse_json_(parser, filename, json, tree, tree->root_id()); }
190 void parse_json_in_place(Parser *parser, substr json, Tree *tree ) { check_(parser, tree); parse_json_(parser, {} , json, tree, tree->root_id()); }
191 void parse_json_in_place(Parser *parser, csubstr filename, substr json, NodeRef node ) { check_(parser, node); parse_json_(parser, filename, json, node.tree(), node.id()); }
192 void parse_json_in_place(Parser *parser, substr json, NodeRef node ) { check_(parser, node); parse_json_(parser, {} , json, node.tree(), node.id()); }
193 Tree parse_json_in_place(Parser *parser, csubstr filename, substr json ) { check_(parser); Tree tree(parser->callbacks()); parse_json_(parser, filename, json, &tree, tree.root_id()); return tree; }
194 Tree parse_json_in_place(Parser *parser, substr json ) { check_(parser); Tree tree(parser->callbacks()); parse_json_(parser, {} , json, &tree, tree.root_id()); return tree; }
195 
196 // this is vertically aligned to highlight the parameter differences.
197 void parse_json_in_place(csubstr filename, substr json, Tree *tree, id_type node_id, ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, filename, json, tree, node_id); }
198 void parse_json_in_place( substr json, Tree *tree, id_type node_id, ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, {} , json, tree, node_id); }
199 void parse_json_in_place(csubstr filename, substr json, Tree *tree , ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, filename, json, tree, tree->root_id()); }
200 void parse_json_in_place( substr json, Tree *tree , ParserOptions const& opts) { check_(tree); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, {} , json, tree, tree->root_id()); }
201 void parse_json_in_place(csubstr filename, substr json, NodeRef node , ParserOptions const& opts) { check_(node); TmpParser tmp(node, opts); parse_json_(&tmp.parser, filename, json, node.tree(), node.id()); }
202 void parse_json_in_place( substr json, NodeRef node , ParserOptions const& opts) { check_(node); TmpParser tmp(node, opts); parse_json_(&tmp.parser, {} , json, node.tree(), node.id()); }
203 Tree parse_json_in_place(csubstr filename, substr json , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; parse_json_(&tmp.parser, filename, json, &tree, tree.root_id()); return tree; }
204 Tree parse_json_in_place( substr json , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; parse_json_(&tmp.parser, {} , json, &tree, tree.root_id()); return tree; }
205 
206 
207 
208 // this is vertically aligned to highlight the parameter differences.
209 void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *tree, id_type node_id) { substr src = checkcp_(parser, tree, yaml); parse_yaml_(parser, filename, src, tree, node_id); }
210 void parse_in_arena(Parser *parser, csubstr yaml, Tree *tree, id_type node_id) { substr src = checkcp_(parser, tree, yaml); parse_yaml_(parser, {} , src, tree, node_id); }
211 void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *tree ) { substr src = checkcp_(parser, tree, yaml); parse_yaml_(parser, filename, src, tree, tree->root_id()); }
212 void parse_in_arena(Parser *parser, csubstr yaml, Tree *tree ) { substr src = checkcp_(parser, tree, yaml); parse_yaml_(parser, {} , src, tree, tree->root_id()); }
213 void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, NodeRef node ) { substr src = checkcp_(parser, node, yaml); parse_yaml_(parser, filename, src, node.tree(), node.id()); }
214 void parse_in_arena(Parser *parser, csubstr yaml, NodeRef node ) { substr src = checkcp_(parser, node, yaml); parse_yaml_(parser, {} , src, node.tree(), node.id()); }
215 Tree parse_in_arena(Parser *parser, csubstr filename, csubstr yaml ) { check_(parser); Tree tree(parser->callbacks()); substr src = cpsrc_(&tree, yaml); parse_yaml_(parser, filename, src, &tree, tree.root_id()); return tree; }
216 Tree parse_in_arena(Parser *parser, csubstr yaml ) { check_(parser); Tree tree(parser->callbacks()); substr src = cpsrc_(&tree, yaml); parse_yaml_(parser, {} , src, &tree, tree.root_id()); return tree; }
217 
218 // this is vertically aligned to highlight the parameter differences.
219 void parse_in_arena(csubstr filename, csubstr yaml, Tree *tree, id_type node_id, ParserOptions const& opts) { substr src = checkcp_(tree, yaml); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, filename, src, tree, node_id); }
220 void parse_in_arena( csubstr yaml, Tree *tree, id_type node_id, ParserOptions const& opts) { substr src = checkcp_(tree, yaml); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, {} , src, tree, node_id); }
221 void parse_in_arena(csubstr filename, csubstr yaml, Tree *tree , ParserOptions const& opts) { substr src = checkcp_(tree, yaml); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, filename, src, tree, tree->root_id()); }
222 void parse_in_arena( csubstr yaml, Tree *tree , ParserOptions const& opts) { substr src = checkcp_(tree, yaml); TmpParser tmp(tree, opts); parse_yaml_(&tmp.parser, {} , src, tree, tree->root_id()); }
223 void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node , ParserOptions const& opts) { substr src = checkcp_(node, yaml); TmpParser tmp(node, opts); parse_yaml_(&tmp.parser, filename, src, node.tree(), node.id()); }
224 void parse_in_arena( csubstr yaml, NodeRef node , ParserOptions const& opts) { substr src = checkcp_(node, yaml); TmpParser tmp(node, opts); parse_yaml_(&tmp.parser, {} , src, node.tree(), node.id()); }
225 Tree parse_in_arena(csubstr filename, csubstr yaml , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; substr src = cpsrc_(&tree, yaml); parse_yaml_(&tmp.parser, filename, src, &tree, tree.root_id()); return tree; }
226 Tree parse_in_arena( csubstr yaml , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; substr src = cpsrc_(&tree, yaml); parse_yaml_(&tmp.parser, {} , src, &tree, tree.root_id()); return tree; }
227 
228 
229 
230 // this is vertically aligned to highlight the parameter differences.
231 void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *tree, id_type node_id) { substr src = checkcp_(parser, tree, json); parse_json_(parser, filename, src, tree, node_id); }
232 void parse_json_in_arena(Parser *parser, csubstr json, Tree *tree, id_type node_id) { substr src = checkcp_(parser, tree, json); parse_json_(parser, {} , src, tree, node_id); }
233 void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *tree ) { substr src = checkcp_(parser, tree, json); parse_json_(parser, filename, src, tree, tree->root_id()); }
234 void parse_json_in_arena(Parser *parser, csubstr json, Tree *tree ) { substr src = checkcp_(parser, tree, json); parse_json_(parser, {} , src, tree, tree->root_id()); }
235 void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, NodeRef node ) { substr src = checkcp_(parser, node, json); parse_json_(parser, filename, src, node.tree(), node.id()); }
236 void parse_json_in_arena(Parser *parser, csubstr json, NodeRef node ) { substr src = checkcp_(parser, node, json); parse_json_(parser, {} , src, node.tree(), node.id()); }
237 Tree parse_json_in_arena(Parser *parser, csubstr filename, csubstr json ) { check_(parser); Tree tree(parser->callbacks()); substr src = cpsrc_(&tree, json); parse_json_(parser, filename, src, &tree, tree.root_id()); return tree; }
238 Tree parse_json_in_arena(Parser *parser, csubstr json ) { check_(parser); Tree tree(parser->callbacks()); substr src = cpsrc_(&tree, json); parse_json_(parser, {} , src, &tree, tree.root_id()); return tree; }
239 
240 // this is vertically aligned to highlight the parameter differences.
241 void parse_json_in_arena(csubstr filename, csubstr json, Tree *tree, id_type node_id, ParserOptions const& opts) { substr src = checkcp_(tree, json); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, filename, src, tree, node_id); }
242 void parse_json_in_arena( csubstr json, Tree *tree, id_type node_id, ParserOptions const& opts) { substr src = checkcp_(tree, json); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, {} , src, tree, node_id); }
243 void parse_json_in_arena(csubstr filename, csubstr json, Tree *tree , ParserOptions const& opts) { substr src = checkcp_(tree, json); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, filename, src, tree, tree->root_id()); }
244 void parse_json_in_arena( csubstr json, Tree *tree , ParserOptions const& opts) { substr src = checkcp_(tree, json); TmpParser tmp(tree, opts); parse_json_(&tmp.parser, {} , src, tree, tree->root_id()); }
245 void parse_json_in_arena(csubstr filename, csubstr json, NodeRef node , ParserOptions const& opts) { substr src = checkcp_(node, json); TmpParser tmp(node, opts); parse_json_(&tmp.parser, filename, src, node.tree(), node.id()); }
246 void parse_json_in_arena( csubstr json, NodeRef node , ParserOptions const& opts) { substr src = checkcp_(node, json); TmpParser tmp(node, opts); parse_json_(&tmp.parser, {} , src, node.tree(), node.id()); }
247 Tree parse_json_in_arena(csubstr filename, csubstr json , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; substr src = cpsrc_(&tree, json); parse_json_(&tmp.parser, filename, src, &tree, tree.root_id()); return tree; }
248 Tree parse_json_in_arena( csubstr json , ParserOptions const& opts) { TmpParser tmp(opts); Tree tree; substr src = cpsrc_(&tree, json); parse_json_(&tmp.parser, {} , src, &tree, tree.root_id()); return tree; }
249 
250 
251 
252 //-----------------------------------------------------------------------------
253 
255 {
256  id_type num_nodes = 1; // root
257  for(size_t i = 0; i < src.len; ++i)
258  {
259  const char c = src.str[i];
260  num_nodes += (c == '\n') || (c == ',') || (c == '[') || (c == '{');
261  }
262  return num_nodes;
263 }
264 
265 } // namespace yml
266 } // namespace c4
void parse_json_in_arena(Parser *parser, csubstr filename, csubstr json, Tree *tree, id_type node_id)
(1) parse JSON into an existing tree node. The filename will be used in any error messages arising du...
Definition: parse.cpp:231
an index to none
Definition: common.hpp:131
Handler handler
Definition: parse.cpp:116
C * str
a restricted pointer to the first character of the substring
Definition: substr.hpp:216
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree (see Event Ha...
Definition: fwd.hpp:19
Tree const * tree() const noexcept
Definition: node.hpp:1210
void parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *tree, id_type node_id)
(1) parse YAML into an existing tree node. The filename will be used in any error messages arising du...
Definition: parse.cpp:209
id_type root_id() const
Get the id of the root node. The tree must not be empty. The tree can be empty only when constructed ...
Definition: tree.hpp:386
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition: node.hpp:1062
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
Definition: common.hpp:124
Options to give to the ParseEngine to control its behavior.
id_type id() const noexcept
Definition: node.hpp:1208
Parser parser
Definition: parse.cpp:117
basic_substring< char > substr
a mutable string view
Definition: substr.hpp:2355
basic_substring< const char > csubstr
an immutable string view
Definition: substr.hpp:2356
EventHandler handler_type
size_t len
the length of the substring
Definition: substr.hpp:218
id_type estimate_tree_capacity(csubstr src)
Quickly inspect the source to estimate the number of nodes the resulting tree is likely to have...
Definition: parse.cpp:254
This is the main driver of parsing logic: it scans the YAML or JSON source for tokens, and emits the appropriate sequence of parsing events to its event handler.
Definition: fwd.hpp:17
Callbacks const & get_callbacks()
get the global callbacks
Definition: common.cpp:94
Node classes.
Callbacks const & callbacks() const
Get the current callbacks in the parser.
void parse_in_place(Parser *parser, csubstr filename, substr yaml, Tree *tree, id_type node_id)
(1) parse YAML into an existing tree node.
Definition: parse.cpp:165
#define RYML_EXPORT
Definition: export.hpp:18
void parse_json_in_place(Parser *parser, csubstr filename, substr json, Tree *tree, id_type node_id)
(1) parse JSON into an existing tree node. The filename will be used in any error messages arising du...
Definition: parse.cpp:187