rapidyaml  0.13.0
parse and emit YAML, and do it fast
event_handler_tree.hpp
Go to the documentation of this file.
1 #ifndef _C4_YML_EVENT_HANDLER_TREE_HPP_
2 #define _C4_YML_EVENT_HANDLER_TREE_HPP_
3 
4 #ifndef _C4_YML_TREE_HPP_
5 #include "c4/yml/tree.hpp"
6 #endif
7 
8 #ifndef _C4_YML_EVENT_HANDLER_STACK_HPP_
10 #endif
11 
12 C4_SUPPRESS_WARNING_GCC_PUSH
13 C4_SUPPRESS_WARNING_MSVC_PUSH
14 C4_SUPPRESS_WARNING_MSVC(4702) // unreachable code
15 #if defined(__GNUC__) && __GNUC__ >= 6
16 C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
17 #endif
18 
19 // NOLINTBEGIN(hicpp-signed-bitwise)
20 
21 namespace c4 {
22 namespace yml {
23 
24 /** @addtogroup doc_event_handlers
25  * @{ */
26 
27 
28 /** @cond dev */
29 struct EventHandlerTreeState : public ParserState
30 {
31  NodeData *tr_data;
32 };
33 /** @endcond */
34 
35 
36 /** The event handler to create a ryml @ref Tree. See the
37  * documentation for @ref doc_event_handlers, which has important
38  * notes about the event model used by rapidyaml. */
39 struct EventHandlerTree : public EventHandlerStack<EventHandlerTree, EventHandlerTreeState>
40 {
41 
42  /** @name types
43  * @{ */
44 
45  using state = EventHandlerTreeState;
46  enum { requires_strings_on_buffers = false };
47 
48  /** @} */
49 
50 public:
51 
52  /** @cond dev */
53  Tree *C4_RESTRICT m_tree;
54  id_type m_curr_doc;
55  TagCache m_tag_cache;
56 
57  #ifdef RYML_DBG
58  #define _enable_(bits) _enable__<bits>(); _c4dbgpf("node[{}]: enable {}", m_curr->node_id, #bits)
59  #define _disable_(bits) _disable__<bits>(); _c4dbgpf("node[{}]: disable {}", m_curr->node_id, #bits)
60  #else
61  #define _enable_(bits) _enable__<bits>()
62  #define _disable_(bits) _disable__<bits>()
63  #endif
64  #define _has_any_(bits) _has_any__<bits>()
65  /** @endcond */
66 
67 public:
68 
69  /** @name construction and resetting
70  * @{ */
71 
72  EventHandlerTree() : EventHandlerStack(), m_tree(), m_curr_doc() {}
73  EventHandlerTree(Callbacks const& cb) : EventHandlerStack(cb), m_tree(), m_curr_doc() {}
74  EventHandlerTree(Tree *tree, id_type id) : EventHandlerStack(tree->callbacks()), m_tree(tree), m_curr_doc()
75  {
76  reset(tree, id);
77  }
78 
79  void reset(Tree *tree, id_type id)
80  {
81  if(C4_UNLIKELY(!tree))
82  _RYML_ERR_BASIC_(m_stack.m_callbacks, "null tree");
83  if(C4_UNLIKELY(id >= tree->capacity()))
84  _RYML_ERR_BASIC_(tree->callbacks(), "invalid node");
85  if(C4_UNLIKELY(!tree->is_root(id)))
86  if(C4_UNLIKELY(tree->is_map(tree->parent(id))))
87  if(C4_UNLIKELY(!tree->has_key(id)))
88  _RYML_ERR_BASIC_(tree->callbacks(), "destination node belongs to a map and has no key");
89  m_tree = tree;
90  if(m_tree->is_root(id))
91  {
93  _reset_parser_state(m_curr, id, m_tree->root_id());
94  }
95  else
96  {
98  _reset_parser_state(m_parent, id, m_tree->parent(id));
99  _reset_parser_state(m_curr, id, id);
100  }
101  m_curr_doc = m_tree->ancestor_doc(id);
102  m_tag_cache.clear();
103  }
104 
105  Callbacks const& callbacks() const { return m_stack.m_callbacks; }
106 
107  C4_ALWAYS_INLINE TagDirectives& tag_directives() { return m_tree->m_tag_directives; } // NOLINT(readability-make-member-function-const)
108  C4_ALWAYS_INLINE TagCache &tag_cache() { return m_tag_cache; }
109 
110  /** @} */
111 
112 public:
113 
114  /** @name parse events
115  * @{ */
116 
117  void start_parse(const char* filename, substr ymlsrc)
118  {
119  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree != nullptr);
120  this->_stack_start_parse(filename, ymlsrc);
121  }
122 
124  {
125  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree != nullptr);
126  this->_stack_finish_parse();
127  /* This pointer is temporary. Remember that:
128  *
129  * - this handler object may be held by the user
130  * - it may be used with a temporary tree inside the parse function
131  * - when the parse function returns the temporary tree, its address
132  * will change
133  *
134  * As a result, the user could try to read the tree from m_tree, and
135  * end up reading the stale temporary object.
136  *
137  * So it is better to clear it here; then the user will get an obvious
138  * segfault if reading from m_tree. */
139  m_tree = nullptr;
140  }
141 
143  {
144  m_tree = nullptr;
145  }
146 
147  /** @} */
148 
149 public:
150 
151  /** @name YAML stream events */
152  /** @{ */
153 
154  C4_ALWAYS_INLINE void begin_stream() const noexcept { /* nothing to do */ }
155 
156  C4_ALWAYS_INLINE void end_stream() const noexcept { /* nothing to do */ }
157 
158  /** @} */
159 
160 public:
161 
162  /** @name YAML document events */
163  /** @{ */
164 
165  /** implicit doc start (without ---) */
166  void begin_doc()
167  {
168  _c4dbgp("begin_doc");
170  {
171  _c4dbgp("push!");
172  _set_root_as_stream();
173  _push();
174  _enable_(DOC);
175  }
176  m_curr_doc = m_curr->node_id;
177  }
178  /** implicit doc end (without ...) */
179  void end_doc()
180  {
181  _c4dbgp("end_doc");
182  m_curr_doc = m_tree->size();
184  {
185  _remove_speculative();
186  _c4dbgp("pop!");
187  _pop();
188  }
189  }
190 
191  /** explicit doc start, with --- */
193  {
194  _c4dbgp("begin_doc_expl");
195  _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->root_id() == m_curr->node_id, m_tree, m_curr->node_id);
196  if(m_tree->is_stream(m_tree->root_id())) //if(_should_push_on_begin_doc())
197  {
198  _c4dbgp("push!");
199  _push();
200  }
201  else
202  {
203  _c4dbgp("ensure stream");
204  _set_root_as_stream();
205  const id_type root = m_tree->root_id();
206  const id_type first = m_tree->first_child(root);
207  _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->is_stream(root), m_tree, root);
208  _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->num_children(root) == 1u, m_tree, root);
209  if(m_tree->is_container(first) || m_tree->is_val(first))
210  {
211  _c4dbgp("push!");
212  _push();
213  #ifdef RYML_WITH_COMMENTS
214  m_tree->_p(root)->m_first_comment = NONE;
215  m_tree->_p(root)->m_last_comment = NONE;
216  #endif
217  }
218  else
219  {
220  _c4dbgp("tweak");
221  _push();
222  _remove_speculative();
223  m_curr->node_id = m_tree->last_child(root);
224  m_curr->tr_data = m_tree->_p(m_curr->node_id);
225  }
226  }
227  _enable_(DOC);
228  m_curr_doc = m_curr->node_id;
229  }
230  /** explicit doc end, with ... */
232  {
233  _c4dbgp("end_doc_expl");
234  m_curr_doc = m_tree->size();
235  _remove_speculative();
237  {
238  _c4dbgp("pop!");
239  _pop();
240  }
241  }
242 
243  /** @} */
244 
245 public:
246 
247  /** @name YAML map events */
248  /** @{ */
249 
251  {
252  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
253  }
255  {
256  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
257  }
258 
260  {
261  _c4dbgpf("node[{}]: begin_map_val_flow", m_curr->node_id);
262  _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
263  _enable_(MAP|FLOW_SL);
264  _save_loc();
265  _push();
266  }
268  {
269  _c4dbgpf("node[{}]: begin_map_val_block", m_curr->node_id);
270  _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
271  _enable_(MAP|BLOCK);
272  _save_loc();
273  _push();
274  }
275 
277  {
278  _c4dbgpf("node[{}]: end_map_block", m_parent->node_id, m_parent->pos.line, m_curr->pos.line);
279  _pop();
280  }
281 
282  void end_map_flow(bool multiline)
283  {
284  _c4dbgpf("node[{}]: end_map. multiline={} startline={} endline={}", m_parent->node_id, multiline, m_parent->pos.line, m_curr->pos.line);
285  _pop();
286  if(multiline)
287  {
288  _disable_(FLOW_SL);
289  _enable_(FLOW_ML);
290  }
291  }
292 
293  /** @} */
294 
295 public:
296 
297  /** @name YAML seq events */
298  /** @{ */
299 
301  {
302  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
303  }
305  {
306  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
307  }
308 
310  {
311  _c4dbgpf("node[{}]: begin_seq_val_flow", m_curr->node_id);
312  _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
313  _enable_(SEQ|FLOW_SL);
314  _save_loc();
315  _push();
316  }
318  {
319  _c4dbgpf("node[{}]: begin_seq_val_block", m_curr->node_id);
320  _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
321  _enable_(SEQ|BLOCK);
322  _save_loc();
323  _push();
324  }
325 
327  {
328  _c4dbgpf("node[{}]: end_seq_block", m_parent->node_id, m_parent->pos.line, m_curr->pos.line);
329  _pop();
330  }
331 
332  void end_seq_flow(bool multiline)
333  {
334  _c4dbgpf("node[{}]: end_seq. multiline={} startline={} endline={}", m_parent->node_id, multiline, m_parent->pos.line, m_curr->pos.line);
335  _pop();
336  if(multiline)
337  {
338  _disable_(FLOW_SL);
339  _enable_(FLOW_ML);
340  }
341  }
342 
343  /** @} */
344 
345 public:
346 
347  /** @name YAML structure events */
348  /** @{ */
349 
350  void add_sibling()
351  {
352  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
353  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent);
354  _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->has_children(m_parent->node_id), m_tree, m_parent->node_id);
355  NodeData const* const prev = m_tree->m_buf; // watchout against relocation of the tree nodes
356  _set_state_(m_curr, m_tree->_append_child__unprotected(m_parent->node_id));
357  if(prev != m_tree->m_buf)
358  _refresh_after_relocation();
359  _c4dbgpf("node[{}]: added sibling={} prev={}", m_parent->node_id, m_curr->node_id, m_tree->prev_sibling(m_curr->node_id));
360  }
361 
362  /** reset the previous val as the first key of a new map, with flow style.
363  *
364  * See the documentation for @ref doc_event_handlers, which has
365  * important notes about this event.
366  */
368  {
369  if(C4_UNLIKELY(m_tree->is_container(m_curr->node_id)))
370  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
371  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent);
372  _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->is_seq(m_parent->node_id), m_tree, m_parent->node_id);
373  _RYML_ASSERT_VISIT_(m_stack.m_callbacks, !m_tree->is_container(m_curr->node_id), m_tree, m_curr->node_id);
374  _RYML_ASSERT_VISIT_(m_stack.m_callbacks, !m_tree->has_key(m_curr->node_id), m_tree, m_curr->node_id);
375  const NodeData tmp = _val2key_(*m_curr->tr_data);
376  _disable_(_VALMASK|VAL_STYLE|VALNIL);
377  m_curr->tr_data->m_val = {};
379  m_curr->tr_data->m_type = tmp.m_type;
380  m_curr->tr_data->m_key = tmp.m_key;
381  }
382 
383  /** like its flow counterpart, but this function can only be
384  * called after the end of a flow-val at root or doc level.
385  *
386  * See the documentation for @ref doc_event_handlers, which has
387  * important notes about this event.
388  */
390  {
391  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
392  }
393 
394  /** @} */
395 
396 public:
397 
398  /** @name YAML scalar events */
399  /** @{ */
400 
401 
402  C4_ALWAYS_INLINE void set_key_scalar_plain_empty() noexcept
403  {
404  _c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
405  m_curr->tr_data->m_key.scalar = {};
406  _enable_(KEY|KEY_PLAIN|KEYNIL);
407  }
408  C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
409  {
410  _c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
411  m_curr->tr_data->m_val.scalar = {};
412  _enable_(VAL|VAL_PLAIN|VALNIL);
413  }
414 
415  C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar) noexcept
416  {
417  _c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
418  m_curr->tr_data->m_key.scalar = scalar;
419  _enable_(KEY|KEY_PLAIN);
420  }
421  C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar) noexcept
422  {
423  _c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
424  m_curr->tr_data->m_val.scalar = scalar;
425  _enable_(VAL|VAL_PLAIN);
426  }
427 
428 
429  C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar) noexcept
430  {
431  _c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
432  m_curr->tr_data->m_key.scalar = scalar;
433  _enable_(KEY|KEY_DQUO);
434  }
435  C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar) noexcept
436  {
437  _c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
438  m_curr->tr_data->m_val.scalar = scalar;
439  _enable_(VAL|VAL_DQUO);
440  }
441 
442 
443  C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar) noexcept
444  {
445  _c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
446  m_curr->tr_data->m_key.scalar = scalar;
447  _enable_(KEY|KEY_SQUO);
448  }
449  C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar) noexcept
450  {
451  _c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
452  m_curr->tr_data->m_val.scalar = scalar;
453  _enable_(VAL|VAL_SQUO);
454  }
455 
456 
457  C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar) noexcept
458  {
459  _c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
460  m_curr->tr_data->m_key.scalar = scalar;
461  _enable_(KEY|KEY_LITERAL);
462  }
463  C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar) noexcept
464  {
465  _c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
466  m_curr->tr_data->m_val.scalar = scalar;
467  _enable_(VAL|VAL_LITERAL);
468  }
469 
470 
471  C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar) noexcept
472  {
473  _c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
474  m_curr->tr_data->m_key.scalar = scalar;
475  _enable_(KEY|KEY_FOLDED);
476  }
477  C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar) noexcept
478  {
479  _c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
480  m_curr->tr_data->m_val.scalar = scalar;
481  _enable_(VAL|VAL_FOLDED);
482  }
483 
484 
485  C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() noexcept
486  {
487  _enable_(KEY_UNFILT);
488  }
489  C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() noexcept
490  {
491  _enable_(VAL_UNFILT);
492  }
493 
494  /** @} */
495 
496 public:
497 
498  /** @name YAML anchor/reference events */
499  /** @{ */
500 
501  void set_key_anchor(csubstr anchor)
502  {
503  _c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
504  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
505  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !_has_any_(KEYREF));
506  _RYML_ASSERT_PARSE_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
507  _enable_(KEYANCH);
508  m_curr->tr_data->m_key.anchor = anchor;
509  }
510  void set_val_anchor(csubstr anchor)
511  {
512  _c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
513  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
514  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !_has_any_(VALREF));
515  _RYML_ASSERT_PARSE_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
516  _enable_(VALANCH);
517  m_curr->tr_data->m_val.anchor = anchor;
518  }
519 
520  void set_key_ref(csubstr ref)
521  {
522  _c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
523  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
524  if(C4_UNLIKELY(_has_any_(KEYANCH)))
525  _RYML_ERR_PARSE_(m_tree->callbacks(), m_curr->pos, "key cannot have both anchor and ref");
526  _RYML_ASSERT_PARSE_(m_tree->callbacks(), ref.begins_with('*'), m_curr->pos);
527  _enable_(KEY|KEYREF);
528  m_curr->tr_data->m_key.anchor = ref.sub(1);
529  m_curr->tr_data->m_key.scalar = ref;
530  }
531  void set_val_ref(csubstr ref)
532  {
533  _c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
534  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
535  if(C4_UNLIKELY(_has_any_(VALANCH)))
536  _RYML_ERR_PARSE_(m_tree->callbacks(), m_curr->pos, "val cannot have both anchor and ref");
537  _RYML_ASSERT_PARSE_(m_tree->callbacks(), ref.begins_with('*'), m_curr->pos);
538  _enable_(VAL|VALREF);
539  m_curr->tr_data->m_val.anchor = ref.sub(1);
540  m_curr->tr_data->m_val.scalar = ref;
541  }
542 
543  /** @} */
544 
545 public:
546 
547  /** @name YAML tag events */
548  /** @{ */
549 
550  void set_key_tag(csubstr tag)
551  {
552  _c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
553  _enable_(KEYTAG);
554  m_curr->tr_data->m_key.tag = tag;
555  }
556  void set_val_tag(csubstr tag)
557  {
558  _c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
559  _enable_(VALTAG);
560  m_curr->tr_data->m_val.tag = tag;
561  }
562 
563  /** @} */
564 
565 public:
566 
567  /** @name YAML directive events */
568  /** @{ */
569 
570  void add_directive_yaml(csubstr yaml_version) // NOLINT(readability-convert-member-functions-to-static)
571  {
572  _c4dbgpf("%YAML directive! version={}", yaml_version);
573  (void)yaml_version;
574  }
575 
576  void add_directive_tag(csubstr handle, csubstr prefix)
577  {
578  _c4dbgpf("%TAG directive! handle={} prefix={} id={}", handle, prefix, m_curr_doc);
579  if(C4_UNLIKELY(!m_tree->m_tag_directives.add(handle, prefix, m_curr_doc)))
580  _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "too many %TAG directives");
581  }
582 
583  /** @} */
584 
585 public:
586 
587  /** @name arena functions */
588  /** @{ */
589 
590  substr arena()
591  {
592  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
593  return m_tree->m_arena.first(m_tree->m_arena_pos);
594  }
595  substr arena_rem()
596  {
597  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
598  return m_tree->m_arena.sub(m_tree->m_arena_pos);
599  }
600  substr alloc_arena(size_t len) // NOLINT(readability-make-member-function-const)
601  {
602  return m_tree->alloc_arena(len);
603  }
604 
605  /** @} */
606 
607 public:
608 
609  /** @cond dev */
610  void _reset_parser_state(state* st, id_type parse_root, id_type node)
611  {
612  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
613  _set_state_(st, node);
614  const NodeType type = m_tree->type(node);
615  #ifdef RYML_DBG
616  char flagbuf[80];
617  _c4dbgpf("resetting state: initial flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
618  #endif
619  if(type == NOTYPE)
620  {
621  _c4dbgpf("node[{}] is notype", node);
622  if(m_tree->is_root(parse_root))
623  {
624  _c4dbgpf("node[{}] is root", node);
625  st->flags |= RUNK|RTOP;
626  }
627  else
628  {
629  _c4dbgpf("node[{}] is not root. setting USTY", node);
630  st->flags |= USTY;
631  }
632  }
633  else if(type.is_map())
634  {
635  _c4dbgpf("node[{}] is map", node);
636  st->flags |= RMAP|USTY;
637  }
638  else if(type.is_seq())
639  {
640  _c4dbgpf("node[{}] is map", node);
641  st->flags |= RSEQ|USTY;
642  }
643  else if(type.has_key())
644  {
645  _c4dbgpf("node[{}] has key. setting USTY", node);
646  st->flags |= USTY;
647  }
648  else
649  {
650  _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node, "cannot append to node");
651  }
652  if(type.is_doc())
653  {
654  _c4dbgpf("node[{}] is doc", node);
655  st->flags |= RDOC;
656  }
657  #ifdef RYML_DBG
658  _c4dbgpf("resetting state: final flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
659  #endif
660  }
661 
662  /** push a new parent, add a child to the new parent, and set the
663  * child as the current node */
664  void _push()
665  {
666  _stack_push();
667  NodeData const* prev = m_tree->m_buf; // watch out against relocation of the tree nodes
668  m_curr->node_id = m_tree->_append_child__unprotected(m_parent->node_id);
669  m_curr->tr_data = m_tree->_p(m_curr->node_id);
670  if(prev != m_tree->m_buf)
671  _refresh_after_relocation();
672  _c4dbgpf("pushed! level={}. top is now node={} (parent={})", m_curr->level, m_curr->node_id, m_parent ? m_parent->node_id : NONE);
673  }
674  /** end the current scope */
675  void _pop()
676  {
677  _remove_speculative_with_parent();
678  _stack_pop();
679  }
680 
681 public:
682 
683  template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _enable__() noexcept
684  {
685  m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type | bits);
686  }
687  template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _disable__() noexcept
688  {
689  m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type & (~bits));
690  }
691  template<type_bits bits> C4_HOT C4_ALWAYS_INLINE bool _has_any__() const noexcept
692  {
693  return (m_curr->tr_data->m_type.type & bits) != 0;
694  }
695 
696 public:
697 
698  C4_ALWAYS_INLINE void _set_state_(state *C4_RESTRICT s, id_type id) const noexcept
699  {
700  s->node_id = id;
701  s->tr_data = m_tree->_p(id);
702  }
703  void _refresh_after_relocation()
704  {
705  _c4dbgp("tree: refreshing stack data after tree data relocation");
706  for(auto &st : m_stack)
707  st.tr_data = m_tree->_p(st.node_id);
708  }
709 
710  void _set_root_as_stream()
711  {
712  _c4dbgp("set root as stream");
713  _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->root_id() == 0u, m_tree, m_tree->root_id());
714  _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_curr->node_id == 0u, m_tree, m_curr->node_id);
715  m_tree->set_root_as_stream();
716  _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()), m_tree, m_tree->root_id());
717  _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()), m_tree, m_tree->root_id());
718  _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())), m_tree, m_tree->root_id());
719  _set_state_(m_curr, m_tree->root_id());
720  }
721 
722  static NodeData _val2key_(NodeData const& C4_RESTRICT d) noexcept
723  {
724  NodeData r = d;
725  r.m_key = d.m_val;
726  r.m_val = {};
727  r.m_type = d.m_type;
728  static_assert((_VALMASK >> 1u) == _KEYMASK, "required for this function to work");
729  static_assert((VAL_STYLE >> 1u) == KEY_STYLE, "required for this function to work");
730  r.m_type.type = ((d.m_type.type & (_VALMASK|VAL_STYLE)) >> 1u);
731  r.m_type.type = (r.m_type.type & ~(_VALMASK|VAL_STYLE));
732  r.m_type.type = (r.m_type.type | KEY);
733  if(d.m_type.type & VALNIL)
734  r.m_type.type = (r.m_type.type | KEYNIL);
735  return r;
736  }
737 
738  void _remove_speculative()
739  {
740  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
741  _RYML_ASSERT_BASIC_(m_tree->callbacks(), !m_tree->empty());
742  const id_type last_added = m_tree->size() - 1;
743  const NodeData *C4_RESTRICT d = m_tree->_p(last_added);
744  if(d->m_parent != NONE && d->m_type == NOTYPE)
745  {
746  _c4dbgpf("remove speculative: currparent={} node={} parent(node)={}", m_parent->node_id, last_added, d->m_parent);
747  m_tree->remove(last_added);
748  --m_curr->node_id;
749  }
750  }
751 
752  void _remove_speculative_with_parent()
753  {
754  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
755  _RYML_ASSERT_BASIC_(m_tree->callbacks(), !m_tree->empty());
756  const id_type last_added = m_tree->size() - 1;
757  _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_parent(last_added), m_tree, last_added);
758  if(m_tree->_p(last_added)->m_type == NOTYPE)
759  {
760  _c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
761  m_tree->remove(last_added);
762  --m_curr->node_id;
763  }
764  }
765 
766  C4_ALWAYS_INLINE void _save_loc()
767  {
768  _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
769  _RYML_ASSERT_BASIC_(m_tree->callbacks(), m_tree->_p(m_curr->node_id)->m_val.scalar.len == 0);
770  m_tree->_p(m_curr->node_id)->m_val.scalar.str = m_curr->line_contents.rem.str;
771  }
772 
773 #undef _enable_
774 #undef _disable_
775 #undef _has_any_
776 
777  /** @endcond */
778 };
779 
780 /** @} */
781 
782 } // namespace yml
783 } // namespace c4
784 
785 // NOLINTEND(hicpp-signed-bitwise)
786 C4_SUPPRESS_WARNING_MSVC_POP
787 C4_SUPPRESS_WARNING_GCC_POP
788 
789 #endif /* _C4_YML_EVENT_HANDLER_TREE_HPP_ */
bool is_map(id_type node) const
Definition: tree.hpp:411
bool is_root(id_type node) const
Definition: tree.hpp:460
bool has_key(id_type node) const
Definition: tree.hpp:413
id_type parent(id_type node) const
Definition: tree.hpp:502
Callbacks const & callbacks() const
Definition: tree.hpp:288
id_type capacity() const
Definition: tree.hpp:285
#define _has_any_(bits)
NodeType_e
a bit mask for marking node types and styles
Definition: node_type.hpp:34
@ VALANCH
the val has an &anchor
Definition: node_type.hpp:46
@ NOTYPE
no node type or style is set
Definition: node_type.hpp:36
@ KEY_DQUO
mark key scalar as double quoted "
Definition: node_type.hpp:69
@ VALREF
a *reference: the val references an &anchor
Definition: node_type.hpp:44
@ VALNIL
the val is null (eg {a : } results in a null val)
Definition: node_type.hpp:50
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition: node_type.hpp:39
@ KEY
is member of a map
Definition: node_type.hpp:37
@ VAL_FOLDED
mark val scalar as multiline, block folded >
Definition: node_type.hpp:66
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
Definition: node_type.hpp:93
@ KEYTAG
the key has a tag
Definition: node_type.hpp:47
@ FLOW_SL
mark container with single-line flow style (seqs as '[val1,val2], maps as '{key: val,...
Definition: node_type.hpp:60
@ FLOW_ML
mark container with multi-line flow style (seqs as '[ val1, val2 ], maps as '{ key: val,...
Definition: node_type.hpp:61
@ VAL_UNFILT
the val scalar was left unfiltered; the parser was set not to filter.
Definition: node_type.hpp:56
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition: node_type.hpp:38
@ VALTAG
the val has a tag
Definition: node_type.hpp:48
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
Definition: node_type.hpp:40
@ VAL_SQUO
mark val scalar as single quoted '
Definition: node_type.hpp:68
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
Definition: node_type.hpp:92
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:72
@ KEYREF
a *reference: the key references an &anchor
Definition: node_type.hpp:43
@ BLOCK
mark container with block style (seqs as '- val ', maps as 'key: val')
Definition: node_type.hpp:62
@ KEYANCH
the key has an &anchor
Definition: node_type.hpp:45
@ VAL_DQUO
mark val scalar as double quoted "
Definition: node_type.hpp:70
@ KEY_UNFILT
the key scalar was left unfiltered; the parser was set not to filter.
Definition: node_type.hpp:55
@ KEY_SQUO
mark key scalar as single quoted '
Definition: node_type.hpp:67
@ VAL_LITERAL
mark val scalar as multiline, block literal |
Definition: node_type.hpp:64
@ KEY_LITERAL
mark key scalar as multiline, block literal |
Definition: node_type.hpp:63
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
Definition: node_type.hpp:71
@ KEY_FOLDED
mark key scalar as multiline, block folded >
Definition: node_type.hpp:65
@ KEYNIL
the key is null (eg { : b} results in a null key)
Definition: node_type.hpp:49
@ DOC
a document
Definition: node_type.hpp:41
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:244
@ RTOP
reading at top level
@ RSEQ
reading a seq
@ RUNK
reading unknown state (when starting): must determine whether scalar, map or seq
@ RDOC
reading a document
@ RMAP
reading a map
@ USTY
reading in unknown style mode - must determine FLOW or BLCK reading an implicit map nested in an expl...
@ NONE
an index to none
Definition: common.hpp:251
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
A c-style callbacks class to customize behavior on errors or allocation.
Definition: common.hpp:541
Use this class a base of implementations of event handler to simplify the stack logic.
state * m_curr
current stack level: top of the stack. cached here for easier access.
The event handler to create a ryml Tree.
void set_key_scalar_plain(csubstr scalar) noexcept
void mark_val_scalar_unfiltered() noexcept
void end_doc_expl()
explicit doc end, with ...
void end_seq_flow(bool multiline)
void end_doc()
implicit doc end (without ...)
EventHandlerTreeState state
void begin_doc()
implicit doc start (without —)
void set_val_scalar_plain(csubstr scalar) noexcept
void set_key_scalar_plain_empty() noexcept
EventHandlerTree(Callbacks const &cb)
void mark_key_scalar_unfiltered() noexcept
void actually_val_is_first_key_of_new_map_block()
like its flow counterpart, but this function can only be called after the end of a flow-val at root o...
void set_val_scalar_folded(csubstr scalar) noexcept
Callbacks const & callbacks() const
void begin_doc_expl()
explicit doc start, with —
void end_stream() const noexcept
void set_val_scalar_dquoted(csubstr scalar) noexcept
void set_val_scalar_plain_empty() noexcept
void start_parse(const char *filename, substr ymlsrc)
void end_map_flow(bool multiline)
void set_val_scalar_squoted(csubstr scalar) noexcept
void reset(Tree *tree, id_type id)
void set_val_anchor(csubstr anchor)
void set_key_scalar_literal(csubstr scalar) noexcept
void actually_val_is_first_key_of_new_map_flow()
reset the previous val as the first key of a new map, with flow style.
EventHandlerTree(Tree *tree, id_type id)
void set_key_scalar_folded(csubstr scalar) noexcept
void begin_stream() const noexcept
void add_directive_tag(csubstr handle, csubstr prefix)
void add_directive_yaml(csubstr yaml_version)
void set_key_anchor(csubstr anchor)
void set_key_scalar_dquoted(csubstr scalar) noexcept
void set_val_scalar_literal(csubstr scalar) noexcept
void set_key_scalar_squoted(csubstr scalar) noexcept
contains the data for each YAML node.
Definition: tree.hpp:228
NodeType m_type
Definition: tree.hpp:229
NodeScalar m_key
Definition: tree.hpp:231
wraps a NodeType_e element with some syntactic sugar and predicates
Definition: node_type.hpp:121
bool has_key() const noexcept
Definition: node_type.hpp:185
bool is_doc() const noexcept
Definition: node_type.hpp:181
bool is_seq() const noexcept
Definition: node_type.hpp:184
bool is_map() const noexcept
Definition: node_type.hpp:183
NodeType_e type
Definition: node_type.hpp:124
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
Definition: tag.hpp:71
void clear() noexcept
Definition: tag.hpp:93