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