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