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