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