• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

biojppm / rapidyaml / 18649960093

20 Oct 2025 11:02AM UTC coverage: 97.642% (-0.008%) from 97.65%
18649960093

Pull #503

github

web-flow
Merge 779b983dc into 48acea949
Pull Request #503: Improve error model, callbacks

1823 of 1870 new or added lines in 32 files covered. (97.49%)

38 existing lines in 4 files now uncovered.

13623 of 13952 relevant lines covered (97.64%)

537812.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.67
/src/c4/yml/event_handler_tree.hpp
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_
9
#include "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() {}
920,698✔
67
    EventHandlerTree(Callbacks const& cb) : EventHandlerStack(cb), m_tree(), m_id(NONE), m_num_directives(), m_yaml_directive() {}
20,058✔
68
    EventHandlerTree(Tree *tree, id_type id) : EventHandlerStack(tree->callbacks()), m_tree(tree), m_id(id), m_num_directives(), m_yaml_directive()
3,756✔
69
    {
70
        reset(tree, id);
3,756✔
71
    }
3,756✔
72

73
    void reset(Tree *tree, id_type id)
618,334✔
74
    {
75
        if(C4_UNLIKELY(!tree))
618,334✔
NEW
76
            _RYML_ERR_BASIC_(m_stack.m_callbacks, "null tree");
×
77
        if(C4_UNLIKELY(id >= tree->capacity()))
618,334✔
NEW
78
            _RYML_ERR_BASIC_(tree->callbacks(), "invalid node");
×
79
        if(C4_UNLIKELY(!tree->is_root(id)))
618,334✔
80
            if(C4_UNLIKELY(tree->is_map(tree->parent(id))))
1,164✔
81
                if(C4_UNLIKELY(!tree->has_key(id)))
480✔
82
                    _RYML_ERR_BASIC_(tree->callbacks(), "destination node belongs to a map and has no key");
12✔
83
        m_tree = tree;
618,322✔
84
        m_id = id;
618,322✔
85
        if(m_tree->is_root(id))
618,322✔
86
        {
87
            _stack_reset_root();
617,752✔
88
            _reset_parser_state(m_curr, id, m_tree->root_id());
617,752✔
89
        }
90
        else
91
        {
92
            _stack_reset_non_root();
570✔
93
            _reset_parser_state(m_parent, id, m_tree->parent(id));
570✔
94
            _reset_parser_state(m_curr, id, id);
570✔
95
        }
96
        m_num_directives = 0;
618,322✔
97
        m_yaml_directive = false;
618,322✔
98
    }
618,322✔
99

100
    Callbacks const& callbacks() const { return m_stack.m_callbacks; }
6✔
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)
616,876✔
109
    {
110
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree != nullptr);
616,876✔
111
        this->_stack_start_parse(filename, ymlsrc, relocate_arena, relocate_arena_data);
616,876✔
112
    }
616,876✔
113

114
    void finish_parse()
599,996✔
115
    {
116
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree != nullptr);
599,996✔
117
        if(m_num_directives && !m_tree->is_stream(m_tree->root_id()))
605,300✔
118
            _RYML_ERR_BASIC_(m_stack.m_callbacks, "directives cannot be used without a document");
108✔
119
        this->_stack_finish_parse();
599,888✔
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;
599,888✔
133
    }
599,888✔
134

135
    void cancel_parse()
7,088✔
136
    {
137
        m_tree = nullptr;
7,088✔
138
    }
7,088✔
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*/ }
618,304✔
148

149
    C4_ALWAYS_INLINE void end_stream() const noexcept { /*nothing to do*/ }
601,352✔
150

151
    /** @} */
152

153
public:
154

155
    /** @name YAML document events */
156
    /** @{ */
157

158
    /** implicit doc start (without ---) */
159
    void begin_doc()
258,550✔
160
    {
161
        _c4dbgp("begin_doc");
86,182✔
162
        if(_stack_should_push_on_begin_doc())
258,550✔
163
        {
164
            _c4dbgp("push!");
150✔
165
            _set_root_as_stream();
450✔
166
            _push();
450✔
167
            _enable_(DOC);
150✔
168
        }
169
    }
258,550✔
170
    /** implicit doc end (without ...) */
171
    void end_doc()
362,906✔
172
    {
173
        _c4dbgp("end_doc");
120,968✔
174
        if(_stack_should_pop_on_end_doc())
362,906✔
175
        {
176
            _remove_speculative();
116,856✔
177
            _c4dbgp("pop!");
38,952✔
178
            _pop();
116,856✔
179
        }
180
    }
362,906✔
181

182
    /** explicit doc start, with --- */
183
    void begin_doc_expl()
126,906✔
184
    {
185
        _c4dbgp("begin_doc_expl");
42,302✔
186
        _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->root_id() == m_curr->node_id, m_tree, m_curr->node_id);
126,906✔
187
        if(!m_tree->is_stream(m_tree->root_id())) //if(_should_push_on_begin_doc())
253,812✔
188
        {
189
            _c4dbgp("ensure stream");
32,938✔
190
            _set_root_as_stream();
98,814✔
191
            id_type first = m_tree->first_child(m_tree->root_id());
98,814✔
192
            _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->is_stream(m_tree->root_id()), m_tree, m_curr->node_id);
197,628✔
193
            _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->num_children(m_tree->root_id()) == 1u, m_tree, m_curr->node_id);
98,814✔
194
            if(m_tree->is_container(first) || m_tree->is_val(first))
296,130✔
195
            {
196
                _c4dbgp("push!");
922✔
197
                _push();
2,766✔
198
            }
199
            else
200
            {
201
                _c4dbgp("tweak");
32,016✔
202
                _push();
96,048✔
203
                _remove_speculative();
96,048✔
204
                m_curr->node_id = m_tree->last_child(m_tree->root_id());
96,048✔
205
                m_curr->tr_data = m_tree->_p(m_curr->node_id);
96,048✔
206
            }
207
        }
208
        else
209
        {
210
            _c4dbgp("push!");
9,364✔
211
            _push();
28,092✔
212
        }
213
        _enable_(DOC);
42,302✔
214
    }
126,906✔
215
    /** explicit doc end, with ... */
216
    void end_doc_expl()
6,018✔
217
    {
218
        _c4dbgp("end_doc_expl");
2,006✔
219
        _remove_speculative();
6,018✔
220
        if(_stack_should_pop_on_end_doc())
6,018✔
221
        {
222
            _c4dbgp("pop!");
1,494✔
223
            _pop();
4,482✔
224
        }
225
        m_yaml_directive = false;
6,018✔
226
    }
6,018✔
227

228
    /** @} */
229

230
public:
231

232
    /** @name YAML map events */
233
    /** @{ */
234

235
    void begin_map_key_flow()
204✔
236
    {
237
        _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
204✔
238
    }
239
    void begin_map_key_block()
1,782✔
240
    {
241
        _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
1,782✔
242
    }
243

244
    void begin_map_val_flow()
85,724✔
245
    {
246
        _c4dbgpf("node[{}]: begin_map_val_flow", m_curr->node_id);
28,574✔
247
        _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
85,724✔
248
        _enable_(MAP|FLOW_SL);
28,574✔
249
        _save_loc();
250
        _push();
85,724✔
251
    }
85,724✔
252
    void begin_map_val_block()
206,546✔
253
    {
254
        _c4dbgpf("node[{}]: begin_map_val_block", m_curr->node_id);
68,848✔
255
        _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
206,546✔
256
        _enable_(MAP|BLOCK);
68,848✔
257
        _save_loc();
258
        _push();
206,546✔
259
    }
206,546✔
260

261
    void end_map()
281,492✔
262
    {
263
        _pop();
281,492✔
264
        _c4dbgpf("node[{}]: end_map_val", m_curr->node_id);
93,830✔
265
    }
281,492✔
266

267
    /** @} */
268

269
public:
270

271
    /** @name YAML seq events */
272
    /** @{ */
273

274
    void begin_seq_key_flow()
1,092✔
275
    {
276
        _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
1,092✔
277
    }
278
    void begin_seq_key_block()
4,842✔
279
    {
280
        _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
4,842✔
281
    }
282

283
    void begin_seq_val_flow()
60,846✔
284
    {
285
        _c4dbgpf("node[{}]: begin_seq_val_flow", m_curr->node_id);
20,282✔
286
        _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
60,846✔
287
        _enable_(SEQ|FLOW_SL);
20,282✔
288
        _save_loc();
289
        _push();
60,846✔
290
    }
60,846✔
291
    void begin_seq_val_block()
101,328✔
292
    {
293
        _c4dbgpf("node[{}]: begin_seq_val_block", m_curr->node_id);
33,776✔
294
        _RYML_CHECK_BASIC_(m_stack.m_callbacks, !_has_any_(VAL));
101,328✔
295
        _enable_(SEQ|BLOCK);
33,776✔
296
        _save_loc();
297
        _push();
101,328✔
298
    }
101,328✔
299

300
    void end_seq()
157,206✔
301
    {
302
        _pop();
157,206✔
303
        _c4dbgpf("node[{}]: end_seq_val", m_curr->node_id);
52,402✔
304
    }
157,206✔
305

306
    /** @} */
307

308
public:
309

310
    /** @name YAML structure events */
311
    /** @{ */
312

313
    void add_sibling()
480,924✔
314
    {
315
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
480,924✔
316
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent);
480,924✔
317
        _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->has_children(m_parent->node_id), m_tree, m_parent->node_id);
480,924✔
318
        NodeData const* prev = m_tree->m_buf; // watchout against relocation of the tree nodes
480,924✔
319
        _set_state_(m_curr, m_tree->_append_child__unprotected(m_parent->node_id));
480,924✔
320
        if(prev != m_tree->m_buf)
480,924✔
321
            _refresh_after_relocation();
4,482✔
322
        _c4dbgpf("node[{}]: added sibling={} prev={}", m_parent->node_id, m_curr->node_id, m_tree->prev_sibling(m_curr->node_id));
160,308✔
323
    }
480,924✔
324

325
    /** set the previous val as the first key of a new map, with flow style.
326
     *
327
     * See the documentation for @ref doc_event_handlers, which has
328
     * important notes about this event.
329
     */
330
    void actually_val_is_first_key_of_new_map_flow()
2,550✔
331
    {
332
        if(C4_UNLIKELY(m_tree->is_container(m_curr->node_id)))
5,100✔
333
            _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
522✔
334
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_parent);
2,028✔
335
        _RYML_ASSERT_VISIT_(m_stack.m_callbacks, m_tree->is_seq(m_parent->node_id), m_tree, m_parent->node_id);
4,056✔
336
        _RYML_ASSERT_VISIT_(m_stack.m_callbacks, !m_tree->is_container(m_curr->node_id), m_tree, m_curr->node_id);
4,056✔
337
        _RYML_ASSERT_VISIT_(m_stack.m_callbacks, !m_tree->has_key(m_curr->node_id), m_tree, m_curr->node_id);
4,056✔
338
        const NodeData tmp = _val2key_(*m_curr->tr_data);
2,028✔
339
        _disable_(_VALMASK|VAL_STYLE);
676✔
340
        m_curr->tr_data->m_val = {};
2,028✔
341
        begin_map_val_flow();
2,028✔
342
        m_curr->tr_data->m_type = tmp.m_type;
2,028✔
343
        m_curr->tr_data->m_key = tmp.m_key;
2,028✔
344
    }
2,028✔
345

346
    /** like its flow counterpart, but this function can only be
347
     * called after the end of a flow-val at root or doc level.
348
     *
349
     * See the documentation for @ref doc_event_handlers, which has
350
     * important notes about this event.
351
     */
352
    void actually_val_is_first_key_of_new_map_block()
480✔
353
    {
354
        _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "ryml trees cannot handle containers as keys");
480✔
355
    }
356

357
    /** @} */
358

359
public:
360

361
    /** @name YAML scalar events */
362
    /** @{ */
363

364

365
    C4_ALWAYS_INLINE void set_key_scalar_plain_empty() noexcept
366
    {
367
        _c4dbgpf("node[{}]: set key scalar plain as empty", m_curr->node_id);
6,464✔
368
        m_curr->tr_data->m_key.scalar = {};
19,392✔
369
        _enable_(KEY|KEY_PLAIN|KEYNIL);
6,464✔
370
    }
19,392✔
371
    C4_ALWAYS_INLINE void set_val_scalar_plain_empty() noexcept
372
    {
373
        _c4dbgpf("node[{}]: set val scalar plain as empty", m_curr->node_id);
16,024✔
374
        m_curr->tr_data->m_val.scalar = {};
48,072✔
375
        _enable_(VAL|VAL_PLAIN|VALNIL);
16,024✔
376
    }
48,072✔
377

378
    C4_ALWAYS_INLINE void set_key_scalar_plain(csubstr scalar) noexcept
379
    {
380
        _c4dbgpf("node[{}]: set key scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
132,214✔
381
        m_curr->tr_data->m_key.scalar = scalar;
396,646✔
382
        _enable_(KEY|KEY_PLAIN);
132,214✔
383
    }
396,646✔
384
    C4_ALWAYS_INLINE void set_val_scalar_plain(csubstr scalar) noexcept
385
    {
386
        _c4dbgpf("node[{}]: set val scalar plain: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
149,538✔
387
        m_curr->tr_data->m_val.scalar = scalar;
448,616✔
388
        _enable_(VAL|VAL_PLAIN);
149,538✔
389
    }
448,616✔
390

391

392
    C4_ALWAYS_INLINE void set_key_scalar_dquoted(csubstr scalar) noexcept
393
    {
394
        _c4dbgpf("node[{}]: set key scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
37,040✔
395
        m_curr->tr_data->m_key.scalar = scalar;
111,120✔
396
        _enable_(KEY|KEY_DQUO);
37,040✔
397
    }
111,120✔
398
    C4_ALWAYS_INLINE void set_val_scalar_dquoted(csubstr scalar) noexcept
399
    {
400
        _c4dbgpf("node[{}]: set val scalar dquot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
65,312✔
401
        m_curr->tr_data->m_val.scalar = scalar;
195,936✔
402
        _enable_(VAL|VAL_DQUO);
65,312✔
403
    }
195,936✔
404

405

406
    C4_ALWAYS_INLINE void set_key_scalar_squoted(csubstr scalar) noexcept
407
    {
408
        _c4dbgpf("node[{}]: set key scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
2,472✔
409
        m_curr->tr_data->m_key.scalar = scalar;
7,416✔
410
        _enable_(KEY|KEY_SQUO);
2,472✔
411
    }
7,416✔
412
    C4_ALWAYS_INLINE void set_val_scalar_squoted(csubstr scalar) noexcept
413
    {
414
        _c4dbgpf("node[{}]: set val scalar squot: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
9,312✔
415
        m_curr->tr_data->m_val.scalar = scalar;
27,936✔
416
        _enable_(VAL|VAL_SQUO);
9,312✔
417
    }
27,936✔
418

419

420
    C4_ALWAYS_INLINE void set_key_scalar_literal(csubstr scalar) noexcept
421
    {
422
        _c4dbgpf("node[{}]: set key scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
492✔
423
        m_curr->tr_data->m_key.scalar = scalar;
1,476✔
424
        _enable_(KEY|KEY_LITERAL);
492✔
425
    }
1,476✔
426
    C4_ALWAYS_INLINE void set_val_scalar_literal(csubstr scalar) noexcept
427
    {
428
        _c4dbgpf("node[{}]: set val scalar literal: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
22,084✔
429
        m_curr->tr_data->m_val.scalar = scalar;
66,252✔
430
        _enable_(VAL|VAL_LITERAL);
22,084✔
431
    }
66,252✔
432

433

434
    C4_ALWAYS_INLINE void set_key_scalar_folded(csubstr scalar) noexcept
435
    {
436
        _c4dbgpf("node[{}]: set key scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
80✔
437
        m_curr->tr_data->m_key.scalar = scalar;
240✔
438
        _enable_(KEY|KEY_FOLDED);
80✔
439
    }
240✔
440
    C4_ALWAYS_INLINE void set_val_scalar_folded(csubstr scalar) noexcept
441
    {
442
        _c4dbgpf("node[{}]: set val scalar folded: [{}]~~~{}~~~", m_curr->node_id, scalar.len, scalar);
11,852✔
443
        m_curr->tr_data->m_val.scalar = scalar;
35,556✔
444
        _enable_(VAL|VAL_FOLDED);
11,852✔
445
    }
35,556✔
446

447

448
    C4_ALWAYS_INLINE void mark_key_scalar_unfiltered() noexcept
449
    {
450
        _enable_(KEY_UNFILT);
20✔
451
    }
60✔
452
    C4_ALWAYS_INLINE void mark_val_scalar_unfiltered() noexcept
453
    {
454
        _enable_(VAL_UNFILT);
20✔
455
    }
60✔
456

457
    /** @} */
458

459
public:
460

461
    /** @name YAML anchor/reference events */
462
    /** @{ */
463

464
    void set_key_anchor(csubstr anchor)
21,414✔
465
    {
466
        _c4dbgpf("node[{}]: set key anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
7,138✔
467
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
21,414✔
468
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !_has_any_(KEYREF));
21,414✔
469
        _RYML_ASSERT_PARSE_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
21,414✔
470
        _enable_(KEYANCH);
7,138✔
471
        m_curr->tr_data->m_key.anchor = anchor;
21,414✔
472
    }
21,414✔
473
    void set_val_anchor(csubstr anchor)
42,900✔
474
    {
475
        _c4dbgpf("node[{}]: set val anchor: [{}]~~~{}~~~", m_curr->node_id, anchor.len, anchor);
14,300✔
476
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
42,900✔
477
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, !_has_any_(VALREF));
42,900✔
478
        _RYML_ASSERT_PARSE_(m_tree->callbacks(), !anchor.begins_with('&'), m_curr->pos);
42,900✔
479
        _enable_(VALANCH);
14,300✔
480
        m_curr->tr_data->m_val.anchor = anchor;
42,900✔
481
    }
42,900✔
482

483
    void set_key_ref(csubstr ref)
3,390✔
484
    {
485
        _c4dbgpf("node[{}]: set key ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
1,130✔
486
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
3,390✔
487
        if(C4_UNLIKELY(_has_any_(KEYANCH)))
3,390✔
488
            _RYML_ERR_PARSE_(m_tree->callbacks(), m_curr->pos, "key cannot have both anchor and ref");
60✔
489
        _RYML_ASSERT_PARSE_(m_tree->callbacks(), ref.begins_with('*'), m_curr->pos);
3,330✔
490
        _enable_(KEY|KEYREF);
1,110✔
491
        m_curr->tr_data->m_key.anchor = ref.sub(1);
3,330✔
492
        m_curr->tr_data->m_key.scalar = ref;
3,330✔
493
    }
3,330✔
494
    void set_val_ref(csubstr ref)
12,780✔
495
    {
496
        _c4dbgpf("node[{}]: set val ref: [{}]~~~{}~~~", m_curr->node_id, ref.len, ref);
4,260✔
497
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
12,780✔
498
        if(C4_UNLIKELY(_has_any_(VALANCH)))
12,780✔
499
            _RYML_ERR_PARSE_(m_tree->callbacks(), m_curr->pos, "val cannot have both anchor and ref");
72✔
500
        _RYML_ASSERT_PARSE_(m_tree->callbacks(), ref.begins_with('*'), m_curr->pos);
12,708✔
501
        _enable_(VAL|VALREF);
4,236✔
502
        m_curr->tr_data->m_val.anchor = ref.sub(1);
12,708✔
503
        m_curr->tr_data->m_val.scalar = ref;
12,708✔
504
    }
12,708✔
505

506
    /** @} */
507

508
public:
509

510
    /** @name YAML tag events */
511
    /** @{ */
512

513
    void set_key_tag(csubstr tag) noexcept
10,758✔
514
    {
515
        _c4dbgpf("node[{}]: set key tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
3,586✔
516
        _enable_(KEYTAG);
3,586✔
517
        m_curr->tr_data->m_key.tag = tag;
10,758✔
518
    }
10,758✔
519
    void set_val_tag(csubstr tag) noexcept
60,270✔
520
    {
521
        _c4dbgpf("node[{}]: set val tag: [{}]~~~{}~~~", m_curr->node_id, tag.len, tag);
20,090✔
522
        _enable_(VALTAG);
20,090✔
523
        m_curr->tr_data->m_val.tag = tag;
60,270✔
524
    }
60,270✔
525

526
    /** @} */
527

528
public:
529

530
    /** @name YAML directive events */
531
    /** @{ */
532

533
    C4_NO_INLINE void add_directive(csubstr directive)
6,222✔
534
    {
535
        _c4dbgpf("% directive! {}", directive);
2,074✔
536
        _RYML_ASSERT_PARSE_(m_tree->callbacks(), directive.begins_with('%'), m_curr->pos);
6,222✔
537
        if(directive.begins_with("%TAG"))
6,222✔
538
        {
539
            if(C4_UNLIKELY(!m_tree->add_tag_directive(directive)))
4,140✔
NEW
540
                _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "failed to add directive");
×
541
        }
542
        else if(directive.begins_with("%YAML"))
2,082✔
543
        {
544
            _c4dbgpf("%YAML directive! ignoring...: {}", directive);
592✔
545
            if(C4_UNLIKELY(m_yaml_directive))
1,776✔
546
                _RYML_ERR_PARSE_(m_stack.m_callbacks, m_curr->pos, "multiple yaml directives");
120✔
547
            m_yaml_directive = true;
1,656✔
548
        }
549
        else
550
        {
551
            _c4dbgpf("unknown directive! ignoring... {}", directive);
102✔
552
        }
553
        ++m_num_directives;
6,072✔
554
    }
6,072✔
555

556
    /** @} */
557

558
public:
559

560
    /** @name arena functions */
561
    /** @{ */
562

563
    substr alloc_arena(size_t len)
7,296✔
564
    {
565
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
7,296✔
566
        csubstr prev = m_tree->arena();
7,296✔
567
        substr out = m_tree->alloc_arena(len);
7,296✔
568
        substr curr = m_tree->arena();
7,296✔
569
        if(curr.str != prev.str)
7,296✔
570
            _stack_relocate_to_new_arena(prev, curr);
3,222✔
571
        return out;
9,728✔
572
    }
573

574
    substr alloc_arena(size_t len, substr *relocated)
7,218✔
575
    {
576
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
7,218✔
577
        csubstr prev = m_tree->arena();
14,436✔
578
        if(!prev.is_super(*relocated))
14,436✔
579
            return alloc_arena(len);
948✔
580
        substr out = alloc_arena(len);
6,270✔
581
        substr curr = m_tree->arena();
6,270✔
582
        if(curr.str != prev.str)
6,270✔
583
            *relocated = _stack_relocate_to_new_arena(*relocated, prev, curr);
6,228✔
584
        return out;
6,270✔
585
    }
586

587
    /** @} */
588

589
public:
590

591
    /** @cond dev */
592
    void _reset_parser_state(state* st, id_type parse_root, id_type node)
618,892✔
593
    {
594
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
618,892✔
595
        _set_state_(st, node);
206,296✔
596
        const NodeType type = m_tree->type(node);
618,892✔
597
        #ifdef RYML_DBG
598
        char flagbuf[80];
599
        _c4dbgpf("resetting state: initial flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
206,296✔
600
        #endif
601
        if(type == NOTYPE)
618,892✔
602
        {
603
            _c4dbgpf("node[{}] is notype", node);
205,780✔
604
            if(m_tree->is_root(parse_root))
617,344✔
605
            {
606
                _c4dbgpf("node[{}] is root", node);
205,746✔
607
                st->flags |= RUNK|RTOP;
617,242✔
608
            }
609
            else
610
            {
611
                _c4dbgpf("node[{}] is not root. setting USTY", node);
34✔
612
                st->flags |= USTY;
102✔
613
            }
614
        }
615
        else if(type.is_map())
1,548✔
616
        {
617
            _c4dbgpf("node[{}] is map", node);
308✔
618
            st->flags |= RMAP|USTY;
924✔
619
        }
620
        else if(type.is_seq())
624✔
621
        {
622
            _c4dbgpf("node[{}] is map", node);
74✔
623
            st->flags |= RSEQ|USTY;
222✔
624
        }
625
        else if(type.has_key())
402✔
626
        {
627
            _c4dbgpf("node[{}] has key. setting USTY", node);
134✔
628
            st->flags |= USTY;
402✔
629
        }
630
        else
631
        {
NEW
632
            _RYML_ERR_VISIT_(m_tree->callbacks(), m_tree, node, "cannot append to node");
×
633
        }
634
        if(type.is_doc())
618,892✔
635
        {
636
            _c4dbgpf("node[{}] is doc", node);
637
            st->flags |= RDOC;
×
638
        }
639
        #ifdef RYML_DBG
640
        _c4dbgpf("resetting state: final flags={}", detail::_parser_flags_to_str(flagbuf, st->flags));
206,296✔
641
        #endif
642
    }
618,892✔
643

644
    /** push a new parent, add a child to the new parent, and set the
645
     * child as the current node */
646
    void _push()
582,040✔
647
    {
648
        _stack_push();
582,040✔
649
        NodeData const* prev = m_tree->m_buf; // watch out against relocation of the tree nodes
582,040✔
650
        m_curr->node_id = m_tree->_append_child__unprotected(m_parent->node_id);
582,040✔
651
        m_curr->tr_data = m_tree->_p(m_curr->node_id);
582,040✔
652
        if(prev != m_tree->m_buf)
582,040✔
653
            _refresh_after_relocation();
1,122✔
654
        _c4dbgpf("pushed! level={}. top is now node={} (parent={})", m_curr->level, m_curr->node_id, m_parent ? m_parent->node_id : NONE);
194,012✔
655
    }
582,040✔
656
    /** end the current scope */
657
    void _pop()
560,102✔
658
    {
659
        _remove_speculative_with_parent();
560,102✔
660
        _stack_pop();
560,102✔
661
    }
560,102✔
662

663
public:
664

665
    template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _enable__() noexcept
666
    {
667
        m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type | bits);
2,091,958✔
668
    }
2,091,958✔
669
    template<type_bits bits> C4_HOT C4_ALWAYS_INLINE void _disable__() noexcept
670
    {
671
        m_curr->tr_data->m_type.type = static_cast<NodeType_e>(m_curr->tr_data->m_type.type & (~bits));
2,028✔
672
    }
2,028✔
673
    template<type_bits bits> C4_HOT C4_ALWAYS_INLINE bool _has_any__() const noexcept
674
    {
675
        return (m_curr->tr_data->m_type.type & bits) != 0;
1,422,864✔
676
    }
677

678
public:
679

680
    C4_ALWAYS_INLINE void _set_state_(state *C4_RESTRICT s, id_type id) const noexcept
681
    {
682
        s->node_id = id;
1,199,080✔
683
        s->tr_data = m_tree->_p(id);
1,099,816✔
684
    }
1,199,080✔
685
    void _refresh_after_relocation()
5,604✔
686
    {
687
        _c4dbgp("tree: refreshing stack data after tree data relocation");
1,868✔
688
        for(auto &st : m_stack)
29,160✔
689
            st.tr_data = m_tree->_p(st.node_id);
23,556✔
690
    }
5,604✔
691

692
    void _set_root_as_stream()
99,264✔
693
    {
694
        _c4dbgp("set root as stream");
33,088✔
695
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->root_id() == 0u, m_tree, m_tree->root_id());
99,264✔
696
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_curr->node_id == 0u, m_tree, m_curr->node_id);
99,264✔
697
        m_tree->set_root_as_stream();
99,264✔
698
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_stream(m_tree->root_id()), m_tree, m_tree->root_id());
198,528✔
699
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_children(m_tree->root_id()), m_tree, m_tree->root_id());
99,264✔
700
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->is_doc(m_tree->first_child(m_tree->root_id())), m_tree, m_tree->root_id());
198,528✔
701
        _set_state_(m_curr, m_tree->root_id());
99,264✔
702
    }
99,264✔
703

704
    static NodeData _val2key_(NodeData const& C4_RESTRICT d) noexcept
2,028✔
705
    {
706
        NodeData r = d;
2,028✔
707
        r.m_key = d.m_val;
2,028✔
708
        r.m_val = {};
2,028✔
709
        r.m_type = d.m_type;
2,028✔
710
        static_assert((_VALMASK >> 1u) == _KEYMASK, "required for this function to work");
711
        static_assert((VAL_STYLE >> 1u) == KEY_STYLE, "required for this function to work");
712
        r.m_type.type = ((d.m_type.type & (_VALMASK|VAL_STYLE)) >> 1u);
6,084✔
713
        r.m_type.type = (r.m_type.type & ~(_VALMASK|VAL_STYLE));
4,056✔
714
        r.m_type.type = (r.m_type.type | KEY);
2,028✔
715
        return r;
2,028✔
716
    }
717

718
    void _remove_speculative()
218,922✔
719
    {
720
        _c4dbgp("remove speculative node");
72,974✔
721
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
218,922✔
722
        _RYML_ASSERT_BASIC_(m_tree->callbacks(), !m_tree->empty());
218,922✔
723
        const id_type last_added = m_tree->size() - 1;
218,922✔
724
        if(m_tree->has_parent(last_added))
218,922✔
725
            if(m_tree->_p(last_added)->m_type == NOTYPE)
436,380✔
726
                m_tree->remove(last_added);
96,048✔
727
    }
218,922✔
728

729
    void _remove_speculative_with_parent()
560,102✔
730
    {
731
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
560,102✔
732
        _RYML_ASSERT_BASIC_(m_tree->callbacks(), !m_tree->empty());
560,102✔
733
        const id_type last_added = m_tree->size() - 1;
560,102✔
734
        _RYML_ASSERT_VISIT_(m_tree->callbacks(), m_tree->has_parent(last_added), m_tree, last_added);
560,102✔
735
        if(m_tree->_p(last_added)->m_type == NOTYPE)
1,120,204✔
736
        {
737
            _c4dbgpf("remove speculative node with parent. parent={} node={} parent(node)={}", m_parent->node_id, last_added, m_tree->parent(last_added));
7,112✔
738
            m_tree->remove(last_added);
21,336✔
739
        }
740
    }
560,102✔
741

742
    C4_ALWAYS_INLINE void _save_loc()
743
    {
744
        _RYML_ASSERT_BASIC_(m_stack.m_callbacks, m_tree);
454,444✔
745
        _RYML_ASSERT_BASIC_(m_tree->callbacks(), m_tree->_p(m_curr->node_id)->m_val.scalar.len == 0);
454,444✔
746
        m_tree->_p(m_curr->node_id)->m_val.scalar.str = m_curr->line_contents.rem.str;
454,444✔
747
    }
454,444✔
748

749
#undef _enable_
750
#undef _disable_
751
#undef _has_any_
752

753
    /** @endcond */
754
};
755

756
/** @} */
757

758
} // namespace yml
759
} // namespace c4
760

761
// NOLINTEND(hicpp-signed-bitwise)
762
C4_SUPPRESS_WARNING_MSVC_POP
763

764
#endif /* _C4_YML_EVENT_HANDLER_TREE_HPP_ */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc