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

biojppm / rapidyaml / 18160471768

01 Oct 2025 11:19AM UTC coverage: 97.276% (-0.4%) from 97.65%
18160471768

Pull #503

github

web-flow
Merge 8e72e99dd into 653eac974
Pull Request #503: Improve error model, callbacks

1735 of 1782 new or added lines in 31 files covered. (97.36%)

64 existing lines in 7 files now uncovered.

12677 of 13032 relevant lines covered (97.28%)

187443.13 hits per line

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

95.42
/src/c4/yml/tree.cpp
1
#include "c4/yml/tree.hpp"
2
#include "c4/yml/detail/dbgprint.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()
66,388✔
22
{
23
    return NodeRef(this, root_id());
66,388✔
24
}
25
ConstNodeRef Tree::rootref() const
47,795✔
26
{
27
    return ConstNodeRef(this, root_id());
47,795✔
28
}
29

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

35
NodeRef Tree::ref(id_type id)
1,924✔
36
{
37
    _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
1,924✔
38
    return NodeRef(this, id);
1,812✔
39
}
40
ConstNodeRef Tree::ref(id_type id) const
40✔
41
{
42
    _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
40✔
43
    return ConstNodeRef(this, id);
40✔
44
}
45
ConstNodeRef Tree::cref(id_type id) const
3,004✔
46
{
47
    _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
3,004✔
48
    return ConstNodeRef(this, id);
2,988✔
49
}
50

51
NodeRef Tree::operator[] (csubstr key)
5,544✔
52
{
53
    return rootref()[key];
11,088✔
54
}
55
ConstNodeRef Tree::operator[] (csubstr key) const
7,443✔
56
{
57
    return rootref()[key];
14,874✔
58
}
59

60
NodeRef Tree::operator[] (id_type i)
1,200✔
61
{
62
    return rootref()[i];
2,400✔
63
}
64
ConstNodeRef Tree::operator[] (id_type i) const
3,972✔
65
{
66
    return rootref()[i];
7,936✔
67
}
68

69
NodeRef Tree::docref(id_type i)
604✔
70
{
71
    return ref(doc(i));
604✔
72
}
73
ConstNodeRef Tree::docref(id_type i) const
2,792✔
74
{
75
    return cref(doc(i));
2,792✔
76
}
77
ConstNodeRef Tree::cdocref(id_type i) const
16✔
78
{
79
    return cref(doc(i));
16✔
80
}
81

82

83
//-----------------------------------------------------------------------------
84
Tree::Tree(Callbacks const& cb)
672,713✔
85
    : m_buf(nullptr)
672,713✔
86
    , m_cap(0)
672,713✔
87
    , m_size(0)
672,713✔
88
    , m_free_head(NONE)
672,713✔
89
    , m_free_tail(NONE)
672,713✔
90
    , m_arena()
672,713✔
91
    , m_arena_pos(0)
672,713✔
92
    , m_callbacks(cb)
672,713✔
93
    , m_tag_directives()
3,363,565✔
94
{
95
}
672,713✔
96

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

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

109

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

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

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

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

142
void Tree::_free()
861,244✔
143
{
144
    if(m_buf)
861,244✔
145
    {
146
        _RYML_ASSERT_VISIT_(m_callbacks, m_cap > 0, this, NONE);
411,211✔
147
        _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
411,211✔
148
    }
149
    if(m_arena.str)
861,244✔
150
    {
151
        _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len > 0, this, NONE);
106,189✔
152
        _RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);
106,189✔
153
    }
154
    _clear();
861,244✔
155
}
861,244✔
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()
1,051,264✔
164
{
165
    m_buf = nullptr;
1,051,264✔
166
    m_cap = 0;
1,051,264✔
167
    m_size = 0;
1,051,264✔
168
    m_free_head = 0;
1,051,264✔
169
    m_free_tail = 0;
1,051,264✔
170
    m_arena = {};
1,051,264✔
171
    m_arena_pos = 0;
1,051,264✔
172
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
5,256,320✔
173
        m_tag_directives[i] = {};
4,205,056✔
174
}
1,051,264✔
175

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

205
void Tree::_move(Tree & that) noexcept
190,020✔
206
{
207
    _RYML_ASSERT_VISIT_(m_callbacks, m_buf == nullptr, this, NONE);
190,020✔
208
    _RYML_ASSERT_VISIT_(m_callbacks, m_arena.str == nullptr, this, NONE);
190,020✔
209
    _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len == 0, this, NONE);
190,020✔
210
    m_buf = that.m_buf;
190,020✔
211
    m_cap = that.m_cap;
190,020✔
212
    m_size = that.m_size;
190,020✔
213
    m_free_head = that.m_free_head;
190,020✔
214
    m_free_tail = that.m_free_tail;
190,020✔
215
    m_arena = that.m_arena;
190,020✔
216
    m_arena_pos = that.m_arena_pos;
190,020✔
217
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
950,100✔
218
        m_tag_directives[i] = that.m_tag_directives[i];
760,080✔
219
    that._clear();
190,020✔
220
}
190,020✔
221

222
void Tree::_relocate(substr next_arena)
3,772✔
223
{
224
    _RYML_ASSERT_VISIT_(m_callbacks, next_arena.not_empty(), this, NONE);
3,772✔
225
    _RYML_ASSERT_VISIT_(m_callbacks, next_arena.len >= m_arena.len, this, NONE);
3,772✔
226
    if(m_arena_pos)
3,772✔
227
        memcpy(next_arena.str, m_arena.str, m_arena_pos);
3,760✔
228
    for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n)
69,284✔
229
    {
230
        if(in_arena(n->m_key.scalar))
65,512✔
231
            n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
3,728✔
232
        if(in_arena(n->m_key.tag))
65,512✔
233
            n->m_key.tag = _relocated(n->m_key.tag, next_arena);
88✔
234
        if(in_arena(n->m_key.anchor))
65,512✔
235
            n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
480✔
236
        if(in_arena(n->m_val.scalar))
65,512✔
237
            n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
13,432✔
238
        if(in_arena(n->m_val.tag))
65,512✔
239
            n->m_val.tag = _relocated(n->m_val.tag, next_arena);
1,544✔
240
        if(in_arena(n->m_val.anchor))
65,512✔
241
            n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
480✔
242
    }
243
    for(TagDirective &C4_RESTRICT td : m_tag_directives)
18,860✔
244
    {
245
        if(in_arena(td.prefix))
15,088✔
246
            td.prefix = _relocated(td.prefix, next_arena);
688✔
247
        if(in_arena(td.handle))
15,088✔
248
            td.handle = _relocated(td.handle, next_arena);
688✔
249
    }
250
}
3,772✔
251

252

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

285
        if( ! m_size)
417,116✔
286
            _claim_root();
412,644✔
287
    }
288
}
425,080✔
289

290

291
//-----------------------------------------------------------------------------
292
void Tree::clear()
212,412✔
293
{
294
    _clear_range(0, m_cap);
212,412✔
295
    m_size = 0;
212,412✔
296
    if(m_buf)
212,412✔
297
    {
298
        _RYML_ASSERT_VISIT_(m_callbacks, m_cap >= 0, this, NONE);
299
        m_free_head = 0;
25,280✔
300
        m_free_tail = m_cap-1;
25,280✔
301
        _claim_root();
25,280✔
302
    }
303
    else
304
    {
305
        m_free_head = NONE;
187,132✔
306
        m_free_tail = NONE;
187,132✔
307
    }
308
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
1,062,060✔
309
        m_tag_directives[i] = {};
849,648✔
310
}
212,412✔
311

312
void Tree::_claim_root()
437,924✔
313
{
314
    id_type r = _claim();
437,924✔
315
    _RYML_ASSERT_VISIT_(m_callbacks, r == 0, this, r);
437,924✔
316
    _set_hierarchy(r, NONE, NONE);
437,924✔
317
}
437,924✔
318

319

320
//-----------------------------------------------------------------------------
321
void Tree::_clear_range(id_type first, id_type num)
629,528✔
322
{
323
    if(num == 0)
629,528✔
324
        return; // prevent overflow when subtracting
187,132✔
325
    _RYML_ASSERT_VISIT_(m_callbacks, first >= 0 && first + num <= m_cap, this, first);
442,396✔
326
    memset(m_buf + first, 0, (size_t)num * sizeof(NodeData)); // TODO we should not need this
442,396✔
327
    for(id_type i = first, e = first + num; i < e; ++i)
7,470,776✔
328
    {
329
        _clear(i);
7,028,380✔
330
        NodeData *n = m_buf + i;
7,028,380✔
331
        n->m_prev_sibling = i - 1;
7,028,380✔
332
        n->m_next_sibling = i + 1;
7,028,380✔
333
    }
334
    m_buf[first + num - 1].m_next_sibling = NONE;
442,396✔
335
}
336

337
C4_SUPPRESS_WARNING_GCC_POP
338

339

340
//-----------------------------------------------------------------------------
341
void Tree::_release(id_type i)
80,540✔
342
{
343
    _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
80,540✔
344

345
    _rem_hierarchy(i);
80,540✔
346
    _free_list_add(i);
80,540✔
347
    _clear(i);
80,540✔
348

349
    --m_size;
80,540✔
350
}
80,540✔
351

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

359
    w.m_parent = NONE;
80,612✔
360
    w.m_next_sibling = m_free_head;
80,612✔
361
    w.m_prev_sibling = NONE;
80,612✔
362
    if(m_free_head != NONE)
80,612✔
363
        m_buf[m_free_head].m_prev_sibling = i;
80,580✔
364
    m_free_head = i;
80,612✔
365
    if(m_free_tail == NONE)
80,612✔
366
        m_free_tail = m_free_head;
32✔
367
}
80,612✔
368

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

376
//-----------------------------------------------------------------------------
377
id_type Tree::_claim()
1,293,888✔
378
{
379
    if(m_free_head == NONE || m_buf == nullptr)
1,293,888✔
380
    {
381
        id_type sz = 2 * m_cap;
4,456✔
382
        sz = sz ? sz : 16;
4,456✔
383
        reserve(sz);
4,456✔
384
        _RYML_ASSERT_VISIT_(m_callbacks, m_free_head != NONE, this, NONE);
4,456✔
385
    }
386

387
    _RYML_ASSERT_VISIT_(m_callbacks, m_size < m_cap, this, NONE);
1,293,888✔
388
    _RYML_ASSERT_VISIT_(m_callbacks, m_free_head >= 0 && m_free_head < m_cap, this, NONE);
1,293,888✔
389

390
    id_type ichild = m_free_head;
1,293,888✔
391
    NodeData *child = m_buf + ichild;
1,293,888✔
392

393
    ++m_size;
1,293,888✔
394
    m_free_head = child->m_next_sibling;
1,293,888✔
395
    if(m_free_head == NONE)
1,293,888✔
396
    {
397
        m_free_tail = NONE;
9,632✔
398
        _RYML_ASSERT_VISIT_(m_callbacks, m_size == m_cap, this, NONE);
9,632✔
399
    }
400

401
    _clear(ichild);
1,293,888✔
402

403
    return ichild;
1,293,888✔
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)
1,294,440✔
421
{
422
    _RYML_ASSERT_VISIT_(m_callbacks, ichild >= 0 && ichild < m_cap, this, ichild);
1,294,440✔
423
    _RYML_ASSERT_VISIT_(m_callbacks, iparent == NONE || (iparent >= 0 && iparent < m_cap), this, iparent);
1,294,440✔
424
    _RYML_ASSERT_VISIT_(m_callbacks, iprev_sibling == NONE || (iprev_sibling >= 0 && iprev_sibling < m_cap), this, iprev_sibling);
1,294,440✔
425

426
    NodeData *C4_RESTRICT child = _p(ichild);
1,294,440✔
427

428
    child->m_parent = iparent;
1,294,440✔
429
    child->m_prev_sibling = NONE;
1,294,440✔
430
    child->m_next_sibling = NONE;
1,294,440✔
431

432
    if(iparent == NONE)
1,294,440✔
433
    {
434
        _RYML_ASSERT_VISIT_(m_callbacks, ichild == 0, this, ichild);
437,924✔
435
        _RYML_ASSERT_VISIT_(m_callbacks, iprev_sibling == NONE, this, iprev_sibling);
437,924✔
436
    }
437

438
    if(iparent == NONE)
1,294,440✔
439
        return;
437,924✔
440

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

446
    if(psib)
856,516✔
447
    {
448
        _RYML_ASSERT_VISIT_(m_callbacks, next_sibling(iprev_sibling) == id(nsib), this, iprev_sibling);
449,588✔
449
        child->m_prev_sibling = id(psib);
449,588✔
450
        psib->m_next_sibling = id(child);
449,588✔
451
        _RYML_ASSERT_VISIT_(m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling == NONE, this, iprev_sibling);
449,588✔
452
    }
453

454
    if(nsib)
856,516✔
455
    {
456
        _RYML_ASSERT_VISIT_(m_callbacks, prev_sibling(inext_sibling) == id(psib), this, inext_sibling);
536✔
457
        child->m_next_sibling = id(nsib);
536✔
458
        nsib->m_prev_sibling = id(child);
536✔
459
        _RYML_ASSERT_VISIT_(m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling == NONE, this, inext_sibling);
536✔
460
    }
461

462
    if(parent->m_first_child == NONE)
856,516✔
463
    {
464
        _RYML_ASSERT_VISIT_(m_callbacks, parent->m_last_child == NONE, this, parent->m_last_child);
406,688✔
465
        parent->m_first_child = id(child);
406,688✔
466
        parent->m_last_child = id(child);
406,688✔
467
    }
468
    else
469
    {
470
        if(child->m_next_sibling == parent->m_first_child)
449,828✔
471
            parent->m_first_child = id(child);
240✔
472

473
        if(child->m_prev_sibling == parent->m_last_child)
449,828✔
474
            parent->m_last_child = id(child);
449,292✔
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)
81,164✔
484
{
485
    _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
81,164✔
486

487
    NodeData &C4_RESTRICT w = m_buf[i];
81,164✔
488

489
    // remove from the parent
490
    if(w.m_parent != NONE)
81,164✔
491
    {
492
        NodeData &C4_RESTRICT p = m_buf[w.m_parent];
81,092✔
493
        if(p.m_first_child == i)
81,092✔
494
        {
495
            p.m_first_child = w.m_next_sibling;
7,200✔
496
        }
497
        if(p.m_last_child == i)
81,092✔
498
        {
499
            p.m_last_child = w.m_prev_sibling;
79,840✔
500
        }
501
    }
502

503
    // remove from the used list
504
    if(w.m_prev_sibling != NONE)
81,164✔
505
    {
506
        NodeData *C4_RESTRICT prev = get(w.m_prev_sibling);
73,948✔
507
        prev->m_next_sibling = w.m_next_sibling;
73,948✔
508
    }
509
    if(w.m_next_sibling != NONE)
81,164✔
510
    {
511
        NodeData *C4_RESTRICT next = get(w.m_next_sibling);
1,324✔
512
        next->m_prev_sibling = w.m_prev_sibling;
1,324✔
513
    }
514
}
81,164✔
515

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

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

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

545

546
//-----------------------------------------------------------------------------
547
/** @cond dev */
548
void Tree::_swap(id_type n_, id_type m_)
384✔
549
{
550
    _RYML_ASSERT_VISIT_(m_callbacks, (parent(n_) != NONE) || type(n_) == NOTYPE, this, n_);
384✔
551
    _RYML_ASSERT_VISIT_(m_callbacks, (parent(m_) != NONE) || type(m_) == NOTYPE, this, m_);
456✔
552
    NodeType tn = type(n_);
384✔
553
    NodeType tm = type(m_);
384✔
554
    if(tn != NOTYPE && tm != NOTYPE)
768✔
555
    {
556
        _swap_props(n_, m_);
312✔
557
        _swap_hierarchy(n_, m_);
312✔
558
    }
559
    else if(tn == NOTYPE && tm != NOTYPE)
72✔
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)
144✔
568
    {
569
        _copy_props(m_, n_);
72✔
570
        _free_list_rem(m_);
72✔
571
        _copy_hierarchy(m_, n_);
72✔
572
        _clear(n_);
72✔
573
        _free_list_add(n_);
72✔
574
    }
575
    else
576
    {
577
        C4_NEVER_REACH();
×
578
    }
579
}
384✔
580

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

586
    for(id_type i = first_child(ia); i != NONE; i = next_sibling(i))
456✔
587
    {
588
        if(i == ib || i == ia)
144✔
589
            continue;
8✔
590
        _p(i)->m_parent = ib;
136✔
591
    }
592

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

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

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

650
    if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
312✔
651
       a.m_next_sibling != ib && b.m_next_sibling != ia)
272✔
652
    {
653
        if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib)
272✔
654
            _p(a.m_prev_sibling)->m_next_sibling = ib;
168✔
655
        if(a.m_next_sibling != NONE && a.m_next_sibling != ib)
272✔
656
            _p(a.m_next_sibling)->m_prev_sibling = ib;
184✔
657
        if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia)
272✔
658
            _p(b.m_prev_sibling)->m_next_sibling = ia;
168✔
659
        if(b.m_next_sibling != NONE && b.m_next_sibling != ia)
272✔
660
            _p(b.m_next_sibling)->m_prev_sibling = ia;
120✔
661
        std::swap(a.m_prev_sibling, b.m_prev_sibling);
272✔
662
        std::swap(a.m_next_sibling, b.m_next_sibling);
272✔
663
    }
664
    else
665
    {
666
        if(a.m_next_sibling == ib) // n will go after m
40✔
667
        {
668
            _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling == ia, this, ia);
40✔
669
            if(a.m_prev_sibling != NONE)
40✔
670
            {
671
                _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ib, this, ib);
32✔
672
                _p(a.m_prev_sibling)->m_next_sibling = ib;
32✔
673
            }
674
            if(b.m_next_sibling != NONE)
40✔
675
            {
676
                _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ia, this, ia);
16✔
677
                _p(b.m_next_sibling)->m_prev_sibling = ia;
16✔
678
            }
679
            id_type ns = b.m_next_sibling;
40✔
680
            b.m_prev_sibling = a.m_prev_sibling;
40✔
681
            b.m_next_sibling = ia;
40✔
682
            a.m_prev_sibling = ib;
40✔
683
            a.m_next_sibling = ns;
40✔
684
        }
685
        else if(a.m_prev_sibling == ib) // m will go after n
×
686
        {
NEW
687
            _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling == ia, this, ia);
×
688
            if(b.m_prev_sibling != NONE)
×
689
            {
NEW
690
                _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling != ia, this, ia);
×
691
                _p(b.m_prev_sibling)->m_next_sibling = ia;
×
692
            }
693
            if(a.m_next_sibling != NONE)
×
694
            {
NEW
695
                _RYML_ASSERT_VISIT_(m_callbacks, a.m_next_sibling != ib, this, 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_ASSERT_VISIT_(m_callbacks, a.m_next_sibling != ia, this, ia);
312✔
710
    _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ia, this, ia);
312✔
711
    _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ib, this, ib);
312✔
712
    _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling != ib, this, ib);
312✔
713

714
    if(a.m_parent != ib && b.m_parent != ia)
312✔
715
    {
716
        std::swap(a.m_parent, b.m_parent);
304✔
717
    }
718
    else
719
    {
720
        if(a.m_parent == ib && b.m_parent != ia)
8✔
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)
8✔
726
        {
727
            b.m_parent = a.m_parent;
8✔
728
            a.m_parent = ib;
8✔
729
        }
730
        else
731
        {
732
            C4_NEVER_REACH();
×
733
        }
734
    }
735
}
736

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

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

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

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

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

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

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

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

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

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

855

856
//-----------------------------------------------------------------------------
857
void Tree::remove_children(id_type node)
80,612✔
858
{
859
    _RYML_ASSERT_VISIT_(m_callbacks, get(node) != nullptr, this, node);
80,612✔
860
    #if __GNUC__ >= 6
861
    C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wnull-dereference")
862
    #endif
863
    id_type ich = get(node)->m_first_child;
80,612✔
864
    #if __GNUC__ >= 6
865
    C4_SUPPRESS_WARNING_GCC_POP
866
    #endif
867
    while(ich != NONE)
81,296✔
868
    {
869
        remove_children(ich);
684✔
870
        _RYML_ASSERT_VISIT_(m_callbacks, get(ich) != nullptr, this, node);
684✔
871
        id_type next = get(ich)->m_next_sibling;
684✔
872
        _release(ich);
684✔
873
        if(ich == get(node)->m_last_child)
684✔
874
            break;
×
875
        ich = next;
684✔
876
    }
877
}
80,612✔
878

879
bool Tree::change_type(id_type node, NodeType type)
72✔
880
{
881
    _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() || type.is_map() || type.is_seq(), this, node);
144✔
882
    _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1, this, node);
216✔
883
    _RYML_ASSERT_VISIT_(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()), this, node);
216✔
884
    NodeData *d = _p(node);
72✔
885
    if(type.is_map() && is_map(node))
96✔
886
        return false;
8✔
887
    else if(type.is_seq() && is_seq(node))
88✔
888
        return false;
8✔
889
    else if(type.is_val() && is_val(node))
80✔
890
        return false;
4✔
891
    d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type;
364✔
892
    remove_children(node);
52✔
893
    return true;
52✔
894
}
895

896

897
//-----------------------------------------------------------------------------
898
id_type Tree::duplicate(id_type node, id_type parent, id_type after)
12✔
899
{
900
    return duplicate(this, node, parent, after);
12✔
901
}
902

903
id_type Tree::duplicate(Tree const* src, id_type node, id_type parent, id_type after)
1,132✔
904
{
905
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
1,132✔
906
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1,132✔
907
    _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
1,132✔
908
    _RYML_ASSERT_VISIT_(m_callbacks,  ! src->is_root(node), src, node);
1,132✔
909

910
    id_type copy = _claim();
1,132✔
911

912
    _copy_props(copy, src, node);
1,132✔
913
    _set_hierarchy(copy, parent, after);
1,132✔
914
    duplicate_children(src, node, copy, NONE);
1,132✔
915

916
    return copy;
1,132✔
917
}
918

919
//-----------------------------------------------------------------------------
920
id_type Tree::duplicate_children(id_type node, id_type parent, id_type after)
×
921
{
922
    return duplicate_children(this, node, parent, after);
×
923
}
924

925
id_type Tree::duplicate_children(Tree const* src, id_type node, id_type parent, id_type after)
1,344✔
926
{
927
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
1,344✔
928
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1,344✔
929
    _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
1,344✔
930
    _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
1,344✔
931

932
    id_type prev = after;
1,344✔
933
    for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
2,136✔
934
    {
935
        prev = duplicate(src, i, parent, prev);
792✔
936
    }
937

938
    return prev;
1,344✔
939
}
940

941
//-----------------------------------------------------------------------------
942
void Tree::duplicate_contents(id_type node, id_type where)
212✔
943
{
944
    duplicate_contents(this, node, where);
212✔
945
}
212✔
946

947
void Tree::duplicate_contents(Tree const *src, id_type node, id_type where)
212✔
948
{
949
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
212✔
950
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
212✔
951
    _RYML_ASSERT_VISIT_(m_callbacks, where != NONE, this, where);
212✔
952
    _copy_props_wo_key(where, src, node);
212✔
953
    duplicate_children(src, node, where, last_child(where));
212✔
954
}
212✔
955

956
//-----------------------------------------------------------------------------
957
id_type Tree::duplicate_children_no_rep(id_type node, id_type parent, id_type after)
200✔
958
{
959
    return duplicate_children_no_rep(this, node, parent, after);
200✔
960
}
961

962
id_type Tree::duplicate_children_no_rep(Tree const *src, id_type node, id_type parent, id_type after)
212✔
963
{
964
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
212✔
965
    _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
212✔
966
    _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
212✔
967

968
    // don't loop using pointers as there may be a relocation
969

970
    // find the position where "after" is
971
    id_type after_pos = NONE;
212✔
972
    if(after != NONE)
212✔
973
    {
974
        for(id_type i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))
204✔
975
        {
976
            if(i == after)
204✔
977
            {
978
                after_pos = icount;
100✔
979
                break;
100✔
980
            }
981
        }
982
        _RYML_ASSERT_VISIT_(m_callbacks, after_pos != NONE, this, node);
100✔
983
    }
984

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

1051
    return prev;
204✔
1052
}
1053

1054

1055
//-----------------------------------------------------------------------------
1056

1057
void Tree::merge_with(Tree const *src, id_type src_node, id_type dst_node)
736✔
1058
{
1059
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, src_node);
736✔
1060
    if(src_node == NONE)
736✔
1061
        src_node = src->root_id();
240✔
1062
    if(dst_node == NONE)
736✔
1063
        dst_node = root_id();
240✔
1064
    _RYML_ASSERT_VISIT_(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node), src, src_node);
1,220✔
1065
    if(src->has_val(src_node))
736✔
1066
    {
1067
        type_bits mask_src = ~STYLE; // keep the existing style if it is already a val
456✔
1068
        if( ! has_val(dst_node))
456✔
1069
        {
1070
            if(has_children(dst_node))
12✔
1071
                remove_children(dst_node);
12✔
1072
            mask_src |= VAL_STYLE; // copy the src style
12✔
1073
        }
1074
        if(src->is_keyval(src_node))
456✔
1075
        {
1076
            _copy_props(dst_node, src, src_node, mask_src);
268✔
1077
        }
1078
        else
1079
        {
1080
            _RYML_ASSERT_VISIT_(m_callbacks, src->is_val(src_node), src, src_node);
188✔
1081
            _copy_props_wo_key(dst_node, src, src_node, mask_src);
188✔
1082
        }
1083
    }
1084
    else if(src->is_seq(src_node))
280✔
1085
    {
1086
        if( ! is_seq(dst_node))
76✔
1087
        {
1088
            if(has_children(dst_node))
24✔
1089
                remove_children(dst_node);
×
1090
            _clear_type(dst_node);
24✔
1091
            if(src->has_key(src_node))
24✔
1092
                to_seq(dst_node, src->key(src_node));
8✔
1093
            else
1094
                to_seq(dst_node);
16✔
1095
            _p(dst_node)->m_type = src->_p(src_node)->m_type;
24✔
1096
        }
1097
        for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
264✔
1098
        {
1099
            id_type dch = append_child(dst_node);
188✔
1100
            _copy_props_wo_key(dch, src, sch);
188✔
1101
            merge_with(src, sch, dch);
188✔
1102
        }
1103
    }
1104
    else
1105
    {
1106
        _RYML_ASSERT_VISIT_(m_callbacks, src->is_map(src_node), src, src_node);
204✔
1107
        if( ! is_map(dst_node))
204✔
1108
        {
1109
            if(has_children(dst_node))
76✔
1110
                remove_children(dst_node);
4✔
1111
            _clear_type(dst_node);
76✔
1112
            if(src->has_key(src_node))
76✔
1113
                to_map(dst_node, src->key(src_node));
8✔
1114
            else
1115
                to_map(dst_node);
68✔
1116
            _p(dst_node)->m_type = src->_p(src_node)->m_type;
76✔
1117
        }
1118
        for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
508✔
1119
        {
1120
            id_type dch = find_child(dst_node, src->key(sch));
304✔
1121
            if(dch == NONE)
304✔
1122
            {
1123
                dch = append_child(dst_node);
196✔
1124
                _copy_props(dch, src, sch);
196✔
1125
            }
1126
            merge_with(src, sch, dch);
304✔
1127
        }
1128
    }
1129
}
736✔
1130

1131

1132
//-----------------------------------------------------------------------------
1133

1134
void Tree::resolve(bool clear_anchors)
228✔
1135
{
1136
    if(m_size == 0)
228✔
1137
        return;
4✔
1138
    ReferenceResolver rr;
224✔
1139
    resolve(&rr, clear_anchors);
224✔
1140
}
216✔
1141

1142
void Tree::resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors)
224✔
1143
{
1144
    if(m_size == 0)
224✔
1145
        return;
×
1146
    rr->resolve(this, clear_anchors);
224✔
1147
}
1148

1149

1150
//-----------------------------------------------------------------------------
1151

1152
id_type Tree::num_children(id_type node) const
4,709,356✔
1153
{
1154
    id_type count = 0;
4,709,356✔
1155
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
19,223,500✔
1156
        ++count;
14,514,144✔
1157
    return count;
4,709,348✔
1158
}
1159

1160
id_type Tree::child(id_type node, id_type pos) const
1,559,064✔
1161
{
1162
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1,559,064✔
1163
    id_type count = 0;
1,559,060✔
1164
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
5,717,896✔
1165
    {
1166
        if(count++ == pos)
5,717,396✔
1167
            return i;
1,558,560✔
1168
    }
1169
    return NONE;
496✔
1170
}
1171

1172
id_type Tree::child_pos(id_type node, id_type ch) const
16✔
1173
{
1174
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
16✔
1175
    id_type count = 0;
16✔
1176
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
16✔
1177
    {
1178
        if(i == ch)
16✔
1179
            return count;
16✔
1180
        ++count;
×
1181
    }
1182
    return NONE;
×
1183
}
1184

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

1197
id_type Tree::find_child(id_type node, csubstr const& name) const
1,380,163✔
1198
{
1199
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1,380,163✔
1200
    _RYML_ASSERT_VISIT_(m_callbacks, is_map(node), this, node);
1,380,155✔
1201
    if(get(node)->m_first_child == NONE)
1,380,151✔
1202
    {
1203
        _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child == NONE, this, node);
308✔
1204
        return NONE;
308✔
1205
    }
1206
    else
1207
    {
1208
        _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child != NONE, this, node);
1,379,843✔
1209
    }
1210
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
6,988,515✔
1211
    {
1212
        if(_p(i)->m_key.scalar == name)
13,975,214✔
1213
        {
1214
            return i;
1,378,935✔
1215
        }
1216
    }
1217
    return NONE;
908✔
1218
}
1219

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

1226
namespace {
1227
id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0)
1,464✔
1228
{
1229
    maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
1,464✔
1230
    for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
2,444✔
1231
    {
1232
        const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
980✔
1233
        maxdepth = d > maxdepth ? d : maxdepth;
980✔
1234
    }
1235
    return maxdepth;
1,460✔
1236
}
1237
}
1238

1239
id_type Tree::depth_desc(id_type node) const
488✔
1240
{
1241
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
488✔
1242
    return depth_desc_(*this, node);
484✔
1243
}
1244

1245
id_type Tree::depth_asc(id_type node) const
80✔
1246
{
1247
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
80✔
1248
    id_type depth = 0;
76✔
1249
    while(!is_root(node))
208✔
1250
    {
1251
        ++depth;
132✔
1252
        node = parent(node);
132✔
1253
    }
1254
    return depth;
72✔
1255
}
1256

1257
bool Tree::is_ancestor(id_type node, id_type ancestor) const
972✔
1258
{
1259
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
972✔
1260
    id_type p = parent(node);
968✔
1261
    while(p != NONE)
2,260✔
1262
    {
1263
        if(p == ancestor)
1,532✔
1264
            return true;
240✔
1265
        p = parent(p);
1,292✔
1266
    }
1267
    return false;
728✔
1268
}
1269

1270

1271
//-----------------------------------------------------------------------------
1272

1273
void Tree::to_val(id_type node, csubstr val, type_bits more_flags)
10,444✔
1274
{
1275
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
10,444✔
1276
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node);
19,616✔
1277
    _set_flags(node, VAL|more_flags);
10,444✔
1278
    _p(node)->m_key.clear();
10,444✔
1279
    _p(node)->m_val = val;
10,444✔
1280
}
10,444✔
1281

1282
void Tree::to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags)
12,988✔
1283
{
1284
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
12,988✔
1285
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
25,976✔
1286
    _set_flags(node, KEYVAL|more_flags);
12,988✔
1287
    _p(node)->m_key = key;
12,988✔
1288
    _p(node)->m_val = val;
12,988✔
1289
}
12,988✔
1290

1291
void Tree::to_map(id_type node, type_bits more_flags)
4,080✔
1292
{
1293
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
4,080✔
1294
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node); // parent must not have children with keys
8,084✔
1295
    _set_flags(node, MAP|more_flags);
4,080✔
1296
    _p(node)->m_key.clear();
4,080✔
1297
    _p(node)->m_val.clear();
4,080✔
1298
}
4,080✔
1299

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

1309
void Tree::to_seq(id_type node, type_bits more_flags)
1,608✔
1310
{
1311
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
1,608✔
1312
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_seq(node), this, node);
3,200✔
1313
    _set_flags(node, SEQ|more_flags);
1,608✔
1314
    _p(node)->m_key.clear();
1,608✔
1315
    _p(node)->m_val.clear();
1,608✔
1316
}
1,608✔
1317

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

1327
void Tree::to_doc(id_type node, type_bits more_flags)
4,516✔
1328
{
1329
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
4,516✔
1330
    _set_flags(node, DOC|more_flags);
4,516✔
1331
    _p(node)->m_key.clear();
4,516✔
1332
    _p(node)->m_val.clear();
4,516✔
1333
}
4,516✔
1334

1335
void Tree::to_stream(id_type node, type_bits more_flags)
4✔
1336
{
1337
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
4✔
1338
    _set_flags(node, STREAM|more_flags);
4✔
1339
    _p(node)->m_key.clear();
4✔
1340
    _p(node)->m_val.clear();
4✔
1341
}
4✔
1342

1343

1344
//-----------------------------------------------------------------------------
1345

1346
void Tree::clear_style(id_type node, bool recurse)
76✔
1347
{
1348
    NodeData *C4_RESTRICT d = _p(node);
76✔
1349
    d->m_type.clear_style();
76✔
1350
    if(!recurse)
76✔
1351
        return;
8✔
1352
    for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
128✔
1353
        clear_style(child, recurse);
60✔
1354
}
1355

1356
void Tree::set_style_conditionally(id_type node,
220✔
1357
                                   NodeType type_mask,
1358
                                   NodeType rem_style_flags,
1359
                                   NodeType add_style_flags,
1360
                                   bool recurse)
1361
{
1362
    NodeData *C4_RESTRICT d = _p(node);
220✔
1363
    if((d->m_type & type_mask) == type_mask)
880✔
1364
    {
1365
        d->m_type &= ~(NodeType)rem_style_flags;
384✔
1366
        d->m_type |= (NodeType)add_style_flags;
384✔
1367
    }
1368
    if(!recurse)
220✔
1369
        return;
8✔
1370
    for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
404✔
1371
        set_style_conditionally(child, type_mask, rem_style_flags, add_style_flags, recurse);
192✔
1372
}
1373

1374

1375
//-----------------------------------------------------------------------------
1376
id_type Tree::num_tag_directives() const
642,444✔
1377
{
1378
    // this assumes we have a very small number of tag directives
1379
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
650,472✔
1380
        if(m_tag_directives[i].handle.empty())
1,300,912✔
1381
            return i;
642,428✔
1382
    return RYML_MAX_TAG_DIRECTIVES;
16✔
1383
}
1384

1385
void Tree::clear_tag_directives()
4✔
1386
{
1387
    for(TagDirective &td : m_tag_directives)
20✔
1388
        td = {};
16✔
1389
}
4✔
1390

1391
id_type Tree::add_tag_directive(TagDirective const& td)
2,848✔
1392
{
1393
    _RYML_CHECK_BASIC_(m_callbacks, !td.handle.empty());
5,696✔
1394
    _RYML_CHECK_BASIC_(m_callbacks, !td.prefix.empty());
5,696✔
1395
    _RYML_CHECK_BASIC_(m_callbacks, td.handle.begins_with('!'));
2,844✔
1396
    _RYML_CHECK_BASIC_(m_callbacks, td.handle.ends_with('!'));
2,844✔
1397
    // https://yaml.org/spec/1.2.2/#rule-ns-word-char
1398
    _RYML_CHECK_BASIC_(m_callbacks, td.handle == '!' || td.handle == "!!" || td.handle.trim('!').first_not_of("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-") == npos);
9,340✔
1399
    id_type pos = num_tag_directives();
2,844✔
1400
    _RYML_CHECK_BASIC_(m_callbacks, pos < RYML_MAX_TAG_DIRECTIVES);
2,844✔
1401
    m_tag_directives[pos] = td;
2,836✔
1402
    return pos;
2,836✔
1403
}
1404

1405
namespace {
1406
bool _create_tag_directive_from_str(csubstr directive_, TagDirective *td, Tree *tree)
2,832✔
1407
{
1408
    _RYML_CHECK_BASIC_(tree->callbacks(), directive_.begins_with("%TAG "));
2,832✔
1409
    if(!td->create_from_str(directive_))
2,828✔
1410
    {
1411
        _RYML_ERR_BASIC_(tree->callbacks(), "invalid tag directive");
8✔
1412
    }
1413
    td->next_node_id = tree->size();
2,820✔
1414
    if(!tree->empty())
2,820✔
1415
    {
1416
        const id_type prev = tree->size() - 1;
2,820✔
1417
        if(tree->is_root(prev) && tree->type(prev) != NOTYPE && !tree->is_stream(prev))
4,840✔
1418
            ++td->next_node_id;
76✔
1419
    }
1420
    _c4dbgpf("%TAG: handle={} prefix={} next_node={}", td->handle, td->prefix, td->next_node_id);
1421
    return true;
2,820✔
1422
}
1423
} // namespace
1424

1425
bool Tree::add_tag_directive(csubstr directive_)
2,832✔
1426
{
1427
    TagDirective td;
2,832✔
1428
    if(_create_tag_directive_from_str(directive_, &td, this))
2,832✔
1429
    {
1430
        add_tag_directive(td);
2,820✔
1431
        return true;
2,812✔
1432
    }
1433
    return false;
×
1434
}
1435

1436
size_t Tree::resolve_tag(substr output, csubstr tag, id_type node_id) const
13,012✔
1437
{
1438
    // lookup from the end. We want to find the first directive that
1439
    // matches the tag and has a target node id leq than the given
1440
    // node_id.
1441
    for(id_type i = RYML_MAX_TAG_DIRECTIVES-1; i != (id_type)-1; --i)
59,696✔
1442
    {
1443
        auto const& td = m_tag_directives[i];
51,788✔
1444
        if(td.handle.empty())
103,576✔
1445
            continue;
40,164✔
1446
        if(tag.begins_with(td.handle) && td.next_node_id <= node_id)
11,624✔
1447
            return td.transform(tag, output, m_callbacks);
5,104✔
1448
    }
1449
    if(tag.begins_with('!'))
7,908✔
1450
    {
1451
        if(is_custom_tag(tag))
5,244✔
1452
        {
1453
            _RYML_ERR_VISIT_(m_callbacks, this, node_id, "tag directive not found");
8✔
1454
        }
1455
    }
1456
    return 0; // return 0 to signal that the tag is local and cannot be resolved
7,900✔
1457
}
1458

1459
namespace {
1460
csubstr _transform_tag(Tree *t, csubstr tag, id_type node)
4,436✔
1461
{
1462
    _c4dbgpf("[{}] resolving tag ~~~{}~~~", node, tag);
1463
    size_t required_size = t->resolve_tag(substr{}, tag, node);
4,436✔
1464
    if(!required_size)
4,436✔
1465
    {
1466
        if(tag.begins_with("!<"))
3,572✔
1467
            tag = tag.sub(1);
2,716✔
1468
        _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, tag);
1469
        return tag;
3,572✔
1470
    }
1471
    const char *prev_arena = t->arena().str;(void)prev_arena;
864✔
1472
    substr buf = t->alloc_arena(required_size);
864✔
1473
    _RYML_ASSERT_VISIT_(t->m_callbacks, t->arena().str == prev_arena, t, node);
864✔
1474
    size_t actual_size = t->resolve_tag(buf, tag, node);
864✔
1475
    _RYML_ASSERT_VISIT_(t->m_callbacks, actual_size <= required_size, t, node);
864✔
1476
    _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, buf.first(actual_size));
1477
    return buf.first(actual_size);
1,728✔
1478
}
1479
void _resolve_tags(Tree *t, id_type node)
10,100✔
1480
{
1481
    NodeData *C4_RESTRICT d = t->_p(node);
10,100✔
1482
    if(d->m_type & KEYTAG)
30,300✔
1483
        d->m_key.tag = _transform_tag(t, d->m_key.tag, node);
8✔
1484
    if(d->m_type & VALTAG)
30,300✔
1485
        d->m_val.tag = _transform_tag(t, d->m_val.tag, node);
4,428✔
1486
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
17,860✔
1487
        _resolve_tags(t, child);
7,760✔
1488
}
10,100✔
1489
size_t _count_resolved_tags_size(Tree const* t, id_type node)
10,188✔
1490
{
1491
    size_t sz = 0;
10,188✔
1492
    NodeData const* C4_RESTRICT d = t->_p(node);
10,188✔
1493
    if(d->m_type & KEYTAG)
30,564✔
1494
        sz += t->resolve_tag(substr{}, d->m_key.tag, node);
8✔
1495
    if(d->m_type & VALTAG)
30,564✔
1496
        sz += t->resolve_tag(substr{}, d->m_val.tag, node);
4,464✔
1497
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
17,920✔
1498
        sz += _count_resolved_tags_size(t, child);
7,816✔
1499
    return sz;
10,104✔
1500
}
1501
void _normalize_tags(Tree *t, id_type node)
84✔
1502
{
1503
    NodeData *C4_RESTRICT d = t->_p(node);
84✔
1504
    if(d->m_type & KEYTAG)
252✔
1505
        d->m_key.tag = normalize_tag(d->m_key.tag);
4✔
1506
    if(d->m_type & VALTAG)
252✔
1507
        d->m_val.tag = normalize_tag(d->m_val.tag);
40✔
1508
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
164✔
1509
        _normalize_tags(t, child);
80✔
1510
}
84✔
1511
void _normalize_tags_long(Tree *t, id_type node)
778,548✔
1512
{
1513
    NodeData *C4_RESTRICT d = t->_p(node);
778,548✔
1514
    if(d->m_type & KEYTAG)
2,335,644✔
1515
        d->m_key.tag = normalize_tag_long(d->m_key.tag);
5,636✔
1516
    if(d->m_type & VALTAG)
2,335,644✔
1517
        d->m_val.tag = normalize_tag_long(d->m_val.tag);
36,456✔
1518
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1,348,804✔
1519
        _normalize_tags_long(t, child);
570,256✔
1520
}
778,548✔
1521
} // namespace
1522

1523
void Tree::resolve_tags()
2,376✔
1524
{
1525
    if(empty())
2,376✔
1526
        return;
4✔
1527
    size_t needed_size = _count_resolved_tags_size(this, root_id());
2,372✔
1528
    if(needed_size)
2,340✔
1529
        reserve_arena(arena_size() + needed_size);
592✔
1530
    _resolve_tags(this, root_id());
2,340✔
1531
}
1532

1533
void Tree::normalize_tags()
4✔
1534
{
1535
    if(empty())
4✔
1536
        return;
×
1537
    _normalize_tags(this, root_id());
4✔
1538
}
1539

1540
void Tree::normalize_tags_long()
208,292✔
1541
{
1542
    if(empty())
208,292✔
1543
        return;
×
1544
    _normalize_tags_long(this, root_id());
208,292✔
1545
}
1546

1547

1548
//-----------------------------------------------------------------------------
1549

1550
csubstr Tree::lookup_result::resolved() const
20✔
1551
{
1552
    csubstr p = path.first(path_pos);
20✔
1553
    if(p.ends_with('.'))
20✔
1554
        p = p.first(p.len-1);
24✔
1555
    return p;
20✔
1556
}
1557

1558
csubstr Tree::lookup_result::unresolved() const
2,656✔
1559
{
1560
    return path.sub(path_pos);
5,312✔
1561
}
1562

1563
void Tree::_advance(lookup_result *r, size_t more)
1,036✔
1564
{
1565
    r->path_pos += more;
1,036✔
1566
    if(r->path.sub(r->path_pos).begins_with('.'))
2,072✔
1567
        ++r->path_pos;
160✔
1568
}
1,036✔
1569

1570
Tree::lookup_result Tree::lookup_path(csubstr path, id_type start) const
172✔
1571
{
1572
    if(start == NONE)
172✔
1573
        start = root_id();
120✔
1574
    lookup_result r(path, start);
172✔
1575
    if(path.empty())
172✔
1576
        return r;
×
1577
    _lookup_path(&r);
172✔
1578
    if(r.target == NONE && r.closest == start)
172✔
1579
        r.closest = NONE;
12✔
1580
    return r;
172✔
1581
}
1582

1583
id_type Tree::lookup_path_or_modify(csubstr default_value, csubstr path, id_type start)
88✔
1584
{
1585
    id_type target = _lookup_path_or_create(path, start);
88✔
1586
    if(parent_is_map(target))
88✔
1587
        to_keyval(target, key(target), default_value);
56✔
1588
    else
1589
        to_val(target, default_value);
32✔
1590
    return target;
88✔
1591
}
1592

1593
id_type Tree::lookup_path_or_modify(Tree const *src, id_type src_node, csubstr path, id_type start)
4✔
1594
{
1595
    id_type target = _lookup_path_or_create(path, start);
4✔
1596
    merge_with(src, src_node, target);
4✔
1597
    return target;
4✔
1598
}
1599

1600
id_type Tree::_lookup_path_or_create(csubstr path, id_type start)
92✔
1601
{
1602
    if(start == NONE)
92✔
1603
        start = root_id();
92✔
1604
    lookup_result r(path, start);
92✔
1605
    _lookup_path(&r);
92✔
1606
    if(r.target != NONE)
92✔
1607
    {
1608
        C4_ASSERT(r.unresolved().empty());
96✔
1609
        return r.target;
48✔
1610
    }
1611
    _lookup_path_modify(&r);
44✔
1612
    return r.target;
44✔
1613
}
1614

1615
void Tree::_lookup_path(lookup_result *r) const
264✔
1616
{
1617
    C4_ASSERT( ! r->unresolved().empty());
528✔
1618
    _lookup_path_token parent{"", type(r->closest)};
264✔
1619
    id_type node;
1620
    do
1621
    {
1622
        node = _next_node(r, &parent);
924✔
1623
        if(node != NONE)
924✔
1624
            r->closest = node;
848✔
1625
        if(r->unresolved().empty())
1,848✔
1626
        {
1627
            r->target = node;
188✔
1628
            return;
188✔
1629
        }
1630
    } while(node != NONE);
736✔
1631
}
1632

1633
void Tree::_lookup_path_modify(lookup_result *r)
44✔
1634
{
1635
    C4_ASSERT( ! r->unresolved().empty());
88✔
1636
    _lookup_path_token parent{"", type(r->closest)};
44✔
1637
    id_type node;
1638
    do
1639
    {
1640
        node = _next_node_modify(r, &parent);
112✔
1641
        if(node != NONE)
112✔
1642
            r->closest = node;
112✔
1643
        if(r->unresolved().empty())
224✔
1644
        {
1645
            r->target = node;
44✔
1646
            return;
44✔
1647
        }
1648
    } while(node != NONE);
68✔
1649
}
1650

1651
id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const
924✔
1652
{
1653
    _lookup_path_token token = _next_token(r, *parent);
924✔
1654
    if( ! token)
924✔
1655
        return NONE;
×
1656

1657
    id_type node = NONE;
924✔
1658
    csubstr prev = token.value;
924✔
1659
    if(token.type == MAP || token.type == SEQ)
1,560✔
1660
    {
1661
        _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
504✔
1662
        //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1663
        _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1,008✔
1664
        node = find_child(r->closest, token.value);
504✔
1665
    }
1666
    else if(token.type == KEYVAL)
420✔
1667
    {
1668
        _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
352✔
1669
        if(is_map(r->closest))
352✔
1670
            node = find_child(r->closest, token.value);
172✔
1671
    }
1672
    else if(token.type == KEY)
244✔
1673
    {
1674
        _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
244✔
1675
        token.value = token.value.offs(1, 1).trim(' ');
244✔
1676
        id_type idx = 0;
244✔
1677
        _RYML_CHECK_BASIC_(m_callbacks, from_chars(token.value, &idx));
244✔
1678
        node = child(r->closest, idx);
244✔
1679
    }
1680
    else
1681
    {
1682
        C4_NEVER_REACH();
×
1683
    }
1684

1685
    if(node != NONE)
924✔
1686
    {
1687
        *parent = token;
848✔
1688
    }
1689
    else
1690
    {
1691
        csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
76✔
1692
        r->path_pos -= prev.len;
76✔
1693
        if(p.begins_with('.'))
76✔
1694
            r->path_pos -= 1u;
16✔
1695
    }
1696

1697
    return node;
924✔
1698
}
1699

1700
id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
112✔
1701
{
1702
    _lookup_path_token token = _next_token(r, *parent);
112✔
1703
    if( ! token)
112✔
1704
        return NONE;
×
1705

1706
    id_type node = NONE;
112✔
1707
    if(token.type == MAP || token.type == SEQ)
200✔
1708
    {
1709
        _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
44✔
1710
        //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1711
        if( ! is_container(r->closest))
88✔
1712
        {
1713
            if(has_key(r->closest))
56✔
1714
                to_map(r->closest, key(r->closest));
20✔
1715
            else
1716
                to_map(r->closest);
8✔
1717
        }
1718
        else
1719
        {
1720
            if(is_map(r->closest))
32✔
1721
                node = find_child(r->closest, token.value);
16✔
1722
            else
1723
            {
1724
                id_type pos = NONE;
×
NEW
1725
                _RYML_CHECK_BASIC_(m_callbacks, c4::atox(token.value, &pos));
×
NEW
1726
                _RYML_ASSERT_VISIT_(m_callbacks, pos != NONE, this, r->closest);
×
UNCOV
1727
                node = child(r->closest, pos);
×
1728
            }
1729
        }
1730
        if(node == NONE)
44✔
1731
        {
1732
            _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
88✔
1733
            node = append_child(r->closest);
44✔
1734
            NodeData *n = _p(node);
44✔
1735
            n->m_key.scalar = token.value;
44✔
1736
            n->m_type.add(KEY);
44✔
1737
        }
1738
    }
1739
    else if(token.type == KEYVAL)
68✔
1740
    {
1741
        _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
64✔
1742
        if(is_map(r->closest))
64✔
1743
        {
1744
            node = find_child(r->closest, token.value);
20✔
1745
            if(node == NONE)
20✔
1746
                node = append_child(r->closest);
40✔
1747
        }
1748
        else
1749
        {
1750
            _RYML_ASSERT_VISIT_(m_callbacks, !is_seq(r->closest), this, r->closest);
24✔
1751
            _add_flags(r->closest, MAP);
12✔
1752
            node = append_child(r->closest);
24✔
1753
        }
1754
        NodeData *n = _p(node);
32✔
1755
        n->m_key.scalar = token.value;
32✔
1756
        n->m_val.scalar = "";
32✔
1757
        n->m_type.add(KEYVAL);
32✔
1758
    }
1759
    else if(token.type == KEY)
36✔
1760
    {
1761
        _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
36✔
1762
        token.value = token.value.offs(1, 1).trim(' ');
36✔
1763
        id_type idx;
1764
        if( ! from_chars(token.value, &idx))
36✔
1765
             return NONE;
×
1766
        if( ! is_container(r->closest))
72✔
1767
        {
1768
            if(has_key(r->closest))
56✔
1769
            {
1770
                csubstr k = key(r->closest);
20✔
1771
                _clear_type(r->closest);
20✔
1772
                to_seq(r->closest, k);
20✔
1773
            }
1774
            else
1775
            {
1776
                _clear_type(r->closest);
8✔
1777
                to_seq(r->closest);
8✔
1778
            }
1779
        }
1780
        _RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest), this, r->closest);
72✔
1781
        node = child(r->closest, idx);
36✔
1782
        if(node == NONE)
36✔
1783
        {
1784
            _RYML_ASSERT_VISIT_(m_callbacks, num_children(r->closest) <= idx, this, r->closest);
36✔
1785
            for(id_type i = num_children(r->closest); i <= idx; ++i)
112✔
1786
            {
1787
                node = append_child(r->closest);
76✔
1788
                if(i < idx)
76✔
1789
                {
1790
                    if(is_map(r->closest))
80✔
1791
                        to_keyval(node, /*"~"*/{}, /*"~"*/{});
×
1792
                    else if(is_seq(r->closest))
80✔
1793
                        to_val(node, /*"~"*/{});
40✔
1794
                }
1795
            }
1796
        }
1797
    }
1798
    else
1799
    {
1800
        C4_NEVER_REACH();
×
1801
    }
1802

1803
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, r->closest);
112✔
1804
    *parent = token;
112✔
1805
    return node;
112✔
1806
}
1807

1808
/* types of tokens:
1809
 * - seeing "map."  ---> "map"/MAP
1810
 * - finishing "scalar" ---> "scalar"/KEYVAL
1811
 * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)
1812
 * - seeing "[n]" ---> "[n]"/KEY
1813
 */
1814
Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const
1,036✔
1815
{
1816
    csubstr unres = r->unresolved();
1,036✔
1817
    if(unres.empty())
1,036✔
1818
        return {};
×
1819

1820
    // is it an indexation like [0], [1], etc?
1821
    if(unres.begins_with('['))
1,036✔
1822
    {
1823
        size_t pos = unres.find(']');
280✔
1824
        if(pos == csubstr::npos)
280✔
1825
            return {};
×
1826
        csubstr idx = unres.first(pos + 1);
280✔
1827
        _advance(r, pos + 1);
280✔
1828
        return {idx, KEY};
280✔
1829
    }
1830

1831
    // no. so it must be a name
1832
    size_t pos = unres.first_of(".[");
756✔
1833
    if(pos == csubstr::npos)
756✔
1834
    {
1835
        _advance(r, unres.len);
208✔
1836
        NodeType t;
1837
        if(( ! parent) || parent.type.is_seq())
416✔
1838
            return {unres, VAL};
×
1839
        return {unres, KEYVAL};
208✔
1840
    }
1841

1842
    // it's either a map or a seq
1843
    _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '.' || unres[pos] == '[', this, r->closest);
784✔
1844
    if(unres[pos] == '.')
548✔
1845
    {
1846
        _RYML_ASSERT_VISIT_(m_callbacks, pos != 0, this, r->closest);
312✔
1847
        _advance(r, pos + 1);
312✔
1848
        return {unres.first(pos), MAP};
312✔
1849
    }
1850

1851
    _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '[', this, r->closest);
236✔
1852
    _advance(r, pos);
236✔
1853
    return {unres.first(pos), SEQ};
236✔
1854
}
1855

1856

1857
} // namespace yml
1858
} // namespace c4
1859

1860

1861
//-----------------------------------------------------------------------------
1862
//-----------------------------------------------------------------------------
1863
//-----------------------------------------------------------------------------
1864

1865
#include "c4/yml/event_handler_tree.hpp"
1866
#include "c4/yml/parse_engine.def.hpp"
1867
#include "c4/yml/parse.hpp"
1868

1869
namespace c4 {
1870
namespace yml {
1871

1872
Location Tree::location(Parser const& parser, id_type node) const
1,444✔
1873
{
1874
    // try hard to avoid getting the location from a null string.
1875
    Location loc;
1,444✔
1876
    if(_location_from_node(parser, node, &loc, 0))
1,444✔
1877
        return loc;
1,432✔
1878
    return parser.val_location(parser.source().str);
8✔
1879
}
1880

1881
bool Tree::_location_from_node(Parser const& parser, id_type node, Location *C4_RESTRICT loc, id_type level) const
1,532✔
1882
{
1883
    if(has_key(node))
1,532✔
1884
    {
1885
        csubstr k = key(node);
712✔
1886
        if(C4_LIKELY(k.str != nullptr))
712✔
1887
        {
1888
            _RYML_ASSERT_BASIC_(m_callbacks, k.is_sub(parser.source()));
1,352✔
1889
            _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(k));
1,352✔
1890
            *loc = parser.val_location(k.str);
676✔
1891
            return true;
672✔
1892
        }
1893
    }
1894

1895
    if(has_val(node))
856✔
1896
    {
1897
        csubstr v = val(node);
496✔
1898
        if(C4_LIKELY(v.str != nullptr))
496✔
1899
        {
1900
            _RYML_ASSERT_BASIC_(m_callbacks, v.is_sub(parser.source()));
816✔
1901
            _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(v));
816✔
1902
            *loc = parser.val_location(v.str);
408✔
1903
            return true;
408✔
1904
        }
1905
    }
1906

1907
    if(is_container(node))
448✔
1908
    {
1909
        if(_location_from_cont(parser, node, loc))
352✔
1910
            return true;
352✔
1911
    }
1912

1913
    if(type(node) != NOTYPE && level == 0)
192✔
1914
    {
1915
        // try the prev sibling
1916
        {
1917
            const id_type prev = prev_sibling(node);
44✔
1918
            if(prev != NONE)
44✔
1919
            {
1920
                if(_location_from_node(parser, prev, loc, level+1))
32✔
1921
                    return true;
8✔
1922
            }
1923
        }
1924
        // try the next sibling
1925
        {
1926
            const id_type next = next_sibling(node);
36✔
1927
            if(next != NONE)
36✔
1928
            {
1929
                if(_location_from_node(parser, next, loc, level+1))
28✔
1930
                    return true;
8✔
1931
            }
1932
        }
1933
        // try the parent
1934
        {
1935
            const id_type parent = this->parent(node);
28✔
1936
            if(parent != NONE)
28✔
1937
            {
1938
                if(_location_from_node(parser, parent, loc, level+1))
28✔
1939
                    return true;
28✔
1940
            }
1941
        }
1942
    }
1943
    return false;
52✔
1944
}
1945

1946
bool Tree::_location_from_cont(Parser const& parser, id_type node, Location *C4_RESTRICT loc) const
352✔
1947
{
1948
    _RYML_ASSERT_BASIC_(m_callbacks, is_container(node));
352✔
1949
    if(!is_stream(node))
352✔
1950
    {
1951
        const char *node_start = _p(node)->m_val.scalar.str;  // this was stored in the container
328✔
1952
        if(has_children(node))
328✔
1953
        {
1954
            id_type child = first_child(node);
280✔
1955
            if(has_key(child))
280✔
1956
            {
1957
                // when a map starts, the container was set after the key
1958
                csubstr k = key(child);
84✔
1959
                if(k.str && node_start > k.str)
84✔
1960
                    node_start = k.str;
64✔
1961
            }
1962
        }
1963
        *loc = parser.val_location(node_start);
328✔
1964
        return true;
328✔
1965
    }
1966
    else // it's a stream
1967
    {
1968
        *loc = parser.val_location(parser.source().str); // just return the front of the buffer
24✔
1969
    }
1970
    return true;
24✔
1971
}
1972

1973
} // namespace yml
1974
} // namespace c4
1975

1976

1977
C4_SUPPRESS_WARNING_GCC_CLANG_POP
1978
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

© 2025 Coveralls, Inc