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