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