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