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

biojppm / rapidyaml / 14049812793

25 Mar 2025 01:47AM UTC coverage: 97.244% (-0.3%) from 97.524%
14049812793

Pull #506

github

web-flow
Merge df77dc42d into d3132a25e
Pull Request #506: Fix merge key order, clear anchors after resolving

67 of 105 new or added lines in 3 files covered. (63.81%)

34 existing lines in 4 files now uncovered.

11573 of 11901 relevant lines covered (97.24%)

761481.38 hits per line

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

94.94
/src/c4/yml/tree.cpp
1
#include "c4/yml/tree.hpp"
2
#include "c4/yml/detail/parser_dbg.hpp"
3
#include "c4/yml/node.hpp"
4
#include "c4/yml/reference_resolver.hpp"
5

6

7
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296/*expression is always 'boolean_value'*/)
8
C4_SUPPRESS_WARNING_MSVC(4702/*unreachable code*/)
9
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
10
C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
11
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
12

13
namespace c4 {
14
namespace yml {
15

16

17
//-----------------------------------------------------------------------------
18
//-----------------------------------------------------------------------------
19
//-----------------------------------------------------------------------------
20

21
NodeRef Tree::rootref()
132,216✔
22
{
23
    return NodeRef(this, root_id());
132,216✔
24
}
25
ConstNodeRef Tree::rootref() const
95,080✔
26
{
27
    return ConstNodeRef(this, root_id());
95,080✔
28
}
29

30
ConstNodeRef Tree::crootref() const
72✔
31
{
32
    return ConstNodeRef(this, root_id());
72✔
33
}
34

35
NodeRef Tree::ref(id_type id)
3,776✔
36
{
37
    _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_cap);
3,776✔
38
    return NodeRef(this, id);
3,552✔
39
}
40
ConstNodeRef Tree::ref(id_type id) const
80✔
41
{
42
    _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_cap);
80✔
43
    return ConstNodeRef(this, id);
80✔
44
}
45
ConstNodeRef Tree::cref(id_type id) const
5,936✔
46
{
47
    _RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_cap);
5,936✔
48
    return ConstNodeRef(this, id);
5,904✔
49
}
50

51
NodeRef Tree::operator[] (csubstr key)
10,928✔
52
{
53
    return rootref()[key];
21,856✔
54
}
55
ConstNodeRef Tree::operator[] (csubstr key) const
14,664✔
56
{
57
    return rootref()[key];
29,304✔
58
}
59

60
NodeRef Tree::operator[] (id_type i)
2,352✔
61
{
62
    return rootref()[i];
4,704✔
63
}
64
ConstNodeRef Tree::operator[] (id_type i) const
7,752✔
65
{
66
    return rootref()[i];
15,488✔
67
}
68

69
NodeRef Tree::docref(id_type i)
1,208✔
70
{
71
    return ref(doc(i));
1,208✔
72
}
73
ConstNodeRef Tree::docref(id_type i) const
5,584✔
74
{
75
    return cref(doc(i));
5,584✔
76
}
77
ConstNodeRef Tree::cdocref(id_type i) const
32✔
78
{
79
    return cref(doc(i));
32✔
80
}
81

82

83
//-----------------------------------------------------------------------------
84
Tree::Tree(Callbacks const& cb)
1,345,104✔
85
    : m_buf(nullptr)
1,345,104✔
86
    , m_cap(0)
1,345,104✔
87
    , m_size(0)
1,345,104✔
88
    , m_free_head(NONE)
1,345,104✔
89
    , m_free_tail(NONE)
1,345,104✔
90
    , m_arena()
1,345,104✔
91
    , m_arena_pos(0)
1,345,104✔
92
    , m_callbacks(cb)
1,345,104✔
93
    , m_tag_directives()
6,725,520✔
94
{
95
}
1,345,104✔
96

97
Tree::Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb)
40✔
98
    : Tree(cb)
40✔
99
{
100
    reserve(node_capacity);
40✔
101
    reserve_arena(arena_capacity);
40✔
102
}
40✔
103

104
Tree::~Tree()
1,345,104✔
105
{
106
    _free();
1,345,104✔
107
}
1,345,104✔
108

109

110
Tree::Tree(Tree const& that) : Tree(that.m_callbacks)
96✔
111
{
112
    _copy(that);
96✔
113
}
96✔
114

115
Tree& Tree::operator= (Tree const& that)
16✔
116
{
117
    if(&that != this)
16✔
118
    {
119
        _free();
16✔
120
        m_callbacks = that.m_callbacks;
16✔
121
        _copy(that);
16✔
122
    }
123
    return *this;
16✔
124
}
125

126
Tree::Tree(Tree && that) noexcept : Tree(that.m_callbacks)
32✔
127
{
128
    _move(that);
32✔
129
}
32✔
130

131
Tree& Tree::operator= (Tree && that) noexcept
380,008✔
132
{
133
    if(&that != this)
380,008✔
134
    {
135
        _free();
380,008✔
136
        m_callbacks = that.m_callbacks;
380,008✔
137
        _move(that);
380,008✔
138
    }
139
    return *this;
380,008✔
140
}
141

142
void Tree::_free()
1,725,128✔
143
{
144
    if(m_buf)
1,725,128✔
145
    {
146
        _RYML_CB_ASSERT(m_callbacks, m_cap > 0);
825,056✔
147
        _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
825,056✔
148
    }
149
    if(m_arena.str)
1,725,128✔
150
    {
151
        _RYML_CB_ASSERT(m_callbacks, m_arena.len > 0);
214,176✔
152
        _RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);
214,176✔
153
    }
154
    _clear();
1,725,128✔
155
}
1,725,128✔
156

157

158
C4_SUPPRESS_WARNING_GCC_PUSH
159
#if defined(__GNUC__) && __GNUC__>= 8
160
    C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wclass-memaccess") // error: ‘void* memset(void*, int, size_t)’ clearing an object of type ‘class c4::yml::Tree’ with no trivial copy-assignment; use assignment or value-initialization instead
161
#endif
162

163
void Tree::_clear()
2,105,168✔
164
{
165
    m_buf = nullptr;
2,105,168✔
166
    m_cap = 0;
2,105,168✔
167
    m_size = 0;
2,105,168✔
168
    m_free_head = 0;
2,105,168✔
169
    m_free_tail = 0;
2,105,168✔
170
    m_arena = {};
2,105,168✔
171
    m_arena_pos = 0;
2,105,168✔
172
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
10,525,840✔
173
        m_tag_directives[i] = {};
8,420,672✔
174
}
2,105,168✔
175

176
void Tree::_copy(Tree const& that)
112✔
177
{
178
    _RYML_CB_ASSERT(m_callbacks, m_buf == nullptr);
112✔
179
    _RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr);
112✔
180
    _RYML_CB_ASSERT(m_callbacks, m_arena.len == 0);
112✔
181
    if(that.m_cap)
112✔
182
    {
183
        m_buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)that.m_cap, that.m_buf);
96✔
184
        memcpy(m_buf, that.m_buf, (size_t)that.m_cap * sizeof(NodeData));
96✔
185
    }
186
    m_cap = that.m_cap;
112✔
187
    m_size = that.m_size;
112✔
188
    m_free_head = that.m_free_head;
112✔
189
    m_free_tail = that.m_free_tail;
112✔
190
    m_arena_pos = that.m_arena_pos;
112✔
191
    m_arena = that.m_arena;
112✔
192
    if(that.m_arena.str)
112✔
193
    {
194
        _RYML_CB_ASSERT(m_callbacks, that.m_arena.len > 0);
96✔
195
        substr arena;
96✔
196
        arena.str = _RYML_CB_ALLOC_HINT(m_callbacks, char, that.m_arena.len, that.m_arena.str);
96✔
197
        arena.len = that.m_arena.len;
96✔
198
        _relocate(arena); // does a memcpy of the arena and updates nodes using the old arena
96✔
199
        m_arena = arena;
96✔
200
    }
201
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
560✔
202
        m_tag_directives[i] = that.m_tag_directives[i];
448✔
203
}
112✔
204

205
void Tree::_move(Tree & that) noexcept
380,040✔
206
{
207
    _RYML_CB_ASSERT(m_callbacks, m_buf == nullptr);
380,040✔
208
    _RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr);
380,040✔
209
    _RYML_CB_ASSERT(m_callbacks, m_arena.len == 0);
380,040✔
210
    m_buf = that.m_buf;
380,040✔
211
    m_cap = that.m_cap;
380,040✔
212
    m_size = that.m_size;
380,040✔
213
    m_free_head = that.m_free_head;
380,040✔
214
    m_free_tail = that.m_free_tail;
380,040✔
215
    m_arena = that.m_arena;
380,040✔
216
    m_arena_pos = that.m_arena_pos;
380,040✔
217
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
1,900,200✔
218
        m_tag_directives[i] = that.m_tag_directives[i];
1,520,160✔
219
    that._clear();
380,040✔
220
}
380,040✔
221

222
void Tree::_relocate(substr next_arena)
7,544✔
223
{
224
    _RYML_CB_ASSERT(m_callbacks, next_arena.not_empty());
7,544✔
225
    _RYML_CB_ASSERT(m_callbacks, next_arena.len >= m_arena.len);
7,544✔
226
    if(m_arena_pos)
7,544✔
227
        memcpy(next_arena.str, m_arena.str, m_arena_pos);
7,520✔
228
    for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n)
138,568✔
229
    {
230
        if(in_arena(n->m_key.scalar))
131,024✔
231
            n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
7,456✔
232
        if(in_arena(n->m_key.tag))
131,024✔
233
            n->m_key.tag = _relocated(n->m_key.tag, next_arena);
176✔
234
        if(in_arena(n->m_key.anchor))
131,024✔
235
            n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
960✔
236
        if(in_arena(n->m_val.scalar))
131,024✔
237
            n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
26,864✔
238
        if(in_arena(n->m_val.tag))
131,024✔
239
            n->m_val.tag = _relocated(n->m_val.tag, next_arena);
3,088✔
240
        if(in_arena(n->m_val.anchor))
131,024✔
241
            n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
960✔
242
    }
243
    for(TagDirective &C4_RESTRICT td : m_tag_directives)
37,720✔
244
    {
245
        if(in_arena(td.prefix))
30,176✔
246
            td.prefix = _relocated(td.prefix, next_arena);
1,376✔
247
        if(in_arena(td.handle))
30,176✔
248
            td.handle = _relocated(td.handle, next_arena);
1,376✔
249
    }
250
}
7,544✔
251

252

253
//-----------------------------------------------------------------------------
254
void Tree::reserve(id_type cap)
849,840✔
255
{
256
    if(cap > m_cap)
849,840✔
257
    {
258
        NodeData *buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)cap, m_buf);
833,912✔
259
        if(m_buf)
833,912✔
260
        {
261
            memcpy(buf, m_buf, (size_t)m_cap * sizeof(NodeData));
8,952✔
262
            _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
8,952✔
263
        }
264
        id_type first = m_cap, del = cap - m_cap;
833,912✔
265
        m_cap = cap;
833,912✔
266
        m_buf = buf;
833,912✔
267
        _clear_range(first, del);
833,912✔
268
        if(m_free_head != NONE)
833,912✔
269
        {
270
            _RYML_CB_ASSERT(m_callbacks, m_buf != nullptr);
32✔
271
            _RYML_CB_ASSERT(m_callbacks, m_free_tail != NONE);
32✔
272
            m_buf[m_free_tail].m_next_sibling = first;
32✔
273
            m_buf[first].m_prev_sibling = m_free_tail;
32✔
274
            m_free_tail = cap-1;
32✔
275
        }
276
        else
277
        {
278
            _RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE);
833,880✔
279
            m_free_head = first;
833,880✔
280
            m_free_tail = cap-1;
833,880✔
281
        }
282
        _RYML_CB_ASSERT(m_callbacks, m_free_head == NONE || (m_free_head >= 0 && m_free_head < cap));
833,912✔
283
        _RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE || (m_free_tail >= 0 && m_free_tail < cap));
833,912✔
284

285
        if( ! m_size)
833,912✔
286
            _claim_root();
824,960✔
287
    }
288
}
849,840✔
289

290

291
//-----------------------------------------------------------------------------
292
void Tree::clear()
424,904✔
293
{
294
    _clear_range(0, m_cap);
424,904✔
295
    m_size = 0;
424,904✔
296
    if(m_buf)
424,904✔
297
    {
298
        _RYML_CB_ASSERT(m_callbacks, m_cap >= 0);
299
        m_free_head = 0;
50,656✔
300
        m_free_tail = m_cap-1;
50,656✔
301
        _claim_root();
50,656✔
302
    }
303
    else
304
    {
305
        m_free_head = NONE;
374,248✔
306
        m_free_tail = NONE;
374,248✔
307
    }
308
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
2,124,520✔
309
        m_tag_directives[i] = {};
1,699,616✔
310
}
424,904✔
311

312
void Tree::_claim_root()
875,616✔
313
{
314
    id_type r = _claim();
875,616✔
315
    _RYML_CB_ASSERT(m_callbacks, r == 0);
875,616✔
316
    _set_hierarchy(r, NONE, NONE);
875,616✔
317
}
875,616✔
318

319

320
//-----------------------------------------------------------------------------
321
void Tree::_clear_range(id_type first, id_type num)
1,258,816✔
322
{
323
    if(num == 0)
1,258,816✔
324
        return; // prevent overflow when subtracting
374,248✔
325
    _RYML_CB_ASSERT(m_callbacks, first >= 0 && first + num <= m_cap);
884,568✔
326
    memset(m_buf + first, 0, (size_t)num * sizeof(NodeData)); // TODO we should not need this
884,568✔
327
    for(id_type i = first, e = first + num; i < e; ++i)
14,938,536✔
328
    {
329
        _clear(i);
14,053,968✔
330
        NodeData *n = m_buf + i;
14,053,968✔
331
        n->m_prev_sibling = i - 1;
14,053,968✔
332
        n->m_next_sibling = i + 1;
14,053,968✔
333
    }
334
    m_buf[first + num - 1].m_next_sibling = NONE;
884,568✔
335
}
336

337
C4_SUPPRESS_WARNING_GCC_POP
338

339

340
//-----------------------------------------------------------------------------
341
void Tree::_release(id_type i)
161,048✔
342
{
343
    _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
161,048✔
344

345
    _rem_hierarchy(i);
161,048✔
346
    _free_list_add(i);
161,048✔
347
    _clear(i);
161,048✔
348

349
    --m_size;
161,048✔
350
}
161,048✔
351

352
//-----------------------------------------------------------------------------
353
// add to the front of the free list
354
void Tree::_free_list_add(id_type i)
161,192✔
355
{
356
    _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
161,192✔
357
    NodeData &C4_RESTRICT w = m_buf[i];
161,192✔
358

359
    w.m_parent = NONE;
161,192✔
360
    w.m_next_sibling = m_free_head;
161,192✔
361
    w.m_prev_sibling = NONE;
161,192✔
362
    if(m_free_head != NONE)
161,192✔
363
        m_buf[m_free_head].m_prev_sibling = i;
161,128✔
364
    m_free_head = i;
161,192✔
365
    if(m_free_tail == NONE)
161,192✔
366
        m_free_tail = m_free_head;
64✔
367
}
161,192✔
368

369
void Tree::_free_list_rem(id_type i)
144✔
370
{
371
    if(m_free_head == i)
144✔
372
        m_free_head = _p(i)->m_next_sibling;
32✔
373
    _rem_hierarchy(i);
144✔
374
}
144✔
375

376
//-----------------------------------------------------------------------------
377
id_type Tree::_claim()
2,586,944✔
378
{
379
    if(m_free_head == NONE || m_buf == nullptr)
2,586,944✔
380
    {
381
        id_type sz = 2 * m_cap;
8,920✔
382
        sz = sz ? sz : 16;
8,920✔
383
        reserve(sz);
8,920✔
384
        _RYML_CB_ASSERT(m_callbacks, m_free_head != NONE);
8,920✔
385
    }
386

387
    _RYML_CB_ASSERT(m_callbacks, m_size < m_cap);
2,586,944✔
388
    _RYML_CB_ASSERT(m_callbacks, m_free_head >= 0 && m_free_head < m_cap);
2,586,944✔
389

390
    id_type ichild = m_free_head;
2,586,944✔
391
    NodeData *child = m_buf + ichild;
2,586,944✔
392

393
    ++m_size;
2,586,944✔
394
    m_free_head = child->m_next_sibling;
2,586,944✔
395
    if(m_free_head == NONE)
2,586,944✔
396
    {
397
        m_free_tail = NONE;
19,240✔
398
        _RYML_CB_ASSERT(m_callbacks, m_size == m_cap);
19,240✔
399
    }
400

401
    _clear(ichild);
2,586,944✔
402

403
    return ichild;
2,586,944✔
404
}
405

406
//-----------------------------------------------------------------------------
407

408
C4_SUPPRESS_WARNING_GCC_PUSH
409
C4_SUPPRESS_WARNING_CLANG_PUSH
410
C4_SUPPRESS_WARNING_CLANG("-Wnull-dereference")
411
#if defined(__GNUC__)
412
#if (__GNUC__ >= 6)
413
C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
414
#endif
415
#if (__GNUC__ > 9)
416
C4_SUPPRESS_WARNING_GCC("-Wanalyzer-fd-leak")
417
#endif
418
#endif
419

420
void Tree::_set_hierarchy(id_type ichild, id_type iparent, id_type iprev_sibling)
2,588,048✔
421
{
422
    _RYML_CB_ASSERT(m_callbacks, ichild >= 0 && ichild < m_cap);
2,588,048✔
423
    _RYML_CB_ASSERT(m_callbacks, iparent == NONE || (iparent >= 0 && iparent < m_cap));
2,588,048✔
424
    _RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE || (iprev_sibling >= 0 && iprev_sibling < m_cap));
2,588,048✔
425

426
    NodeData *C4_RESTRICT child = _p(ichild);
2,588,048✔
427

428
    child->m_parent = iparent;
2,588,048✔
429
    child->m_prev_sibling = NONE;
2,588,048✔
430
    child->m_next_sibling = NONE;
2,588,048✔
431

432
    if(iparent == NONE)
2,588,048✔
433
    {
434
        _RYML_CB_ASSERT(m_callbacks, ichild == 0);
875,616✔
435
        _RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE);
875,616✔
436
    }
437

438
    if(iparent == NONE)
2,588,048✔
439
        return;
875,616✔
440

441
    id_type inext_sibling = iprev_sibling != NONE ? next_sibling(iprev_sibling) : first_child(iparent);
1,712,432✔
442
    NodeData *C4_RESTRICT parent = get(iparent);
1,712,432✔
443
    NodeData *C4_RESTRICT psib   = get(iprev_sibling);
1,712,432✔
444
    NodeData *C4_RESTRICT nsib   = get(inext_sibling);
1,712,432✔
445

446
    if(psib)
1,712,432✔
447
    {
448
        _RYML_CB_ASSERT(m_callbacks, next_sibling(iprev_sibling) == id(nsib));
898,656✔
449
        child->m_prev_sibling = id(psib);
898,656✔
450
        psib->m_next_sibling = id(child);
898,656✔
451
        _RYML_CB_ASSERT(m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling == NONE);
898,656✔
452
    }
453

454
    if(nsib)
1,712,432✔
455
    {
456
        _RYML_CB_ASSERT(m_callbacks, prev_sibling(inext_sibling) == id(psib));
1,032✔
457
        child->m_next_sibling = id(nsib);
1,032✔
458
        nsib->m_prev_sibling = id(child);
1,032✔
459
        _RYML_CB_ASSERT(m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling == NONE);
1,032✔
460
    }
461

462
    if(parent->m_first_child == NONE)
1,712,432✔
463
    {
464
        _RYML_CB_ASSERT(m_callbacks, parent->m_last_child == NONE);
813,304✔
465
        parent->m_first_child = id(child);
813,304✔
466
        parent->m_last_child = id(child);
813,304✔
467
    }
468
    else
469
    {
470
        if(child->m_next_sibling == parent->m_first_child)
899,128✔
471
            parent->m_first_child = id(child);
472✔
472

473
        if(child->m_prev_sibling == parent->m_last_child)
899,128✔
474
            parent->m_last_child = id(child);
898,096✔
475
    }
476
}
477

478
C4_SUPPRESS_WARNING_GCC_POP
479
C4_SUPPRESS_WARNING_CLANG_POP
480

481

482
//-----------------------------------------------------------------------------
483
void Tree::_rem_hierarchy(id_type i)
162,296✔
484
{
485
    _RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);
162,296✔
486

487
    NodeData &C4_RESTRICT w = m_buf[i];
162,296✔
488

489
    // remove from the parent
490
    if(w.m_parent != NONE)
162,296✔
491
    {
492
        NodeData &C4_RESTRICT p = m_buf[w.m_parent];
162,152✔
493
        if(p.m_first_child == i)
162,152✔
494
        {
495
            p.m_first_child = w.m_next_sibling;
14,400✔
496
        }
497
        if(p.m_last_child == i)
162,152✔
498
        {
499
            p.m_last_child = w.m_prev_sibling;
159,648✔
500
        }
501
    }
502

503
    // remove from the used list
504
    if(w.m_prev_sibling != NONE)
162,296✔
505
    {
506
        NodeData *C4_RESTRICT prev = get(w.m_prev_sibling);
147,864✔
507
        prev->m_next_sibling = w.m_next_sibling;
147,864✔
508
    }
509
    if(w.m_next_sibling != NONE)
162,296✔
510
    {
511
        NodeData *C4_RESTRICT next = get(w.m_next_sibling);
2,648✔
512
        next->m_prev_sibling = w.m_prev_sibling;
2,648✔
513
    }
514
}
162,296✔
515

516
//-----------------------------------------------------------------------------
517
/** @cond dev */
518
id_type Tree::_do_reorder(id_type *node, id_type count)
3,584✔
519
{
520
    // swap this node if it's not in place
521
    if(*node != count)
3,584✔
522
    {
523
        _swap(*node, count);
768✔
524
        *node = count;
768✔
525
    }
526
    ++count; // bump the count from this node
3,584✔
527

528
    // now descend in the hierarchy
529
    for(id_type i = first_child(*node); i != NONE; i = next_sibling(i))
6,960✔
530
    {
531
        // this child may have been relocated to a different index,
532
        // so get an updated version
533
        count = _do_reorder(&i, count);
3,376✔
534
    }
535
    return count;
3,584✔
536
}
537
/** @endcond */
538

539
void Tree::reorder()
208✔
540
{
541
    id_type r = root_id();
208✔
542
    _do_reorder(&r, 0);
208✔
543
}
208✔
544

545

546
//-----------------------------------------------------------------------------
547
/** @cond dev */
548
void Tree::_swap(id_type n_, id_type m_)
768✔
549
{
550
    _RYML_CB_ASSERT(m_callbacks, (parent(n_) != NONE) || type(n_) == NOTYPE);
768✔
551
    _RYML_CB_ASSERT(m_callbacks, (parent(m_) != NONE) || type(m_) == NOTYPE);
912✔
552
    NodeType tn = type(n_);
768✔
553
    NodeType tm = type(m_);
768✔
554
    if(tn != NOTYPE && tm != NOTYPE)
1,536✔
555
    {
556
        _swap_props(n_, m_);
624✔
557
        _swap_hierarchy(n_, m_);
624✔
558
    }
559
    else if(tn == NOTYPE && tm != NOTYPE)
144✔
560
    {
561
        _copy_props(n_, m_);
×
562
        _free_list_rem(n_);
×
563
        _copy_hierarchy(n_, m_);
×
564
        _clear(m_);
×
565
        _free_list_add(m_);
×
566
    }
567
    else if(tn != NOTYPE && tm == NOTYPE)
288✔
568
    {
569
        _copy_props(m_, n_);
144✔
570
        _free_list_rem(m_);
144✔
571
        _copy_hierarchy(m_, n_);
144✔
572
        _clear(n_);
144✔
573
        _free_list_add(n_);
144✔
574
    }
575
    else
576
    {
577
        C4_NEVER_REACH();
×
578
    }
579
}
768✔
580

581
//-----------------------------------------------------------------------------
582
void Tree::_swap_hierarchy(id_type ia, id_type ib)
624✔
583
{
584
    if(ia == ib) return;
624✔
585

586
    for(id_type i = first_child(ia); i != NONE; i = next_sibling(i))
912✔
587
    {
588
        if(i == ib || i == ia)
288✔
589
            continue;
16✔
590
        _p(i)->m_parent = ib;
272✔
591
    }
592

593
    for(id_type i = first_child(ib); i != NONE; i = next_sibling(i))
1,408✔
594
    {
595
        if(i == ib || i == ia)
784✔
596
            continue;
×
597
        _p(i)->m_parent = ia;
784✔
598
    }
599

600
    auto & C4_RESTRICT a  = *_p(ia);
624✔
601
    auto & C4_RESTRICT b  = *_p(ib);
624✔
602
    auto & C4_RESTRICT pa = *_p(a.m_parent);
624✔
603
    auto & C4_RESTRICT pb = *_p(b.m_parent);
624✔
604

605
    if(&pa == &pb)
624✔
606
    {
607
        if((pa.m_first_child == ib && pa.m_last_child == ia)
112✔
608
            ||
112✔
609
           (pa.m_first_child == ia && pa.m_last_child == ib))
112✔
610
        {
611
            std::swap(pa.m_first_child, pa.m_last_child);
16✔
612
        }
613
        else
614
        {
615
            bool changed = false;
96✔
616
            if(pa.m_first_child == ia)
96✔
617
            {
618
                pa.m_first_child = ib;
32✔
619
                changed = true;
32✔
620
            }
621
            if(pa.m_last_child  == ia)
96✔
622
            {
623
                pa.m_last_child = ib;
×
624
                changed = true;
×
625
            }
626
            if(pb.m_first_child == ib && !changed)
96✔
627
            {
628
                pb.m_first_child = ia;
×
629
            }
630
            if(pb.m_last_child  == ib && !changed)
96✔
631
            {
632
                pb.m_last_child  = ia;
48✔
633
            }
634
        }
635
    }
636
    else
637
    {
638
        if(pa.m_first_child == ia)
512✔
639
            pa.m_first_child = ib;
176✔
640
        if(pa.m_last_child  == ia)
512✔
641
            pa.m_last_child  = ib;
176✔
642
        if(pb.m_first_child == ib)
512✔
643
            pb.m_first_child = ia;
208✔
644
        if(pb.m_last_child  == ib)
512✔
645
            pb.m_last_child  = ia;
288✔
646
    }
647
    std::swap(a.m_first_child , b.m_first_child);
624✔
648
    std::swap(a.m_last_child  , b.m_last_child);
624✔
649

650
    if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
624✔
651
       a.m_next_sibling != ib && b.m_next_sibling != ia)
544✔
652
    {
653
        if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib)
544✔
654
            _p(a.m_prev_sibling)->m_next_sibling = ib;
336✔
655
        if(a.m_next_sibling != NONE && a.m_next_sibling != ib)
544✔
656
            _p(a.m_next_sibling)->m_prev_sibling = ib;
368✔
657
        if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia)
544✔
658
            _p(b.m_prev_sibling)->m_next_sibling = ia;
336✔
659
        if(b.m_next_sibling != NONE && b.m_next_sibling != ia)
544✔
660
            _p(b.m_next_sibling)->m_prev_sibling = ia;
240✔
661
        std::swap(a.m_prev_sibling, b.m_prev_sibling);
544✔
662
        std::swap(a.m_next_sibling, b.m_next_sibling);
544✔
663
    }
664
    else
665
    {
666
        if(a.m_next_sibling == ib) // n will go after m
80✔
667
        {
668
            _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling == ia);
80✔
669
            if(a.m_prev_sibling != NONE)
80✔
670
            {
671
                _RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ib);
64✔
672
                _p(a.m_prev_sibling)->m_next_sibling = ib;
64✔
673
            }
674
            if(b.m_next_sibling != NONE)
80✔
675
            {
676
                _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ia);
32✔
677
                _p(b.m_next_sibling)->m_prev_sibling = ia;
32✔
678
            }
679
            id_type ns = b.m_next_sibling;
80✔
680
            b.m_prev_sibling = a.m_prev_sibling;
80✔
681
            b.m_next_sibling = ia;
80✔
682
            a.m_prev_sibling = ib;
80✔
683
            a.m_next_sibling = ns;
80✔
684
        }
685
        else if(a.m_prev_sibling == ib) // m will go after n
×
686
        {
687
            _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling == ia);
×
688
            if(b.m_prev_sibling != NONE)
×
689
            {
690
                _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ia);
×
691
                _p(b.m_prev_sibling)->m_next_sibling = ia;
×
692
            }
693
            if(a.m_next_sibling != NONE)
×
694
            {
695
                _RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ib);
×
696
                _p(a.m_next_sibling)->m_prev_sibling = ib;
×
697
            }
698
            id_type ns = b.m_prev_sibling;
×
699
            a.m_prev_sibling = b.m_prev_sibling;
×
700
            a.m_next_sibling = ib;
×
701
            b.m_prev_sibling = ia;
×
702
            b.m_next_sibling = ns;
×
703
        }
704
        else
705
        {
706
            C4_NEVER_REACH();
×
707
        }
708
    }
709
    _RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ia);
624✔
710
    _RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ia);
624✔
711
    _RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ib);
624✔
712
    _RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ib);
624✔
713

714
    if(a.m_parent != ib && b.m_parent != ia)
624✔
715
    {
716
        std::swap(a.m_parent, b.m_parent);
608✔
717
    }
718
    else
719
    {
720
        if(a.m_parent == ib && b.m_parent != ia)
16✔
721
        {
722
            a.m_parent = b.m_parent;
×
723
            b.m_parent = ia;
×
724
        }
725
        else if(a.m_parent != ib && b.m_parent == ia)
16✔
726
        {
727
            b.m_parent = a.m_parent;
16✔
728
            a.m_parent = ib;
16✔
729
        }
730
        else
731
        {
732
            C4_NEVER_REACH();
×
733
        }
734
    }
735
}
736

737
//-----------------------------------------------------------------------------
738
void Tree::_copy_hierarchy(id_type dst_, id_type src_)
144✔
739
{
740
    auto const& C4_RESTRICT src = *_p(src_);
144✔
741
    auto      & C4_RESTRICT dst = *_p(dst_);
144✔
742
    auto      & C4_RESTRICT prt = *_p(src.m_parent);
144✔
743
    for(id_type i = src.m_first_child; i != NONE; i = next_sibling(i))
272✔
744
    {
745
        _p(i)->m_parent = dst_;
128✔
746
    }
747
    if(src.m_prev_sibling != NONE)
144✔
748
    {
749
        _p(src.m_prev_sibling)->m_next_sibling = dst_;
96✔
750
    }
751
    if(src.m_next_sibling != NONE)
144✔
752
    {
753
        _p(src.m_next_sibling)->m_prev_sibling = dst_;
96✔
754
    }
755
    if(prt.m_first_child == src_)
144✔
756
    {
757
        prt.m_first_child = dst_;
48✔
758
    }
759
    if(prt.m_last_child  == src_)
144✔
760
    {
761
        prt.m_last_child  = dst_;
48✔
762
    }
763
    dst.m_parent       = src.m_parent;
144✔
764
    dst.m_first_child  = src.m_first_child;
144✔
765
    dst.m_last_child   = src.m_last_child;
144✔
766
    dst.m_prev_sibling = src.m_prev_sibling;
144✔
767
    dst.m_next_sibling = src.m_next_sibling;
144✔
768
}
144✔
769

770
//-----------------------------------------------------------------------------
771
void Tree::_swap_props(id_type n_, id_type m_)
624✔
772
{
773
    NodeData &C4_RESTRICT n = *_p(n_);
624✔
774
    NodeData &C4_RESTRICT m = *_p(m_);
624✔
775
    std::swap(n.m_type, m.m_type);
624✔
776
    std::swap(n.m_key, m.m_key);
624✔
777
    std::swap(n.m_val, m.m_val);
624✔
778
}
624✔
779
/** @endcond */
780

781
//-----------------------------------------------------------------------------
782
void Tree::move(id_type node, id_type after)
64✔
783
{
784
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
64✔
785
    _RYML_CB_ASSERT(m_callbacks, node != after);
64✔
786
    _RYML_CB_ASSERT(m_callbacks,  ! is_root(node));
64✔
787
    _RYML_CB_ASSERT(m_callbacks, (after == NONE) || (has_sibling(node, after) && has_sibling(after, node)));
64✔
788

789
    _rem_hierarchy(node);
64✔
790
    _set_hierarchy(node, parent(node), after);
64✔
791
}
64✔
792

793
//-----------------------------------------------------------------------------
794

795
void Tree::move(id_type node, id_type new_parent, id_type after)
1,040✔
796
{
797
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
1,040✔
798
    _RYML_CB_ASSERT(m_callbacks, node != after);
1,040✔
799
    _RYML_CB_ASSERT(m_callbacks, new_parent != NONE);
1,040✔
800
    _RYML_CB_ASSERT(m_callbacks, new_parent != node);
1,040✔
801
    _RYML_CB_ASSERT(m_callbacks, new_parent != after);
1,040✔
802
    _RYML_CB_ASSERT(m_callbacks,  ! is_root(node));
1,040✔
803

804
    _rem_hierarchy(node);
1,040✔
805
    _set_hierarchy(node, new_parent, after);
1,040✔
806
}
1,040✔
807

808
id_type Tree::move(Tree *src, id_type node, id_type new_parent, id_type after)
32✔
809
{
810
    _RYML_CB_ASSERT(m_callbacks, src != nullptr);
32✔
811
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
32✔
812
    _RYML_CB_ASSERT(m_callbacks, new_parent != NONE);
32✔
813
    _RYML_CB_ASSERT(m_callbacks, new_parent != after);
32✔
814

815
    id_type dup = duplicate(src, node, new_parent, after);
32✔
816
    src->remove(node);
32✔
817
    return dup;
32✔
818
}
819

820
void Tree::set_root_as_stream()
133,616✔
821
{
822
    id_type root = root_id();
133,616✔
823
    if(is_stream(root))
133,616✔
824
        return;
576✔
825
    // don't use _add_flags() because it's checked and will fail
826
    if(!has_children(root))
133,040✔
827
    {
828
        if(is_val(root))
132,208✔
829
        {
830
            _p(root)->m_type.add(SEQ);
132,200✔
831
            id_type next_doc = append_child(root);
132,200✔
832
            _copy_props_wo_key(next_doc, root);
132,200✔
833
            _p(next_doc)->m_type.add(DOC);
132,200✔
834
            _p(next_doc)->m_type.rem(SEQ);
132,200✔
835
        }
836
        _p(root)->m_type = STREAM;
132,208✔
837
        return;
132,208✔
838
    }
839
    _RYML_CB_ASSERT(m_callbacks, !has_key(root));
832✔
840
    id_type next_doc = append_child(root);
832✔
841
    _copy_props_wo_key(next_doc, root);
832✔
842
    _add_flags(next_doc, DOC);
832✔
843
    for(id_type prev = NONE, ch = first_child(root), next = next_sibling(ch); ch != NONE; )
1,848✔
844
    {
845
        if(ch == next_doc)
1,848✔
846
            break;
832✔
847
        move(ch, next_doc, prev);
1,016✔
848
        prev = ch;
1,016✔
849
        ch = next;
1,016✔
850
        next = next_sibling(next);
1,016✔
851
    }
852
    _p(root)->m_type = STREAM;
832✔
853
}
854

855

856
//-----------------------------------------------------------------------------
857
void Tree::remove_children(id_type node)
161,192✔
858
{
859
    _RYML_CB_ASSERT(m_callbacks, get(node) != nullptr);
161,192✔
860
    id_type ich = get(node)->m_first_child;
161,192✔
861
    while(ich != NONE)
162,560✔
862
    {
863
        remove_children(ich);
1,368✔
864
        _RYML_CB_ASSERT(m_callbacks, get(ich) != nullptr);
1,368✔
865
        id_type next = get(ich)->m_next_sibling;
1,368✔
866
        _release(ich);
1,368✔
867
        if(ich == get(node)->m_last_child)
1,368✔
868
            break;
×
869
        ich = next;
1,368✔
870
    }
871
}
161,192✔
872

873
bool Tree::change_type(id_type node, NodeType type)
144✔
874
{
875
    _RYML_CB_ASSERT(m_callbacks, type.is_val() || type.is_map() || type.is_seq());
288✔
876
    _RYML_CB_ASSERT(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1);
432✔
877
    _RYML_CB_ASSERT(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()));
432✔
878
    NodeData *d = _p(node);
144✔
879
    if(type.is_map() && is_map(node))
192✔
880
        return false;
16✔
881
    else if(type.is_seq() && is_seq(node))
176✔
882
        return false;
16✔
883
    else if(type.is_val() && is_val(node))
160✔
884
        return false;
8✔
885
    d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type;
728✔
886
    remove_children(node);
104✔
887
    return true;
104✔
888
}
889

890

891
//-----------------------------------------------------------------------------
892
id_type Tree::duplicate(id_type node, id_type parent, id_type after)
24✔
893
{
894
    return duplicate(this, node, parent, after);
24✔
895
}
896

897
id_type Tree::duplicate(Tree const* src, id_type node, id_type parent, id_type after)
2,208✔
898
{
899
    _RYML_CB_ASSERT(m_callbacks, src != nullptr);
2,208✔
900
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
2,208✔
901
    _RYML_CB_ASSERT(m_callbacks, parent != NONE);
2,208✔
902
    _RYML_CB_ASSERT(m_callbacks,  ! src->is_root(node));
2,208✔
903

904
    id_type copy = _claim();
2,208✔
905

906
    _copy_props(copy, src, node);
2,208✔
907
    _set_hierarchy(copy, parent, after);
2,208✔
908
    duplicate_children(src, node, copy, NONE);
2,208✔
909

910
    return copy;
2,208✔
911
}
912

913
//-----------------------------------------------------------------------------
914
id_type Tree::duplicate_children(id_type node, id_type parent, id_type after)
×
915
{
916
    return duplicate_children(this, node, parent, after);
×
917
}
918

919
id_type Tree::duplicate_children(Tree const* src, id_type node, id_type parent, id_type after)
2,632✔
920
{
921
    _RYML_CB_ASSERT(m_callbacks, src != nullptr);
2,632✔
922
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
2,632✔
923
    _RYML_CB_ASSERT(m_callbacks, parent != NONE);
2,632✔
924
    _RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after));
2,632✔
925

926
    id_type prev = after;
2,632✔
927
    for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
4,216✔
928
    {
929
        prev = duplicate(src, i, parent, prev);
1,584✔
930
    }
931

932
    return prev;
2,632✔
933
}
934

935
//-----------------------------------------------------------------------------
936
void Tree::duplicate_contents(id_type node, id_type where)
424✔
937
{
938
    duplicate_contents(this, node, where);
424✔
939
}
424✔
940

941
void Tree::duplicate_contents(Tree const *src, id_type node, id_type where)
424✔
942
{
943
    _RYML_CB_ASSERT(m_callbacks, src != nullptr);
424✔
944
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
424✔
945
    _RYML_CB_ASSERT(m_callbacks, where != NONE);
424✔
946
    _copy_props_wo_key(where, src, node);
424✔
947
    duplicate_children(src, node, where, last_child(where));
424✔
948
}
424✔
949

950
//-----------------------------------------------------------------------------
951
id_type Tree::duplicate_children_no_rep(id_type node, id_type parent, id_type after)
392✔
952
{
953
    return duplicate_children_no_rep(this, node, parent, after);
392✔
954
}
955

956
id_type Tree::duplicate_children_no_rep(Tree const *src, id_type node, id_type parent, id_type after)
392✔
957
{
958
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
392✔
959
    _RYML_CB_ASSERT(m_callbacks, parent != NONE);
392✔
960
    _RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after));
392✔
961

962
    // don't loop using pointers as there may be a relocation
963

964
    // find the position where "after" is
965
    id_type after_pos = NONE;
392✔
966
    if(after != NONE)
392✔
967
    {
968
        for(id_type i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))
328✔
969
        {
970
            if(i == after)
328✔
971
            {
972
                after_pos = icount;
176✔
973
                break;
176✔
974
            }
975
        }
976
        _RYML_CB_ASSERT(m_callbacks, after_pos != NONE);
176✔
977
    }
978

979
    // for each child to be duplicated...
980
    id_type prev = after;
392✔
981
    for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
976✔
982
    {
983
        _c4dbgpf("duplicate_no_rep: {} -> {}/{}", i, parent, prev);
300✔
984
        _RYML_CB_CHECK(m_callbacks, this != src || (parent != i && !is_ancestor(parent, i)));
600✔
985
        if(is_seq(parent))
876✔
986
        {
987
            _c4dbgpf("duplicate_no_rep: {} is seq", parent);
NEW
988
            prev = duplicate(src, i, parent, prev);
×
989
        }
990
        else
991
        {
992
            _c4dbgpf("duplicate_no_rep: {} is map", parent);
292✔
993
            _RYML_CB_ASSERT(m_callbacks, is_map(parent));
876✔
994
            // does the parent already have a node with key equal to that of the current duplicate?
995
            id_type dstnode_dup = NONE, dstnode_dup_pos = NONE;
584✔
996
            {
997
                csubstr srckey = src->key(i);
584✔
998
                for(id_type j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j))
1,944✔
999
                {
1000
                    if(key(j) == srckey)
2,960✔
1001
                    {
1002
                        _c4dbgpf("duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i, parent, j);
60✔
1003
                        dstnode_dup = j;
120✔
1004
                        dstnode_dup_pos = jcount;
120✔
1005
                        break;
120✔
1006
                    }
1007
                }
1008
            }
1009
            _c4dbgpf("duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos);
292✔
1010
            if(dstnode_dup == NONE) // there is no repetition; just duplicate
584✔
1011
            {
1012
                _c4dbgpf("duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i, parent, prev);
232✔
1013
                prev = duplicate(src, i, parent, prev);
464✔
1014
            }
1015
            else  // yes, there is a repetition
1016
            {
1017
                if(after_pos != NONE && dstnode_dup_pos <= after_pos)
120✔
1018
                {
1019
                    // the dst duplicate is located before the node which will be inserted,
1020
                    // and will be overridden by the duplicate. So replace it.
1021
                    _c4dbgpf("duplicate_no_dstnode_dup: replace {}/{} with {}/{}", parent, dstnode_dup, node, i);
40✔
1022
                    if(prev == dstnode_dup)
80✔
1023
                        prev = prev_sibling(dstnode_dup);
32✔
1024
                    remove(dstnode_dup);
80✔
1025
                    prev = duplicate(src, i, parent, prev);
80✔
1026
                }
1027
                else if(prev == NONE)
40✔
1028
                {
1029
                    _c4dbgpf("duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup);
4✔
1030
                    // first iteration with prev = after = NONE and dstnode_dupetition
1031
                    prev = dstnode_dup;
8✔
1032
                }
1033
                else if(dstnode_dup != prev)
32✔
1034
                {
1035
                    // dstnode_dup is located after the node which will be inserted
1036
                    // and overrides it. So move the dstnode_dup into this node's place.
1037
                    _c4dbgpf("duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev);
16✔
1038
                    move(dstnode_dup, prev);
32✔
1039
                    prev = dstnode_dup;
32✔
1040
                }
1041
                else {
1042
                    _c4dbgpf("duplicate_no_dstnode_dup: wtf", dstnode_dup, prev);
1043
                }
1044
            } // there's a dstnode_dupetition
1045
        }
1046
    }
1047

1048
    return prev;
376✔
1049
}
1050

1051

1052
//-----------------------------------------------------------------------------
1053

1054
void Tree::merge_with(Tree const *src, id_type src_node, id_type dst_node)
1,472✔
1055
{
1056
    _RYML_CB_ASSERT(m_callbacks, src != nullptr);
1,472✔
1057
    if(src_node == NONE)
1,472✔
1058
        src_node = src->root_id();
480✔
1059
    if(dst_node == NONE)
1,472✔
1060
        dst_node = root_id();
480✔
1061
    _RYML_CB_ASSERT(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node));
2,440✔
1062
    if(src->has_val(src_node))
1,472✔
1063
    {
1064
        type_bits mask_src = ~STYLE; // keep the existing style if it is already a val
912✔
1065
        if( ! has_val(dst_node))
912✔
1066
        {
1067
            if(has_children(dst_node))
24✔
1068
                remove_children(dst_node);
24✔
1069
            mask_src |= VAL_STYLE; // copy the src style
24✔
1070
        }
1071
        if(src->is_keyval(src_node))
912✔
1072
        {
1073
            _copy_props(dst_node, src, src_node, mask_src);
536✔
1074
        }
1075
        else
1076
        {
1077
            _RYML_CB_ASSERT(m_callbacks, src->is_val(src_node));
376✔
1078
            _copy_props_wo_key(dst_node, src, src_node, mask_src);
376✔
1079
        }
1080
    }
1081
    else if(src->is_seq(src_node))
560✔
1082
    {
1083
        if( ! is_seq(dst_node))
152✔
1084
        {
1085
            if(has_children(dst_node))
48✔
UNCOV
1086
                remove_children(dst_node);
×
1087
            _clear_type(dst_node);
48✔
1088
            if(src->has_key(src_node))
48✔
1089
                to_seq(dst_node, src->key(src_node));
16✔
1090
            else
1091
                to_seq(dst_node);
32✔
1092
            _p(dst_node)->m_type = src->_p(src_node)->m_type;
48✔
1093
        }
1094
        for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
528✔
1095
        {
1096
            id_type dch = append_child(dst_node);
376✔
1097
            _copy_props_wo_key(dch, src, sch);
376✔
1098
            merge_with(src, sch, dch);
376✔
1099
        }
1100
    }
1101
    else
1102
    {
1103
        _RYML_CB_ASSERT(m_callbacks, src->is_map(src_node));
408✔
1104
        if( ! is_map(dst_node))
408✔
1105
        {
1106
            if(has_children(dst_node))
152✔
1107
                remove_children(dst_node);
8✔
1108
            _clear_type(dst_node);
152✔
1109
            if(src->has_key(src_node))
152✔
1110
                to_map(dst_node, src->key(src_node));
16✔
1111
            else
1112
                to_map(dst_node);
136✔
1113
            _p(dst_node)->m_type = src->_p(src_node)->m_type;
152✔
1114
        }
1115
        for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
1,016✔
1116
        {
1117
            id_type dch = find_child(dst_node, src->key(sch));
608✔
1118
            if(dch == NONE)
608✔
1119
            {
1120
                dch = append_child(dst_node);
392✔
1121
                _copy_props(dch, src, sch);
392✔
1122
            }
1123
            merge_with(src, sch, dch);
608✔
1124
        }
1125
    }
1126
}
1,472✔
1127

1128

1129
//-----------------------------------------------------------------------------
1130

1131
void Tree::resolve(bool clear_anchors)
448✔
1132
{
1133
    if(m_size == 0)
448✔
1134
        return;
8✔
1135
    ReferenceResolver rr;
440✔
1136
    resolve(&rr, clear_anchors);
440✔
1137
}
440✔
1138

1139
void Tree::resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors)
440✔
1140
{
1141
    if(m_size == 0)
440✔
UNCOV
1142
        return;
×
1143
    rr->resolve(this, clear_anchors);
440✔
1144
}
1145

1146

1147
//-----------------------------------------------------------------------------
1148

1149
id_type Tree::num_children(id_type node) const
12,690,288✔
1150
{
1151
    id_type count = 0;
12,690,288✔
1152
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
49,906,912✔
1153
        ++count;
37,216,624✔
1154
    return count;
12,690,272✔
1155
}
1156

1157
id_type Tree::child(id_type node, id_type pos) const
3,117,856✔
1158
{
1159
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
3,117,856✔
1160
    id_type count = 0;
3,117,848✔
1161
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
11,435,208✔
1162
    {
1163
        if(count++ == pos)
11,434,208✔
1164
            return i;
3,116,848✔
1165
    }
1166
    return NONE;
992✔
1167
}
1168

1169
id_type Tree::child_pos(id_type node, id_type ch) const
32✔
1170
{
1171
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
32✔
1172
    id_type count = 0;
32✔
1173
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
32✔
1174
    {
1175
        if(i == ch)
32✔
1176
            return count;
32✔
UNCOV
1177
        ++count;
×
1178
    }
UNCOV
1179
    return NONE;
×
1180
}
1181

1182
#if defined(__clang__)
1183
#   pragma clang diagnostic push
1184
#   pragma GCC diagnostic ignored "-Wnull-dereference"
1185
#elif defined(__GNUC__)
1186
#   pragma GCC diagnostic push
1187
#   if __GNUC__ >= 6
1188
#       pragma GCC diagnostic ignored "-Wnull-dereference"
1189
#   endif
1190
#   if __GNUC__ > 9
1191
#       pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
1192
#   endif
1193
#endif
1194

1195
id_type Tree::find_child(id_type node, csubstr const& name) const
2,759,968✔
1196
{
1197
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
2,759,968✔
1198
    _RYML_CB_ASSERT(m_callbacks, is_map(node));
2,759,952✔
1199
    if(get(node)->m_first_child == NONE)
2,759,944✔
1200
    {
1201
        _RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child == NONE);
616✔
1202
        return NONE;
616✔
1203
    }
1204
    else
1205
    {
1206
        _RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child != NONE);
2,759,328✔
1207
    }
1208
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
13,976,368✔
1209
    {
1210
        if(_p(i)->m_key.scalar == name)
27,949,104✔
1211
        {
1212
            return i;
2,757,512✔
1213
        }
1214
    }
1215
    return NONE;
1,816✔
1216
}
1217

1218
#if defined(__clang__)
1219
#   pragma clang diagnostic pop
1220
#elif defined(__GNUC__)
1221
#   pragma GCC diagnostic pop
1222
#endif
1223

1224
namespace {
1225
id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0)
2,928✔
1226
{
1227
    maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
2,928✔
1228
    for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
4,888✔
1229
    {
1230
        const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
1,960✔
1231
        maxdepth = d > maxdepth ? d : maxdepth;
1,960✔
1232
    }
1233
    return maxdepth;
2,920✔
1234
}
1235
}
1236

1237
id_type Tree::depth_desc(id_type node) const
976✔
1238
{
1239
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
976✔
1240
    return depth_desc_(*this, node);
968✔
1241
}
1242

1243
id_type Tree::depth_asc(id_type node) const
160✔
1244
{
1245
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
160✔
1246
    id_type depth = 0;
152✔
1247
    while(!is_root(node))
416✔
1248
    {
1249
        ++depth;
264✔
1250
        node = parent(node);
264✔
1251
    }
1252
    return depth;
144✔
1253
}
1254

1255
bool Tree::is_ancestor(id_type node, id_type ancestor) const
584✔
1256
{
1257
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
584✔
1258
    id_type p = parent(node);
584✔
1259
    while(!is_root(p))
664✔
1260
    {
1261
        if(p == ancestor)
80✔
NEW
1262
            return true;
×
1263
        p = parent(p);
80✔
1264
    }
1265
    return false;
584✔
1266
}
1267

1268

1269
//-----------------------------------------------------------------------------
1270

1271
void Tree::to_val(id_type node, csubstr val, type_bits more_flags)
20,888✔
1272
{
1273
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
20,888✔
1274
    _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node));
39,232✔
1275
    _set_flags(node, VAL|more_flags);
20,888✔
1276
    _p(node)->m_key.clear();
20,888✔
1277
    _p(node)->m_val = val;
20,888✔
1278
}
20,888✔
1279

1280
void Tree::to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags)
25,976✔
1281
{
1282
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
25,976✔
1283
    _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));
51,952✔
1284
    _set_flags(node, KEYVAL|more_flags);
25,976✔
1285
    _p(node)->m_key = key;
25,976✔
1286
    _p(node)->m_val = val;
25,976✔
1287
}
25,976✔
1288

1289
void Tree::to_map(id_type node, type_bits more_flags)
8,160✔
1290
{
1291
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
8,160✔
1292
    _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node)); // parent must not have children with keys
16,168✔
1293
    _set_flags(node, MAP|more_flags);
8,160✔
1294
    _p(node)->m_key.clear();
8,160✔
1295
    _p(node)->m_val.clear();
8,160✔
1296
}
8,160✔
1297

1298
void Tree::to_map(id_type node, csubstr key, type_bits more_flags)
2,504✔
1299
{
1300
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
2,504✔
1301
    _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));
5,008✔
1302
    _set_flags(node, KEY|MAP|more_flags);
2,504✔
1303
    _p(node)->m_key = key;
2,504✔
1304
    _p(node)->m_val.clear();
2,504✔
1305
}
2,504✔
1306

1307
void Tree::to_seq(id_type node, type_bits more_flags)
3,216✔
1308
{
1309
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
3,216✔
1310
    _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_seq(node));
6,400✔
1311
    _set_flags(node, SEQ|more_flags);
3,216✔
1312
    _p(node)->m_key.clear();
3,216✔
1313
    _p(node)->m_val.clear();
3,216✔
1314
}
3,216✔
1315

1316
void Tree::to_seq(id_type node, csubstr key, type_bits more_flags)
2,608✔
1317
{
1318
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
2,608✔
1319
    _RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));
5,216✔
1320
    _set_flags(node, KEY|SEQ|more_flags);
2,608✔
1321
    _p(node)->m_key = key;
2,608✔
1322
    _p(node)->m_val.clear();
2,608✔
1323
}
2,608✔
1324

1325
void Tree::to_doc(id_type node, type_bits more_flags)
9,032✔
1326
{
1327
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
9,032✔
1328
    _set_flags(node, DOC|more_flags);
9,032✔
1329
    _p(node)->m_key.clear();
9,032✔
1330
    _p(node)->m_val.clear();
9,032✔
1331
}
9,032✔
1332

1333
void Tree::to_stream(id_type node, type_bits more_flags)
8✔
1334
{
1335
    _RYML_CB_ASSERT(m_callbacks,  ! has_children(node));
8✔
1336
    _set_flags(node, STREAM|more_flags);
8✔
1337
    _p(node)->m_key.clear();
8✔
1338
    _p(node)->m_val.clear();
8✔
1339
}
8✔
1340

1341

1342
//-----------------------------------------------------------------------------
1343
id_type Tree::num_tag_directives() const
2,234,680✔
1344
{
1345
    // this assumes we have a very small number of tag directives
1346
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
2,260,256✔
1347
        if(m_tag_directives[i].handle.empty())
4,520,464✔
1348
            return i;
2,234,656✔
1349
    return RYML_MAX_TAG_DIRECTIVES;
24✔
1350
}
1351

1352
void Tree::clear_tag_directives()
8✔
1353
{
1354
    for(TagDirective &td : m_tag_directives)
40✔
1355
        td = {};
32✔
1356
}
8✔
1357

1358
id_type Tree::add_tag_directive(TagDirective const& td)
5,648✔
1359
{
1360
    _RYML_CB_CHECK(m_callbacks, !td.handle.empty());
11,296✔
1361
    _RYML_CB_CHECK(m_callbacks, !td.prefix.empty());
11,296✔
1362
    _RYML_CB_CHECK(m_callbacks, td.handle.begins_with('!'));
5,640✔
1363
    _RYML_CB_CHECK(m_callbacks, td.handle.ends_with('!'));
5,640✔
1364
    // https://yaml.org/spec/1.2.2/#rule-ns-word-char
1365
    _RYML_CB_CHECK(m_callbacks, td.handle == '!' || td.handle == "!!" || td.handle.trim('!').first_not_of("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-") == npos);
18,568✔
1366
    id_type pos = num_tag_directives();
5,640✔
1367
    _RYML_CB_CHECK(m_callbacks, pos < RYML_MAX_TAG_DIRECTIVES);
5,640✔
1368
    m_tag_directives[pos] = td;
5,632✔
1369
    return pos;
5,632✔
1370
}
1371

1372
bool Tree::add_tag_directive(csubstr directive_)
5,608✔
1373
{
1374
    TagDirective td;
5,608✔
1375
    if(td.create_from_str(directive_, this))
5,608✔
1376
    {
1377
        add_tag_directive(td);
5,592✔
1378
        return true;
5,584✔
1379
    }
UNCOV
1380
    return false;
×
1381
}
1382

1383
size_t Tree::resolve_tag(substr output, csubstr tag, id_type node_id) const
26,008✔
1384
{
1385
    // lookup from the end. We want to find the first directive that
1386
    // matches the tag and has a target node id leq than the given
1387
    // node_id.
1388
    for(id_type i = RYML_MAX_TAG_DIRECTIVES-1; i != (id_type)-1; --i)
119,312✔
1389
    {
1390
        auto const& td = m_tag_directives[i];
103,512✔
1391
        if(td.handle.empty())
207,024✔
1392
            continue;
80,280✔
1393
        if(tag.begins_with(td.handle) && td.next_node_id <= node_id)
23,232✔
1394
            return td.transform(tag, output, m_callbacks);
10,208✔
1395
    }
1396
    if(tag.begins_with('!'))
15,800✔
1397
    {
1398
        if(is_custom_tag(tag))
10,472✔
1399
        {
1400
            _RYML_CB_ERR(m_callbacks, "tag directive not found");
8✔
1401
        }
1402
    }
1403
    return 0; // return 0 to signal that the tag is local and cannot be resolved
15,792✔
1404
}
1405

1406
namespace {
1407
csubstr _transform_tag(Tree *t, csubstr tag, id_type node)
8,872✔
1408
{
1409
    _c4dbgpf("[{}] resolving tag ~~~{}~~~", node, tag);
4,436✔
1410
    size_t required_size = t->resolve_tag(substr{}, tag, node);
8,872✔
1411
    if(!required_size)
8,872✔
1412
    {
1413
        if(tag.begins_with("!<"))
7,144✔
1414
            tag = tag.sub(1);
5,432✔
1415
        _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, tag);
3,572✔
1416
        return tag;
7,144✔
1417
    }
1418
    const char *prev_arena = t->arena().str;(void)prev_arena;
1,728✔
1419
    substr buf = t->alloc_arena(required_size);
1,728✔
1420
    _RYML_CB_ASSERT(t->m_callbacks, t->arena().str == prev_arena);
1,728✔
1421
    size_t actual_size = t->resolve_tag(buf, tag, node);
1,728✔
1422
    _RYML_CB_ASSERT(t->m_callbacks, actual_size <= required_size);
1,728✔
1423
    _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, buf.first(actual_size));
864✔
1424
    return buf.first(actual_size);
3,456✔
1425
}
1426
void _resolve_tags(Tree *t, id_type node)
20,200✔
1427
{
1428
    NodeData *C4_RESTRICT d = t->_p(node);
20,200✔
1429
    if(d->m_type & KEYTAG)
60,600✔
1430
        d->m_key.tag = _transform_tag(t, d->m_key.tag, node);
16✔
1431
    if(d->m_type & VALTAG)
60,600✔
1432
        d->m_val.tag = _transform_tag(t, d->m_val.tag, node);
8,856✔
1433
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
35,720✔
1434
        _resolve_tags(t, child);
15,520✔
1435
}
20,200✔
1436
size_t _count_resolved_tags_size(Tree const* t, id_type node)
20,352✔
1437
{
1438
    size_t sz = 0;
20,352✔
1439
    NodeData const* C4_RESTRICT d = t->_p(node);
20,352✔
1440
    if(d->m_type & KEYTAG)
61,056✔
1441
        sz += t->resolve_tag(substr{}, d->m_key.tag, node);
16✔
1442
    if(d->m_type & VALTAG)
61,056✔
1443
        sz += t->resolve_tag(substr{}, d->m_val.tag, node);
8,912✔
1444
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
35,816✔
1445
        sz += _count_resolved_tags_size(t, child);
15,616✔
1446
    return sz;
20,200✔
1447
}
1448
void _normalize_tags(Tree *t, id_type node)
168✔
1449
{
1450
    NodeData *C4_RESTRICT d = t->_p(node);
168✔
1451
    if(d->m_type & KEYTAG)
504✔
1452
        d->m_key.tag = normalize_tag(d->m_key.tag);
8✔
1453
    if(d->m_type & VALTAG)
504✔
1454
        d->m_val.tag = normalize_tag(d->m_val.tag);
80✔
1455
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
328✔
1456
        _normalize_tags(t, child);
160✔
1457
}
168✔
1458
void _normalize_tags_long(Tree *t, id_type node)
1,557,096✔
1459
{
1460
    NodeData *C4_RESTRICT d = t->_p(node);
1,557,096✔
1461
    if(d->m_type & KEYTAG)
4,671,288✔
1462
        d->m_key.tag = normalize_tag_long(d->m_key.tag);
11,272✔
1463
    if(d->m_type & VALTAG)
4,671,288✔
1464
        d->m_val.tag = normalize_tag_long(d->m_val.tag);
72,912✔
1465
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
2,697,608✔
1466
        _normalize_tags_long(t, child);
1,140,512✔
1467
}
1,557,096✔
1468
} // namespace
1469

1470
void Tree::resolve_tags()
4,744✔
1471
{
1472
    if(empty())
4,744✔
1473
        return;
8✔
1474
    size_t needed_size = _count_resolved_tags_size(this, root_id());
4,736✔
1475
    if(needed_size)
4,680✔
1476
        reserve_arena(arena_size() + needed_size);
1,184✔
1477
    _resolve_tags(this, root_id());
4,680✔
1478
}
1479

1480
void Tree::normalize_tags()
8✔
1481
{
1482
    if(empty())
8✔
UNCOV
1483
        return;
×
1484
    _normalize_tags(this, root_id());
8✔
1485
}
1486

1487
void Tree::normalize_tags_long()
416,584✔
1488
{
1489
    if(empty())
416,584✔
UNCOV
1490
        return;
×
1491
    _normalize_tags_long(this, root_id());
416,584✔
1492
}
1493

1494

1495
//-----------------------------------------------------------------------------
1496

1497
csubstr Tree::lookup_result::resolved() const
40✔
1498
{
1499
    csubstr p = path.first(path_pos);
40✔
1500
    if(p.ends_with('.'))
40✔
1501
        p = p.first(p.len-1);
48✔
1502
    return p;
40✔
1503
}
1504

1505
csubstr Tree::lookup_result::unresolved() const
5,312✔
1506
{
1507
    return path.sub(path_pos);
10,624✔
1508
}
1509

1510
void Tree::_advance(lookup_result *r, size_t more)
2,072✔
1511
{
1512
    r->path_pos += more;
2,072✔
1513
    if(r->path.sub(r->path_pos).begins_with('.'))
4,144✔
1514
        ++r->path_pos;
320✔
1515
}
2,072✔
1516

1517
Tree::lookup_result Tree::lookup_path(csubstr path, id_type start) const
344✔
1518
{
1519
    if(start == NONE)
344✔
1520
        start = root_id();
240✔
1521
    lookup_result r(path, start);
344✔
1522
    if(path.empty())
344✔
UNCOV
1523
        return r;
×
1524
    _lookup_path(&r);
344✔
1525
    if(r.target == NONE && r.closest == start)
344✔
1526
        r.closest = NONE;
24✔
1527
    return r;
344✔
1528
}
1529

1530
id_type Tree::lookup_path_or_modify(csubstr default_value, csubstr path, id_type start)
176✔
1531
{
1532
    id_type target = _lookup_path_or_create(path, start);
176✔
1533
    if(parent_is_map(target))
176✔
1534
        to_keyval(target, key(target), default_value);
112✔
1535
    else
1536
        to_val(target, default_value);
64✔
1537
    return target;
176✔
1538
}
1539

1540
id_type Tree::lookup_path_or_modify(Tree const *src, id_type src_node, csubstr path, id_type start)
8✔
1541
{
1542
    id_type target = _lookup_path_or_create(path, start);
8✔
1543
    merge_with(src, src_node, target);
8✔
1544
    return target;
8✔
1545
}
1546

1547
id_type Tree::_lookup_path_or_create(csubstr path, id_type start)
184✔
1548
{
1549
    if(start == NONE)
184✔
1550
        start = root_id();
184✔
1551
    lookup_result r(path, start);
184✔
1552
    _lookup_path(&r);
184✔
1553
    if(r.target != NONE)
184✔
1554
    {
1555
        C4_ASSERT(r.unresolved().empty());
192✔
1556
        return r.target;
96✔
1557
    }
1558
    _lookup_path_modify(&r);
88✔
1559
    return r.target;
88✔
1560
}
1561

1562
void Tree::_lookup_path(lookup_result *r) const
528✔
1563
{
1564
    C4_ASSERT( ! r->unresolved().empty());
1,056✔
1565
    _lookup_path_token parent{"", type(r->closest)};
528✔
1566
    id_type node;
1567
    do
1568
    {
1569
        node = _next_node(r, &parent);
1,848✔
1570
        if(node != NONE)
1,848✔
1571
            r->closest = node;
1,696✔
1572
        if(r->unresolved().empty())
3,696✔
1573
        {
1574
            r->target = node;
376✔
1575
            return;
376✔
1576
        }
1577
    } while(node != NONE);
1,472✔
1578
}
1579

1580
void Tree::_lookup_path_modify(lookup_result *r)
88✔
1581
{
1582
    C4_ASSERT( ! r->unresolved().empty());
176✔
1583
    _lookup_path_token parent{"", type(r->closest)};
88✔
1584
    id_type node;
1585
    do
1586
    {
1587
        node = _next_node_modify(r, &parent);
224✔
1588
        if(node != NONE)
224✔
1589
            r->closest = node;
224✔
1590
        if(r->unresolved().empty())
448✔
1591
        {
1592
            r->target = node;
88✔
1593
            return;
88✔
1594
        }
1595
    } while(node != NONE);
136✔
1596
}
1597

1598
id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const
1,848✔
1599
{
1600
    _lookup_path_token token = _next_token(r, *parent);
1,848✔
1601
    if( ! token)
1,848✔
UNCOV
1602
        return NONE;
×
1603

1604
    id_type node = NONE;
1,848✔
1605
    csubstr prev = token.value;
1,848✔
1606
    if(token.type == MAP || token.type == SEQ)
3,120✔
1607
    {
1608
        _RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('['));
1,008✔
1609
        //_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE);
1610
        _RYML_CB_ASSERT(m_callbacks, is_map(r->closest));
2,016✔
1611
        node = find_child(r->closest, token.value);
1,008✔
1612
    }
1613
    else if(token.type == KEYVAL)
840✔
1614
    {
1615
        _RYML_CB_ASSERT(m_callbacks, r->unresolved().empty());
704✔
1616
        if(is_map(r->closest))
704✔
1617
            node = find_child(r->closest, token.value);
344✔
1618
    }
1619
    else if(token.type == KEY)
488✔
1620
    {
1621
        _RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'));
488✔
1622
        token.value = token.value.offs(1, 1).trim(' ');
488✔
1623
        id_type idx = 0;
488✔
1624
        _RYML_CB_CHECK(m_callbacks, from_chars(token.value, &idx));
488✔
1625
        node = child(r->closest, idx);
488✔
1626
    }
1627
    else
1628
    {
UNCOV
1629
        C4_NEVER_REACH();
×
1630
    }
1631

1632
    if(node != NONE)
1,848✔
1633
    {
1634
        *parent = token;
1,696✔
1635
    }
1636
    else
1637
    {
1638
        csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
152✔
1639
        r->path_pos -= prev.len;
152✔
1640
        if(p.begins_with('.'))
152✔
1641
            r->path_pos -= 1u;
32✔
1642
    }
1643

1644
    return node;
1,848✔
1645
}
1646

1647
id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
224✔
1648
{
1649
    _lookup_path_token token = _next_token(r, *parent);
224✔
1650
    if( ! token)
224✔
UNCOV
1651
        return NONE;
×
1652

1653
    id_type node = NONE;
224✔
1654
    if(token.type == MAP || token.type == SEQ)
400✔
1655
    {
1656
        _RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('['));
88✔
1657
        //_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE);
1658
        if( ! is_container(r->closest))
176✔
1659
        {
1660
            if(has_key(r->closest))
112✔
1661
                to_map(r->closest, key(r->closest));
40✔
1662
            else
1663
                to_map(r->closest);
16✔
1664
        }
1665
        else
1666
        {
1667
            if(is_map(r->closest))
64✔
1668
                node = find_child(r->closest, token.value);
32✔
1669
            else
1670
            {
1671
                id_type pos = NONE;
×
UNCOV
1672
                _RYML_CB_CHECK(m_callbacks, c4::atox(token.value, &pos));
×
UNCOV
1673
                _RYML_CB_ASSERT(m_callbacks, pos != NONE);
×
UNCOV
1674
                node = child(r->closest, pos);
×
1675
            }
1676
        }
1677
        if(node == NONE)
88✔
1678
        {
1679
            _RYML_CB_ASSERT(m_callbacks, is_map(r->closest));
176✔
1680
            node = append_child(r->closest);
88✔
1681
            NodeData *n = _p(node);
88✔
1682
            n->m_key.scalar = token.value;
88✔
1683
            n->m_type.add(KEY);
88✔
1684
        }
1685
    }
1686
    else if(token.type == KEYVAL)
136✔
1687
    {
1688
        _RYML_CB_ASSERT(m_callbacks, r->unresolved().empty());
128✔
1689
        if(is_map(r->closest))
128✔
1690
        {
1691
            node = find_child(r->closest, token.value);
40✔
1692
            if(node == NONE)
40✔
1693
                node = append_child(r->closest);
80✔
1694
        }
1695
        else
1696
        {
1697
            _RYML_CB_ASSERT(m_callbacks, !is_seq(r->closest));
48✔
1698
            _add_flags(r->closest, MAP);
24✔
1699
            node = append_child(r->closest);
48✔
1700
        }
1701
        NodeData *n = _p(node);
64✔
1702
        n->m_key.scalar = token.value;
64✔
1703
        n->m_val.scalar = "";
64✔
1704
        n->m_type.add(KEYVAL);
64✔
1705
    }
1706
    else if(token.type == KEY)
72✔
1707
    {
1708
        _RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'));
72✔
1709
        token.value = token.value.offs(1, 1).trim(' ');
72✔
1710
        id_type idx;
1711
        if( ! from_chars(token.value, &idx))
72✔
UNCOV
1712
             return NONE;
×
1713
        if( ! is_container(r->closest))
144✔
1714
        {
1715
            if(has_key(r->closest))
112✔
1716
            {
1717
                csubstr k = key(r->closest);
40✔
1718
                _clear_type(r->closest);
40✔
1719
                to_seq(r->closest, k);
40✔
1720
            }
1721
            else
1722
            {
1723
                _clear_type(r->closest);
16✔
1724
                to_seq(r->closest);
16✔
1725
            }
1726
        }
1727
        _RYML_CB_ASSERT(m_callbacks, is_container(r->closest));
144✔
1728
        node = child(r->closest, idx);
72✔
1729
        if(node == NONE)
72✔
1730
        {
1731
            _RYML_CB_ASSERT(m_callbacks, num_children(r->closest) <= idx);
72✔
1732
            for(id_type i = num_children(r->closest); i <= idx; ++i)
224✔
1733
            {
1734
                node = append_child(r->closest);
152✔
1735
                if(i < idx)
152✔
1736
                {
1737
                    if(is_map(r->closest))
160✔
UNCOV
1738
                        to_keyval(node, /*"~"*/{}, /*"~"*/{});
×
1739
                    else if(is_seq(r->closest))
160✔
1740
                        to_val(node, /*"~"*/{});
80✔
1741
                }
1742
            }
1743
        }
1744
    }
1745
    else
1746
    {
UNCOV
1747
        C4_NEVER_REACH();
×
1748
    }
1749

1750
    _RYML_CB_ASSERT(m_callbacks, node != NONE);
224✔
1751
    *parent = token;
224✔
1752
    return node;
224✔
1753
}
1754

1755
/* types of tokens:
1756
 * - seeing "map."  ---> "map"/MAP
1757
 * - finishing "scalar" ---> "scalar"/KEYVAL
1758
 * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)
1759
 * - seeing "[n]" ---> "[n]"/KEY
1760
 */
1761
Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const
2,072✔
1762
{
1763
    csubstr unres = r->unresolved();
2,072✔
1764
    if(unres.empty())
2,072✔
UNCOV
1765
        return {};
×
1766

1767
    // is it an indexation like [0], [1], etc?
1768
    if(unres.begins_with('['))
2,072✔
1769
    {
1770
        size_t pos = unres.find(']');
560✔
1771
        if(pos == csubstr::npos)
560✔
UNCOV
1772
            return {};
×
1773
        csubstr idx = unres.first(pos + 1);
560✔
1774
        _advance(r, pos + 1);
560✔
1775
        return {idx, KEY};
560✔
1776
    }
1777

1778
    // no. so it must be a name
1779
    size_t pos = unres.first_of(".[");
1,512✔
1780
    if(pos == csubstr::npos)
1,512✔
1781
    {
1782
        _advance(r, unres.len);
416✔
1783
        NodeType t;
1784
        if(( ! parent) || parent.type.is_seq())
832✔
UNCOV
1785
            return {unres, VAL};
×
1786
        return {unres, KEYVAL};
416✔
1787
    }
1788

1789
    // it's either a map or a seq
1790
    _RYML_CB_ASSERT(m_callbacks, unres[pos] == '.' || unres[pos] == '[');
1,568✔
1791
    if(unres[pos] == '.')
1,096✔
1792
    {
1793
        _RYML_CB_ASSERT(m_callbacks, pos != 0);
624✔
1794
        _advance(r, pos + 1);
624✔
1795
        return {unres.first(pos), MAP};
624✔
1796
    }
1797

1798
    _RYML_CB_ASSERT(m_callbacks, unres[pos] == '[');
472✔
1799
    _advance(r, pos);
472✔
1800
    return {unres.first(pos), SEQ};
472✔
1801
}
1802

1803

1804
} // namespace yml
1805
} // namespace c4
1806

1807

1808
C4_SUPPRESS_WARNING_GCC_CLANG_POP
1809
C4_SUPPRESS_WARNING_MSVC_POP
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

© 2026 Coveralls, Inc