rapidyaml 0.16.0
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
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
12C4_SUPPRESS_WARNING_GCC_PUSH
13C4_SUPPRESS_WARNING_MSVC_PUSH
14C4_SUPPRESS_WARNING_MSVC(4702) // unreachable code
15#if defined(__GNUC__) && __GNUC__ >= 6
16C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
17#endif
18
19// NOLINTBEGIN(hicpp-signed-bitwise)
20
21namespace c4 {
22namespace yml {
23
24/** @addtogroup doc_event_handlers_tree
25 *
26 * An event handler used by @ref ParseEngine to create the @ref Tree
27 * (see @ref Parser).
28 *
29 * @{ */
30
31
32/** @cond dev */
33struct EventHandlerTreeState : public ParserState
34{
35 NodeData *tr_data;
36};
37/** @endcond */
38
39
40/** The event handler to create a ryml @ref Tree. See the
41 * documentation for @ref doc_event_handlers, which has important
42 * notes about the event model used by rapidyaml. */
43struct EventHandlerTree : public EventHandlerStack<EventHandlerTree, EventHandlerTreeState>
44{
45
46 /** @name types
47 * @{ */
48
49 using state = EventHandlerTreeState;
50 enum { requires_strings_on_buffers = false }; // NOLINT
51
52 /** @} */
53
54public:
55
56 /** @cond dev */
57 Tree *C4_RESTRICT m_tree;
58 id_type m_curr_doc;
59 TagCache m_tag_cache;
60
61 #ifdef RYML_DBG
62 #define ryml_enable_(bits) enable_<bits>(); _c4dbgpf("node[{}]: enable {}", m_curr->node_id, #bits)
63 #define ryml_disable_(bits) disable_<bits>(); _c4dbgpf("node[{}]: disable {}", m_curr->node_id, #bits)
64 #else
65 #define ryml_enable_(bits) enable_<bits>()
66 #define ryml_disable_(bits) disable_<bits>()
67 #endif
68 #define ryml_hasany_(bits) has_any_<bits>()
69 /** @endcond */
70
71public:
72
73 /** @name construction and resetting
74 * @{ */
75
76 EventHandlerTree() noexcept : EventHandlerStack(), m_tree(), m_curr_doc() {}
77 EventHandlerTree(Callbacks const& cb) noexcept : EventHandlerStack(cb), m_tree(), m_curr_doc() {}
78 EventHandlerTree(Tree *tree, id_type id) /*except!*/ : EventHandlerStack(tree->callbacks()), m_tree(tree), m_curr_doc()
79 {
80 reset(tree, id);
81 }
82
83 void reset(Tree *tree, id_type id)
84 {
85 if C4_UNLIKELY(!tree)
86 RYML_ERR_BASIC_CB_(m_stack.m_callbacks, "null tree");
87 if C4_UNLIKELY(id >= tree->capacity())
88 RYML_ERR_VISIT_CB_(tree->callbacks(), tree, id, "invalid node");
89 if C4_UNLIKELY(!tree->is_root(id))
90 if C4_UNLIKELY(tree->is_map(tree->parent(id)))
91 if C4_UNLIKELY(!tree->has_key(id))
92 RYML_ERR_BASIC_CB_(tree->callbacks(), "destination node belongs to a map and has no key");
93 m_tree = tree;
94 if(m_tree->is_root(id))
95 {
97 _reset_parser_state(m_curr, id, m_tree->root_id());
98 }
99 else
100 {
102 _reset_parser_state(m_parent, id, m_tree->parent(id));
103 _reset_parser_state(m_curr, id, id);
104 }
105 m_curr_doc = m_tree->ancestor_doc(id);
106 m_tag_cache.clear();
107 }
108
109 Callbacks const& callbacks() const { return m_stack.m_callbacks; }
110
111 C4_ALWAYS_INLINE TagDirectives& tag_directives() { return m_tree->m_tag_directives; } // NOLINT(readability-make-member-function-const)
112 C4_ALWAYS_INLINE TagCache &tag_cache() { return m_tag_cache; }
113
114 /** @} */
115
116public:
117
118 /** @name parse events
119 * @{ */
120
121 void start_parse(const char* filename, substr ymlsrc)
122 {
123 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree != nullptr);
124 this->_stack_start_parse(filename, ymlsrc);
125 }
126
128 {
129 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree != nullptr);
130 this->_stack_finish_parse();
131 /* This pointer is temporary. Remember that:
132 *
133 * - this handler object may be held by the user
134 * - it may be used with a temporary tree inside the parse function
135 * - when the parse function returns the temporary tree, its address
136 * will change
137 *
138 * As a result, the user could try to read the tree from m_tree, and
139 * end up reading the stale temporary object.
140 *
141 * So it is better to clear it here; then the user will get an obvious
142 * segfault if reading from m_tree. */
143 m_tree = nullptr;
144 }
145
147 {
148 m_tree = nullptr;
149 }
150
151 /** @} */
152
153public:
154
155 /** @name YAML stream events */
156 /** @{ */
157
158 C4_ALWAYS_INLINE void begin_stream() const noexcept { /* nothing to do */ }
159
160 C4_ALWAYS_INLINE void end_stream() const noexcept { /* nothing to do */ }
161
162 /** @} */
163
164public:
165
166 /** @name YAML document events */
167 /** @{ */
168
169 /** implicit doc start (without ---) */
171 {
172 _c4dbgp("begin_doc");
174 {
175 _c4dbgp("push!");
176 _set_root_as_stream();
177 _push();
178 ryml_enable_(DOC);
179 }
180 m_curr_doc = m_curr->node_id;
181 }
182 /** implicit doc end (without ...) */
183 void end_doc()
184 {
185 _c4dbgp("end_doc");
186 m_curr_doc = m_tree->size();
188 {
189 _remove_speculative();
190 _c4dbgp("pop!");
191 _pop();
192 }
193 }
194
195 /** explicit doc start, with --- */
197 {
198 _c4dbgp("begin_doc_expl");
199 RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->root_id() == m_curr->node_id, m_tree, m_curr->node_id);
200 if(m_tree->is_stream(m_tree->root_id())) //if(_should_push_on_begin_doc())
201 {
202 _c4dbgp("push!");
203 _push();
204 }
205 else
206 {
207 _c4dbgp("ensure stream");
208 _set_root_as_stream();
209 const id_type root = m_tree->root_id();
210 const id_type first = m_tree->first_child(root);
211 RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->is_stream(root), m_tree, root);
212 RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->num_children(root) == 1u, m_tree, root);
213 if(m_tree->is_container(first) || m_tree->is_val(first))
214 {
215 _c4dbgp("push!");
216 _push();
217 #ifdef RYML_WITH_COMMENTS
218 m_tree->_p(root)->m_first_comment = NONE;
219 m_tree->_p(root)->m_last_comment = NONE;
220 #endif
221 }
222 else
223 {
224 _c4dbgp("tweak");
225 _push();
226 _remove_speculative();
227 m_curr->node_id = m_tree->last_child(root);
228 m_curr->tr_data = m_tree->_p(m_curr->node_id);
229 }
230 }
231 ryml_enable_(DOC);
232 m_curr_doc = m_curr->node_id;
233 }
234 /** explicit doc end, with ... */
236 {
237 _c4dbgp("end_doc_expl");
238 m_curr_doc = m_tree->size();
239 _remove_speculative();
241 {
242 _c4dbgp("pop!");
243 _pop();
244 }
245 }
246
247 /** @} */
248
249public:
250
251 /** @name YAML map events */
252 /** @{ */
253
254 C4_NORETURN void begin_map_key_flow()
255 {
256 RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
257 }
258 C4_NORETURN void begin_map_key_block()
259 {
260 RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
261 }
262
264 {
265 _c4dbgpf("node[{}]: begin_map_val_flow", m_curr->node_id);
266 RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
267 ryml_enable_(MAP|FLOW_SL);
268 _save_loc();
269 _push();
270 }
272 {
273 _c4dbgpf("node[{}]: begin_map_val_block", m_curr->node_id);
274 RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
275 ryml_enable_(MAP|BLOCK);
276 _save_loc();
277 _push();
278 }
279
281 {
282 _c4dbgpf("node[{}]: end_map_block", m_parent->node_id, m_parent->pos.line, m_curr->pos.line);
283 _pop();
284 }
285
286 void end_map_flow(bool multiline, type_bits multiline_style=FLOW_ML1)
287 {
288 _c4dbgpf("node[{}]: end_map. multiline={} startline={} endline={}", m_parent->node_id, multiline, m_parent->pos.line, m_curr->pos.line);
289 _pop();
290 if(multiline)
291 {
292 ryml_disable_(FLOW_SL);
293 enable_(multiline_style);
294 }
295 }
296
297 /** @} */
298
299public:
300
301 /** @name YAML seq events */
302 /** @{ */
303
304 C4_NORETURN void begin_seq_key_flow()
305 {
306 RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
307 }
308 C4_NORETURN void begin_seq_key_block()
309 {
310 RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
311 }
312
314 {
315 _c4dbgpf("node[{}]: begin_seq_val_flow", m_curr->node_id);
316 RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
317 ryml_enable_(SEQ|FLOW_SL);
318 _save_loc();
319 _push();
320 }
322 {
323 _c4dbgpf("node[{}]: begin_seq_val_block", m_curr->node_id);
324 RYML_CHECK_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VAL));
325 ryml_enable_(SEQ|BLOCK);
326 _save_loc();
327 _push();
328 }
329
331 {
332 _c4dbgpf("node[{}]: end_seq_block", m_parent->node_id, m_parent->pos.line, m_curr->pos.line);
333 _pop();
334 }
335
336 void end_seq_flow(bool multiline, type_bits multiline_style=FLOW_ML1)
337 {
338 _c4dbgpf("node[{}]: end_seq. multiline={} startline={} endline={}", m_parent->node_id, multiline, m_parent->pos.line, m_curr->pos.line);
339 _pop();
340 if(multiline)
341 {
342 ryml_disable_(FLOW_SL);
343 enable_(multiline_style);
344 }
345 }
346
347 /** @} */
348
349public:
350
351 /** @name YAML structure events */
352 /** @{ */
353
355 {
356 #if defined(__GNUC__) && (__GNUC__ >= 6)
357 C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wnull-dereference")
358 #endif
359 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
360 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_parent);
361 RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->has_children(m_parent->node_id), m_tree, m_parent->node_id);
362 NodeData const* const prev = m_tree->m_buf; // watchout against relocation of the tree nodes
363 _set_state_(m_curr, m_tree->_append_child__unprotected(m_parent->node_id));
364 if(prev != m_tree->m_buf)
365 _refresh_after_relocation();
366 _c4dbgpf("node[{}]: added sibling={} prev={}", m_parent->node_id, m_curr->node_id, m_tree->prev_sibling(m_curr->node_id));
367 #if defined(__GNUC__) && (__GNUC__ >= 6)
368 C4_SUPPRESS_WARNING_GCC_POP
369 #endif
370 }
371
372 /** reset the previous val as the first key of a new map, with flow style.
373 *
374 * See the documentation for @ref doc_event_handlers, which has
375 * important notes about this event.
376 */
378 {
379 if C4_UNLIKELY(m_tree->is_container(m_curr->node_id))
380 RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
381 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_parent);
382 RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, m_tree->is_seq(m_parent->node_id), m_tree, m_parent->node_id);
383 RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, !m_tree->is_container(m_curr->node_id), m_tree, m_curr->node_id);
384 RYML_ASSERT_VISIT_CB_(m_stack.m_callbacks, !m_tree->has_key(m_curr->node_id), m_tree, m_curr->node_id);
385 const NodeData tmp = _val2key_(*m_curr->tr_data);
386 ryml_disable_(VALMASK_|VAL_STYLE|VALNIL);
387 m_curr->tr_data->m_val = {};
389 m_curr->tr_data->m_type = tmp.m_type;
390 m_curr->tr_data->m_key = tmp.m_key;
391 }
392
393 /** like its flow counterpart, but this function can only be
394 * called after the end of a flow-val at root or doc level.
395 *
396 * See the documentation for @ref doc_event_handlers, which has
397 * important notes about this event.
398 */
400 {
401 RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
402 }
403
404 /** @} */
405
406public:
407
408 /** @name YAML scalar events */
409 /** @{ */
410
411
412 C4_ALWAYS_INLINE void set_key_scalar_plain_empty() noexcept
413 {
414 _c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
415 m_curr->tr_data->m_key.scalar = {};
416 ryml_enable_(KEY|KEY_PLAIN|KEYNIL);
417 }
418 C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
419 {
420 _c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
421 m_curr->tr_data->m_val.scalar = {};
422 ryml_enable_(VAL|VAL_PLAIN|VALNIL);
423 }
424
425 C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar) noexcept
426 {
427 _c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
428 m_curr->tr_data->m_key.scalar = scalar;
429 ryml_enable_(KEY|KEY_PLAIN);
430 }
431 C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar) noexcept
432 {
433 _c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
434 m_curr->tr_data->m_val.scalar = scalar;
435 ryml_enable_(VAL|VAL_PLAIN);
436 }
437
438
439 C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar) noexcept
440 {
441 _c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
442 m_curr->tr_data->m_key.scalar = scalar;
443 ryml_enable_(KEY|KEY_DQUO);
444 }
445 C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar) noexcept
446 {
447 _c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
448 m_curr->tr_data->m_val.scalar = scalar;
449 ryml_enable_(VAL|VAL_DQUO);
450 }
451
452
453 C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar) noexcept
454 {
455 _c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
456 m_curr->tr_data->m_key.scalar = scalar;
457 ryml_enable_(KEY|KEY_SQUO);
458 }
459 C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar) noexcept
460 {
461 _c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
462 m_curr->tr_data->m_val.scalar = scalar;
463 ryml_enable_(VAL|VAL_SQUO);
464 }
465
466
467 C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar) noexcept
468 {
469 _c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
470 m_curr->tr_data->m_key.scalar = scalar;
471 ryml_enable_(KEY|KEY_LITERAL);
472 }
473 C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar) noexcept
474 {
475 _c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
476 m_curr->tr_data->m_val.scalar = scalar;
477 ryml_enable_(VAL|VAL_LITERAL);
478 }
479
480
481 C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar) noexcept
482 {
483 _c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
484 m_curr->tr_data->m_key.scalar = scalar;
485 ryml_enable_(KEY|KEY_FOLDED);
486 }
487 C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar) noexcept
488 {
489 _c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
490 m_curr->tr_data->m_val.scalar = scalar;
491 ryml_enable_(VAL|VAL_FOLDED);
492 }
493
494
495 C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() noexcept
496 {
497 ryml_enable_(KEY_UNFILT);
498 }
499 C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() noexcept
500 {
501 ryml_enable_(VAL_UNFILT);
502 }
503
504 /** @} */
505
506public:
507
508 /** @name YAML anchor/reference events */
509 /** @{ */
510
512 {
513 _c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
514 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
515 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(KEYREF));
516 RYML_ASSERT_PARSE_CB_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
517 ryml_enable_(KEYANCH);
518 m_curr->tr_data->m_key.anchor = anchor;
519 }
521 {
522 _c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
523 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
524 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, !ryml_hasany_(VALREF));
525 RYML_ASSERT_PARSE_CB_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
526 ryml_enable_(VALANCH);
527 m_curr->tr_data->m_val.anchor = anchor;
528 }
529
531 {
532 _c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
533 RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, ref.begins_with('*'), m_curr->pos);
534 RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, !ryml_hasany_(KEYANCH), m_curr->pos);
535 ryml_enable_(KEY|KEYREF);
536 m_curr->tr_data->m_key.anchor = ref.sub(1);
537 m_curr->tr_data->m_key.scalar = ref;
538 }
540 {
541 _c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
542 RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, ref.begins_with('*'), m_curr->pos);
543 RYML_ASSERT_PARSE_CB_(m_stack.m_callbacks, !ryml_hasany_(VALANCH), m_curr->pos);
544 ryml_enable_(VAL|VALREF);
545 m_curr->tr_data->m_val.anchor = ref.sub(1);
546 m_curr->tr_data->m_val.scalar = ref;
547 }
548
549 /** @} */
550
551public:
552
553 /** @name YAML tag events */
554 /** @{ */
555
557 {
558 _c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
559 ryml_enable_(KEYTAG);
560 m_curr->tr_data->m_key.tag = tag;
561 }
563 {
564 _c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
565 ryml_enable_(VALTAG);
566 m_curr->tr_data->m_val.tag = tag;
567 }
568
569 /** @} */
570
571public:
572
573 /** @name YAML directive events */
574 /** @{ */
575
576 void add_directive_yaml(csubstr yaml_version) // NOLINT(readability-convert-member-functions-to-static)
577 {
578 _c4dbgpf("%YAML directive! version={}", yaml_version);
579 (void)yaml_version;
580 }
581
582 void add_directive_tag(csubstr handle, csubstr prefix)
583 {
584 _c4dbgpf("%TAG directive! handle={} prefix={} id={}", handle, prefix, m_curr_doc);
585 if C4_UNLIKELY(!m_tree->m_tag_directives.add(handle, prefix, m_curr_doc))
586 RYML_ERR_PARSE_CB_(m_stack.m_callbacks, m_curr->pos, "too many %TAG directives");
587 }
588
589 /** @} */
590
591public:
592
593 /** @name arena functions */
594 /** @{ */
595
597 {
598 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
599 return m_tree->m_arena.first(m_tree->m_arena_pos);
600 }
602 {
603 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
604 return m_tree->m_arena.sub(m_tree->m_arena_pos);
605 }
606 substr alloc_arena(size_t len) // NOLINT(readability-make-member-function-const)
607 {
608 return m_tree->alloc_arena(len);
609 }
610
611 /** @} */
612
613public:
614
615 /** @cond dev */
616 void _reset_parser_state(state* st, id_type parse_root, id_type node)
617 {
618 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
619 _set_state_(st, node);
620 const NodeType type = m_tree->type(node);
621 #ifdef RYML_DBG
622 char flagbuf[80];
623 _c4dbgpf("resetting state: initial flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
624 #endif
625 if(type == NOTYPE)
626 {
627 _c4dbgpf("node[{}] is notype", node);
628 if(m_tree->is_root(parse_root))
629 {
630 _c4dbgpf("node[{}] is root", node);
631 st->flags |= RUNK|RTOP;
632 }
633 else
634 {
635 _c4dbgpf("node[{}] is not root. setting USTY", node);
636 st->flags |= USTY;
637 }
638 }
639 else if(type.is_map())
640 {
641 _c4dbgpf("node[{}] is map", node);
642 st->flags |= RMAP|USTY;
643 }
644 else if(type.is_seq())
645 {
646 _c4dbgpf("node[{}] is map", node);
647 st->flags |= RSEQ|USTY;
648 }
649 else if(type.has_key())
650 {
651 _c4dbgpf("node[{}] has key. setting USTY", node);
652 st->flags |= USTY;
653 }
654 else
655 {
656 RYML_ERR_VISIT_CB_(m_tree->callbacks(), m_tree, node, "cannot append to node"); // LCOV_EXCL_LINE
657 }
658 if(type.is_doc())
659 {
660 _c4dbgpf("node[{}] is doc", node);
661 st->flags |= RDOC;
662 }
663 #ifdef RYML_DBG
664 _c4dbgpf("resetting state: final flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
665 #endif
666 }
667
668 /** push a new parent, add a child to the new parent, and set the
669 * child as the current node */
670 void _push()
671 {
672 _stack_push();
673 NodeData const* prev = m_tree->m_buf; // watch out against relocation of the tree nodes
674 m_curr->node_id = m_tree->_append_child__unprotected(m_parent->node_id);
675 m_curr->tr_data = m_tree->_p(m_curr->node_id);
676 if(prev != m_tree->m_buf)
677 _refresh_after_relocation();
678 _c4dbgpf("pushed! level={}. top is now node={} (parent={})", m_curr->level, m_curr->node_id, m_parent ? m_parent->node_id : NONE);
679 }
680 /** end the current scope */
681 void _pop()
682 {
683 _remove_speculative_with_parent();
684 _stack_pop();
685 }
686
687public:
688
689 C4_ALWAYS_INLINE void enable_(type_bits bits) noexcept
690 {
691 m_curr->tr_data->m_type.m_bits |= bits;
692 }
693 template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void enable_() noexcept
694 {
695 m_curr->tr_data->m_type.m_bits |= bits;
696 }
697 template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void disable_() noexcept
698 {
699 m_curr->tr_data->m_type.m_bits &= ~bits;
700 }
701 template<type_bits bits> C4_HOT C4_ALWAYS_INLINE bool has_any_() const noexcept
702 {
703 return (m_curr->tr_data->m_type.m_bits & bits) != 0;
704 }
705
706public:
707
708 C4_ALWAYS_INLINE void _set_state_(state *C4_RESTRICT s, id_type id) const noexcept
709 {
710 s->node_id = id;
711 s->tr_data = m_tree->_p(id);
712 }
713 void _refresh_after_relocation()
714 {
715 _c4dbgp("tree: refreshing stack data after tree data relocation");
716 for(auto &st : m_stack)
717 st.tr_data = m_tree->_p(st.node_id);
718 }
719
720 void _set_root_as_stream()
721 {
722 _c4dbgp("set root as stream");
723 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->root_id() == 0u, m_tree, m_tree->root_id());
724 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_curr->node_id == 0u, m_tree, m_curr->node_id);
725 m_tree->set_root_as_stream();
726 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()), m_tree, m_tree->root_id());
727 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()), m_tree, m_tree->root_id());
728 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())), m_tree, m_tree->root_id());
729 _set_state_(m_curr, m_tree->root_id());
730 }
731
732 static NodeData _val2key_(NodeData const& C4_RESTRICT d) noexcept
733 {
734 NodeData r = d;
735 r.m_key = d.m_val;
736 r.m_val = {};
737 r.m_type = d.m_type;
738 static_assert((VALMASK_ >> 1u) == KEYMASK_, "required for this function to work");
739 static_assert((VAL_STYLE >> 1u) == KEY_STYLE, "required for this function to work");
740 r.m_type.m_bits = ((d.m_type.m_bits & (VALMASK_|VAL_STYLE)) >> 1u);
741 r.m_type.m_bits = (r.m_type.m_bits & ~(VALMASK_|VAL_STYLE));
742 r.m_type.m_bits = (r.m_type.m_bits | KEY);
743 if(d.m_type.m_bits & VALNIL)
744 r.m_type.m_bits = (r.m_type.m_bits | KEYNIL);
745 return r;
746 }
747
748 void _remove_speculative()
749 {
750 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
751 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), !m_tree->empty());
752 const id_type last_added = m_tree->size() - 1;
753 const NodeData *C4_RESTRICT d = m_tree->_p(last_added);
754 if(d->m_parent != NONE && d->m_type == NOTYPE)
755 {
756 _c4dbgpf("remove speculative: currparent={} node={} parent(node)={}", m_parent->node_id, last_added, d->m_parent);
757 m_tree->remove(last_added);
758 --m_curr->node_id;
759 }
760 }
761
762 void _remove_speculative_with_parent()
763 {
764 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
765 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), !m_tree->empty());
766 const id_type last_added = m_tree->size() - 1;
767 RYML_ASSERT_VISIT_CB_(m_tree->callbacks(), m_tree->has_parent(last_added), m_tree, last_added);
768 if(m_tree->_p(last_added)->m_type == NOTYPE)
769 {
770 _c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
771 m_tree->remove(last_added);
772 --m_curr->node_id;
773 }
774 }
775
776 C4_ALWAYS_INLINE void _save_loc()
777 {
778 RYML_ASSERT_BASIC_CB_(m_stack.m_callbacks, m_tree);
779 RYML_ASSERT_BASIC_CB_(m_tree->callbacks(), m_tree->_p(m_curr->node_id)->m_val.scalar.len == 0);
780 m_tree->_p(m_curr->node_id)->m_val.scalar.str = m_curr->line_contents.rem.str;
781 }
782
783#undef ryml_enable_
784#undef ryml_disable_
785#undef ryml_has_any_
786
787 /** @endcond */
788};
789
790/** @} */
791
792} // namespace yml
793} // namespace c4
794
795// NOLINTEND(hicpp-signed-bitwise)
796C4_SUPPRESS_WARNING_MSVC_POP
797C4_SUPPRESS_WARNING_GCC_POP
798
799#endif /* C4_YML_EVENT_HANDLER_TREE_HPP_ */
bool is_map(id_type node) const
Definition tree.hpp:480
bool is_root(id_type node) const
Definition tree.hpp:529
bool has_key(id_type node) const
Definition tree.hpp:482
id_type parent(id_type node) const
Definition tree.hpp:569
Callbacks const & callbacks() const
Definition tree.hpp:349
id_type capacity() const
Definition tree.hpp:346
id_type ancestor_doc(id_type node) const
get the document which is a parent document of node i, or the root if the tree is not a stream
Definition tree.hpp:608
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition node_type.hpp:26
@ 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 "
@ VALREF
a *reference: the val references an &anchor
Definition node_type.hpp:40
@ VALNIL
the val is null (eg {a : } results in a null val)
Definition node_type.hpp:46
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition node_type.hpp:35
@ KEY
the scalar to the left of : in a map's member
Definition node_type.hpp:33
@ FLOW_ML1
mark container with multi-line flow style, 1 element per line
Definition node_type.hpp:75
@ VAL_FOLDED
mark val scalar as multiline, block folded >
@ VAL_STYLE
mask of VALQUO|VAL_PLAIN : all the val scalar styles for val (not container styles!...
@ KEYTAG
the key has a tag
Definition node_type.hpp:43
@ FLOW_SL
mark container with single-line flow style
Definition node_type.hpp:56
@ VAL_UNFILT
the val scalar was left unfiltered; the parser was set not to filter.
Definition node_type.hpp:52
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition node_type.hpp:34
@ VALTAG
the val has a tag
Definition node_type.hpp:44
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
Definition node_type.hpp:36
@ VAL_SQUO
mark val scalar as single quoted '
@ KEY_STYLE
mask of KEYQUO|KEY_PLAIN : all the key scalar styles for key (not container styles!...
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
@ KEYREF
a *reference: the key references an &anchor
Definition node_type.hpp:39
@ BLOCK
mark container with block style
@ KEYANCH
the key has an &anchor
Definition node_type.hpp:41
@ VAL_DQUO
mark val scalar as double quoted "
@ KEY_UNFILT
the key scalar was left unfiltered; the parser was set not to filter.
Definition node_type.hpp:51
@ KEY_SQUO
mark key scalar as single quoted '
@ VAL_LITERAL
mark val scalar as multiline, block literal |
@ KEY_LITERAL
mark key scalar as multiline, block literal |
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
@ KEY_FOLDED
mark key scalar as multiline, block folded >
@ KEYNIL
the key is null (eg { : b} results in a null key)
Definition node_type.hpp:45
@ DOC
a document
Definition node_type.hpp:37
basic_substring< char > substr
a mutable string view
Definition substr.hpp:2355
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2356
@ NONE
an index to none
Definition common.hpp:131
@ 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...
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:124
bool begins_with(const C c) const noexcept
true if the first character of the string is c
Definition substr.hpp:850
size_t len
the length of the substring
Definition substr.hpp:218
basic_substring sub(size_t first) const noexcept
return [first,len[
Definition substr.hpp:502
A c-style callbacks class to customize behavior on errors or allocation.
Definition common.hpp:374
void set_key_scalar_plain(csubstr scalar) noexcept
void mark_val_scalar_unfiltered() noexcept
void end_doc_expl()
explicit doc end, with ...
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
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 end_seq_flow(bool multiline, type_bits multiline_style=FLOW_ML1)
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, type_bits multiline_style=FLOW_ML1)
EventHandlerTree(Callbacks const &cb) noexcept
Callbacks const & callbacks() const
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:288
NodeType m_type
Definition tree.hpp:289
NodeScalar m_key
Definition tree.hpp:291
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
bool has_key() const noexcept
bool is_doc() const noexcept
bool is_seq() const noexcept
bool is_map() const noexcept
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
Definition tag.hpp:71
void clear() noexcept
Definition tag.hpp:93