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

biojppm / rapidyaml / 18649960093

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

Pull #503

github

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

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

38 existing lines in 4 files now uncovered.

13623 of 13952 relevant lines covered (97.64%)

537812.42 hits per line

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

95.49
/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()
99,588✔
22
{
23
    return NodeRef(this, root_id());
99,588✔
24
}
25
ConstNodeRef Tree::rootref() const
71,691✔
26
{
27
    return ConstNodeRef(this, root_id());
71,691✔
28
}
29

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

35
NodeRef Tree::ref(id_type id)
2,886✔
36
{
37
    _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
2,886✔
38
    return NodeRef(this, id);
2,718✔
39
}
40
ConstNodeRef Tree::ref(id_type id) const
60✔
41
{
42
    _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
60✔
43
    return ConstNodeRef(this, id);
60✔
44
}
45
ConstNodeRef Tree::cref(id_type id) const
4,506✔
46
{
47
    _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
4,506✔
48
    return ConstNodeRef(this, id);
4,482✔
49
}
50

51
NodeRef Tree::operator[] (csubstr key)
8,316✔
52
{
53
    return rootref()[key];
16,632✔
54
}
55
ConstNodeRef Tree::operator[] (csubstr key) const
11,163✔
56
{
57
    return rootref()[key];
22,308✔
58
}
59

60
NodeRef Tree::operator[] (id_type i)
1,800✔
61
{
62
    return rootref()[i];
3,600✔
63
}
64
ConstNodeRef Tree::operator[] (id_type i) const
5,958✔
65
{
66
    return rootref()[i];
11,904✔
67
}
68

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

82

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

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

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

109

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

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

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

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

142
void Tree::_free()
1,289,034✔
143
{
144
    if(m_buf)
1,289,034✔
145
    {
146
        _RYML_ASSERT_VISIT_(m_callbacks, m_cap > 0, this, NONE);
613,985✔
147
        _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
613,985✔
148
    }
149
    if(m_arena.str)
1,289,034✔
150
    {
151
        _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len > 0, this, NONE);
159,769✔
152
        _RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);
159,769✔
153
    }
154
    _clear();
1,289,034✔
155
}
1,289,034✔
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,574,064✔
164
{
165
    m_buf = nullptr;
1,574,064✔
166
    m_cap = 0;
1,574,064✔
167
    m_size = 0;
1,574,064✔
168
    m_free_head = 0;
1,574,064✔
169
    m_free_tail = 0;
1,574,064✔
170
    m_arena = {};
1,574,064✔
171
    m_arena_pos = 0;
1,574,064✔
172
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
7,870,320✔
173
        m_tag_directives[i] = {};
6,296,256✔
174
}
1,574,064✔
175

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

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

222
void Tree::_relocate(substr next_arena)
5,658✔
223
{
224
    _RYML_ASSERT_VISIT_(m_callbacks, next_arena.not_empty(), this, NONE);
5,658✔
225
    _RYML_ASSERT_VISIT_(m_callbacks, next_arena.len >= m_arena.len, this, NONE);
5,658✔
226
    if(m_arena_pos)
5,658✔
227
        memcpy(next_arena.str, m_arena.str, m_arena_pos);
5,640✔
228
    for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n)
103,926✔
229
    {
230
        if(in_arena(n->m_key.scalar))
98,268✔
231
            n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
5,592✔
232
        if(in_arena(n->m_key.tag))
98,268✔
233
            n->m_key.tag = _relocated(n->m_key.tag, next_arena);
132✔
234
        if(in_arena(n->m_key.anchor))
98,268✔
235
            n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
720✔
236
        if(in_arena(n->m_val.scalar))
98,268✔
237
            n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
20,148✔
238
        if(in_arena(n->m_val.tag))
98,268✔
239
            n->m_val.tag = _relocated(n->m_val.tag, next_arena);
2,316✔
240
        if(in_arena(n->m_val.anchor))
98,268✔
241
            n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
720✔
242
    }
243
    for(TagDirective &C4_RESTRICT td : m_tag_directives)
28,290✔
244
    {
245
        if(in_arena(td.prefix))
22,632✔
246
            td.prefix = _relocated(td.prefix, next_arena);
1,032✔
247
        if(in_arena(td.handle))
22,632✔
248
            td.handle = _relocated(td.handle, next_arena);
1,032✔
249
    }
250
}
5,658✔
251

252

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

285
        if( ! m_size)
621,376✔
286
            _claim_root();
615,394✔
287
    }
288
}
633,322✔
289

290

291
//-----------------------------------------------------------------------------
292
void Tree::clear()
318,618✔
293
{
294
    _clear_range(0, m_cap);
318,618✔
295
    m_size = 0;
318,618✔
296
    if(m_buf)
318,618✔
297
    {
298
        _RYML_ASSERT_VISIT_(m_callbacks, m_cap >= 0, this, NONE);
299
        m_free_head = 0;
37,920✔
300
        m_free_tail = m_cap-1;
37,920✔
301
        _claim_root();
37,920✔
302
    }
303
    else
304
    {
305
        m_free_head = NONE;
280,698✔
306
        m_free_tail = NONE;
280,698✔
307
    }
308
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
1,593,090✔
309
        m_tag_directives[i] = {};
1,274,472✔
310
}
318,618✔
311

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

319

320
//-----------------------------------------------------------------------------
321
void Tree::_clear_range(id_type first, id_type num)
939,994✔
322
{
323
    if(num == 0)
939,994✔
324
        return; // prevent overflow when subtracting
280,698✔
325
    _RYML_ASSERT_VISIT_(m_callbacks, first >= 0 && first + num <= m_cap, this, first);
659,296✔
326
    memset(m_buf + first, 0, (size_t)num * sizeof(NodeData)); // TODO we should not need this
659,296✔
327
    for(id_type i = first, e = first + num; i < e; ++i)
11,129,930✔
328
    {
329
        _clear(i);
10,470,634✔
330
        NodeData *n = m_buf + i;
10,470,634✔
331
        n->m_prev_sibling = i - 1;
10,470,634✔
332
        n->m_next_sibling = i + 1;
10,470,634✔
333
    }
334
    m_buf[first + num - 1].m_next_sibling = NONE;
659,296✔
335
}
336

337
C4_SUPPRESS_WARNING_GCC_POP
338

339

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

345
    _rem_hierarchy(i);
118,914✔
346
    _free_list_add(i);
118,914✔
347
    _clear(i);
118,914✔
348

349
    --m_size;
118,914✔
350
}
118,914✔
351

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

359
    w.m_parent = NONE;
119,022✔
360
    w.m_next_sibling = m_free_head;
119,022✔
361
    w.m_prev_sibling = NONE;
119,022✔
362
    if(m_free_head != NONE)
119,022✔
363
        m_buf[m_free_head].m_prev_sibling = i;
118,974✔
364
    m_free_head = i;
119,022✔
365
    if(m_free_tail == NONE)
119,022✔
366
        m_free_tail = m_free_head;
48✔
367
}
119,022✔
368

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

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

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

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

393
    ++m_size;
1,911,194✔
394
    m_free_head = child->m_next_sibling;
1,911,194✔
395
    if(m_free_head == NONE)
1,911,194✔
396
    {
397
        m_free_tail = NONE;
13,722✔
398
        _RYML_ASSERT_VISIT_(m_callbacks, m_size == m_cap, this, NONE);
13,722✔
399
    }
400

401
    _clear(ichild);
1,911,194✔
402

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

426
    NodeData *C4_RESTRICT child = _p(ichild);
1,911,752✔
427

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

432
    if(iparent == NONE)
1,911,752✔
433
    {
434
        _RYML_ASSERT_VISIT_(m_callbacks, ichild == 0, this, ichild);
653,314✔
435
        _RYML_ASSERT_VISIT_(m_callbacks, iprev_sibling == NONE, this, iprev_sibling);
653,314✔
436
    }
437

438
    if(iparent == NONE)
1,911,752✔
439
        return;
653,314✔
440

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

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

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

462
    if(parent->m_first_child == NONE)
1,258,438✔
463
    {
464
        _RYML_ASSERT_VISIT_(m_callbacks, parent->m_last_child == NONE, this, parent->m_last_child);
595,390✔
465
        parent->m_first_child = id(child);
595,390✔
466
        parent->m_last_child = id(child);
595,390✔
467
    }
468
    else
469
    {
470
        if(child->m_next_sibling == parent->m_first_child)
663,048✔
471
            parent->m_first_child = id(child);
360✔
472

473
        if(child->m_prev_sibling == parent->m_last_child)
663,048✔
474
            parent->m_last_child = id(child);
662,244✔
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)
119,580✔
484
{
485
    _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
119,580✔
486

487
    NodeData &C4_RESTRICT w = m_buf[i];
119,580✔
488

489
    // remove from the parent
490
    if(w.m_parent != NONE)
119,580✔
491
    {
492
        NodeData &C4_RESTRICT p = m_buf[w.m_parent];
119,472✔
493
        if(p.m_first_child == i)
119,472✔
494
        {
495
            p.m_first_child = w.m_next_sibling;
10,122✔
496
        }
497
        if(p.m_last_child == i)
119,472✔
498
        {
499
            p.m_last_child = w.m_prev_sibling;
117,864✔
500
        }
501
    }
502

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

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

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

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

545

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

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

586
    for(id_type i = first_child(ia); i != NONE; i = next_sibling(i))
684✔
587
    {
588
        if(i == ib || i == ia)
216✔
589
            continue;
12✔
590
        _p(i)->m_parent = ib;
204✔
591
    }
592

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

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

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

650
    if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
468✔
651
       a.m_next_sibling != ib && b.m_next_sibling != ia)
408✔
652
    {
653
        if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib)
408✔
654
            _p(a.m_prev_sibling)->m_next_sibling = ib;
252✔
655
        if(a.m_next_sibling != NONE && a.m_next_sibling != ib)
408✔
656
            _p(a.m_next_sibling)->m_prev_sibling = ib;
276✔
657
        if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia)
408✔
658
            _p(b.m_prev_sibling)->m_next_sibling = ia;
252✔
659
        if(b.m_next_sibling != NONE && b.m_next_sibling != ia)
408✔
660
            _p(b.m_next_sibling)->m_prev_sibling = ia;
180✔
661
        std::swap(a.m_prev_sibling, b.m_prev_sibling);
408✔
662
        std::swap(a.m_next_sibling, b.m_next_sibling);
408✔
663
    }
664
    else
665
    {
666
        if(a.m_next_sibling == ib) // n will go after m
60✔
667
        {
668
            _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling == ia, this, ia);
60✔
669
            if(a.m_prev_sibling != NONE)
60✔
670
            {
671
                _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ib, this, ib);
48✔
672
                _p(a.m_prev_sibling)->m_next_sibling = ib;
48✔
673
            }
674
            if(b.m_next_sibling != NONE)
60✔
675
            {
676
                _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ia, this, ia);
24✔
677
                _p(b.m_next_sibling)->m_prev_sibling = ia;
24✔
678
            }
679
            id_type ns = b.m_next_sibling;
60✔
680
            b.m_prev_sibling = a.m_prev_sibling;
60✔
681
            b.m_next_sibling = ia;
60✔
682
            a.m_prev_sibling = ib;
60✔
683
            a.m_next_sibling = ns;
60✔
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);
468✔
710
    _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ia, this, ia);
468✔
711
    _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ib, this, ib);
468✔
712
    _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling != ib, this, ib);
468✔
713

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

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

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

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

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

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

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

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

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

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

820
void Tree::set_root_as_stream()
99,342✔
821
{
822
    id_type root = root_id();
99,342✔
823
    if(is_stream(root))
99,342✔
824
        return;
234✔
825
    // don't use _add_flags() because it's checked and will fail
826
    if(!has_children(root))
99,108✔
827
    {
828
        if(is_container(root))
98,754✔
829
        {
830
            id_type next_doc = append_child(root);
24✔
831
            _copy_props_wo_key(next_doc, root);
24✔
832
            _p(next_doc)->m_type.add(DOC);
24✔
833
        }
834
        else
835
        {
836
            _p(root)->m_type.add(SEQ);
98,730✔
837
            id_type next_doc = append_child(root);
98,730✔
838
            _copy_props_wo_key(next_doc, root);
98,730✔
839
            _p(next_doc)->m_type.add(DOC);
98,730✔
840
            _p(next_doc)->m_type.rem(SEQ);
98,730✔
841
        }
842
        _p(root)->m_type = STREAM;
98,754✔
843
        return;
98,754✔
844
    }
845
    _RYML_ASSERT_VISIT_(m_callbacks, !has_key(root), this, root);
354✔
846
    id_type next_doc = append_child(root);
354✔
847
    _copy_props_wo_key(next_doc, root);
354✔
848
    _add_flags(next_doc, DOC);
354✔
849
    for(id_type prev = NONE, ch = first_child(root), next = next_sibling(ch); ch != NONE; )
846✔
850
    {
851
        if(ch == next_doc)
846✔
852
            break;
354✔
853
        move(ch, next_doc, prev);
492✔
854
        prev = ch;
492✔
855
        ch = next;
492✔
856
        next = next_sibling(next);
492✔
857
    }
858
    _p(root)->m_type = STREAM;
354✔
859
}
860

861

862
//-----------------------------------------------------------------------------
863
void Tree::remove_children(id_type node)
119,022✔
864
{
865
    _RYML_ASSERT_VISIT_(m_callbacks, get(node) != nullptr, this, node);
119,022✔
866
    #if __GNUC__ >= 6
867
    C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wnull-dereference")
868
    #endif
869
    id_type ich = get(node)->m_first_child;
119,022✔
870
    #if __GNUC__ >= 6
871
    C4_SUPPRESS_WARNING_GCC_POP
872
    #endif
873
    while(ich != NONE)
120,048✔
874
    {
875
        remove_children(ich);
1,026✔
876
        _RYML_ASSERT_VISIT_(m_callbacks, get(ich) != nullptr, this, node);
1,026✔
877
        id_type next = get(ich)->m_next_sibling;
1,026✔
878
        _release(ich);
1,026✔
879
        if(ich == get(node)->m_last_child)
1,026✔
880
            break;
×
881
        ich = next;
1,026✔
882
    }
883
}
119,022✔
884

885
bool Tree::change_type(id_type node, NodeType type)
108✔
886
{
887
    _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() || type.is_map() || type.is_seq(), this, node);
216✔
888
    _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1, this, node);
324✔
889
    _RYML_ASSERT_VISIT_(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()), this, node);
324✔
890
    NodeData *d = _p(node);
108✔
891
    if(type.is_map() && is_map(node))
144✔
892
        return false;
12✔
893
    else if(type.is_seq() && is_seq(node))
132✔
894
        return false;
12✔
895
    else if(type.is_val() && is_val(node))
120✔
896
        return false;
6✔
897
    d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type;
546✔
898
    remove_children(node);
78✔
899
    return true;
78✔
900
}
901

902

903
//-----------------------------------------------------------------------------
904
id_type Tree::duplicate(id_type node, id_type parent, id_type after)
18✔
905
{
906
    return duplicate(this, node, parent, after);
18✔
907
}
908

909
id_type Tree::duplicate(Tree const* src, id_type node, id_type parent, id_type after)
1,698✔
910
{
911
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
1,698✔
912
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1,698✔
913
    _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
1,698✔
914
    _RYML_ASSERT_VISIT_(m_callbacks,  ! src->is_root(node), src, node);
1,698✔
915

916
    id_type copy = _claim();
1,698✔
917

918
    _copy_props(copy, src, node);
1,698✔
919
    _set_hierarchy(copy, parent, after);
1,698✔
920
    duplicate_children(src, node, copy, NONE);
1,698✔
921

922
    return copy;
1,698✔
923
}
924

925
//-----------------------------------------------------------------------------
926
id_type Tree::duplicate_children(id_type node, id_type parent, id_type after)
×
927
{
928
    return duplicate_children(this, node, parent, after);
×
929
}
930

931
id_type Tree::duplicate_children(Tree const* src, id_type node, id_type parent, id_type after)
2,016✔
932
{
933
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
2,016✔
934
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
2,016✔
935
    _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
2,016✔
936
    _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
2,016✔
937

938
    id_type prev = after;
2,016✔
939
    for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
3,204✔
940
    {
941
        prev = duplicate(src, i, parent, prev);
1,188✔
942
    }
943

944
    return prev;
2,016✔
945
}
946

947
//-----------------------------------------------------------------------------
948
void Tree::duplicate_contents(id_type node, id_type where)
318✔
949
{
950
    duplicate_contents(this, node, where);
318✔
951
}
318✔
952

953
void Tree::duplicate_contents(Tree const *src, id_type node, id_type where)
318✔
954
{
955
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
318✔
956
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
318✔
957
    _RYML_ASSERT_VISIT_(m_callbacks, where != NONE, this, where);
318✔
958
    _copy_props_wo_key(where, src, node);
318✔
959
    duplicate_children(src, node, where, last_child(where));
318✔
960
}
318✔
961

962
//-----------------------------------------------------------------------------
963
id_type Tree::duplicate_children_no_rep(id_type node, id_type parent, id_type after)
300✔
964
{
965
    return duplicate_children_no_rep(this, node, parent, after);
300✔
966
}
967

968
id_type Tree::duplicate_children_no_rep(Tree const *src, id_type node, id_type parent, id_type after)
318✔
969
{
970
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
318✔
971
    _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
318✔
972
    _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
318✔
973

974
    // don't loop using pointers as there may be a relocation
975

976
    // find the position where "after" is
977
    id_type after_pos = NONE;
318✔
978
    if(after != NONE)
318✔
979
    {
980
        for(id_type i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))
306✔
981
        {
982
            if(i == after)
306✔
983
            {
984
                after_pos = icount;
150✔
985
                break;
150✔
986
            }
987
        }
988
        _RYML_ASSERT_VISIT_(m_callbacks, after_pos != NONE, this, node);
150✔
989
    }
990

991
    // for each child to be duplicated...
992
    id_type prev = after;
318✔
993
    for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
798✔
994
    {
995
        _c4dbgpf("duplicate_no_rep: {} -> {}/{}", i, parent, prev);
164✔
996
        _RYML_CHECK_VISIT_(m_callbacks, this != src || (parent != i && !is_ancestor(parent, i)), this, parent);
492✔
997
        if(is_seq(parent))
640✔
998
        {
999
            _c4dbgpf("duplicate_no_rep: {} is seq", parent);
12✔
1000
            prev = duplicate(src, i, parent, prev);
36✔
1001
        }
1002
        else
1003
        {
1004
            _c4dbgpf("duplicate_no_rep: {} is map", parent);
148✔
1005
            _RYML_ASSERT_VISIT_(m_callbacks, is_map(parent), this, parent);
592✔
1006
            // does the parent already have a node with key equal to that of the current duplicate?
1007
            id_type dstnode_dup = NONE, dstnode_dup_pos = NONE;
444✔
1008
            {
1009
                csubstr srckey = src->key(i);
444✔
1010
                for(id_type j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j))
1,512✔
1011
                {
1012
                    if(key(j) == srckey)
2,316✔
1013
                    {
1014
                        _c4dbgpf("duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i, parent, j);
30✔
1015
                        dstnode_dup = j;
90✔
1016
                        dstnode_dup_pos = jcount;
90✔
1017
                        break;
90✔
1018
                    }
1019
                }
1020
            }
1021
            _c4dbgpf("duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos);
148✔
1022
            if(dstnode_dup == NONE) // there is no repetition; just duplicate
444✔
1023
            {
1024
                _c4dbgpf("duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i, parent, prev);
118✔
1025
                prev = duplicate(src, i, parent, prev);
354✔
1026
            }
1027
            else  // yes, there is a repetition
1028
            {
1029
                if(after_pos != NONE && dstnode_dup_pos <= after_pos)
90✔
1030
                {
1031
                    // the dst duplicate is located before the node which will be inserted,
1032
                    // and will be overridden by the duplicate. So replace it.
1033
                    _c4dbgpf("duplicate_no_dstnode_dup: replace {}/{} with {}/{}", parent, dstnode_dup, node, i);
20✔
1034
                    if(prev == dstnode_dup)
60✔
1035
                        prev = prev_sibling(dstnode_dup);
24✔
1036
                    remove(dstnode_dup);
60✔
1037
                    prev = duplicate(src, i, parent, prev);
60✔
1038
                }
1039
                else if(prev == NONE)
30✔
1040
                {
1041
                    _c4dbgpf("duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup);
2✔
1042
                    // first iteration with prev = after = NONE and dstnode_dupetition
1043
                    prev = dstnode_dup;
6✔
1044
                }
1045
                else if(dstnode_dup != prev)
24✔
1046
                {
1047
                    // dstnode_dup is located after the node which will be inserted
1048
                    // and overrides it. So move the dstnode_dup into this node's place.
1049
                    _c4dbgpf("duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev);
8✔
1050
                    move(dstnode_dup, prev);
24✔
1051
                    prev = dstnode_dup;
24✔
1052
                }
1053
            } // there's a dstnode_dupetition
1054
        }
1055
    }
1056

1057
    return prev;
306✔
1058
}
1059

1060

1061
//-----------------------------------------------------------------------------
1062

1063
void Tree::merge_with(Tree const *src, id_type src_node, id_type dst_node)
1,104✔
1064
{
1065
    _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, src_node);
1,104✔
1066
    if(src_node == NONE)
1,104✔
1067
        src_node = src->root_id();
360✔
1068
    if(dst_node == NONE)
1,104✔
1069
        dst_node = root_id();
360✔
1070
    _RYML_ASSERT_VISIT_(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node), src, src_node);
1,830✔
1071
    if(src->has_val(src_node))
1,104✔
1072
    {
1073
        type_bits mask_src = ~STYLE; // keep the existing style if it is already a val
684✔
1074
        if( ! has_val(dst_node))
684✔
1075
        {
1076
            if(has_children(dst_node))
18✔
1077
                remove_children(dst_node);
18✔
1078
            mask_src |= VAL_STYLE; // copy the src style
18✔
1079
        }
1080
        if(src->is_keyval(src_node))
684✔
1081
        {
1082
            _copy_props(dst_node, src, src_node, mask_src);
402✔
1083
        }
1084
        else
1085
        {
1086
            _RYML_ASSERT_VISIT_(m_callbacks, src->is_val(src_node), src, src_node);
282✔
1087
            _copy_props_wo_key(dst_node, src, src_node, mask_src);
282✔
1088
        }
1089
    }
1090
    else if(src->is_seq(src_node))
420✔
1091
    {
1092
        if( ! is_seq(dst_node))
114✔
1093
        {
1094
            if(has_children(dst_node))
36✔
1095
                remove_children(dst_node);
×
1096
            _clear_type(dst_node);
36✔
1097
            if(src->has_key(src_node))
36✔
1098
                to_seq(dst_node, src->key(src_node));
12✔
1099
            else
1100
                to_seq(dst_node);
24✔
1101
            _p(dst_node)->m_type = src->_p(src_node)->m_type;
36✔
1102
        }
1103
        for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
396✔
1104
        {
1105
            id_type dch = append_child(dst_node);
282✔
1106
            _copy_props_wo_key(dch, src, sch);
282✔
1107
            merge_with(src, sch, dch);
282✔
1108
        }
1109
    }
1110
    else
1111
    {
1112
        _RYML_ASSERT_VISIT_(m_callbacks, src->is_map(src_node), src, src_node);
306✔
1113
        if( ! is_map(dst_node))
306✔
1114
        {
1115
            if(has_children(dst_node))
114✔
1116
                remove_children(dst_node);
6✔
1117
            _clear_type(dst_node);
114✔
1118
            if(src->has_key(src_node))
114✔
1119
                to_map(dst_node, src->key(src_node));
12✔
1120
            else
1121
                to_map(dst_node);
102✔
1122
            _p(dst_node)->m_type = src->_p(src_node)->m_type;
114✔
1123
        }
1124
        for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
762✔
1125
        {
1126
            id_type dch = find_child(dst_node, src->key(sch));
456✔
1127
            if(dch == NONE)
456✔
1128
            {
1129
                dch = append_child(dst_node);
294✔
1130
                _copy_props(dch, src, sch);
294✔
1131
            }
1132
            merge_with(src, sch, dch);
456✔
1133
        }
1134
    }
1135
}
1,104✔
1136

1137

1138
//-----------------------------------------------------------------------------
1139

1140
void Tree::resolve(bool clear_anchors)
342✔
1141
{
1142
    if(m_size == 0)
342✔
1143
        return;
6✔
1144
    ReferenceResolver rr;
336✔
1145
    resolve(&rr, clear_anchors);
336✔
1146
}
328✔
1147

1148
void Tree::resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors)
336✔
1149
{
1150
    if(m_size == 0)
336✔
1151
        return;
×
1152
    rr->resolve(this, clear_anchors);
336✔
1153
}
1154

1155

1156
//-----------------------------------------------------------------------------
1157

1158
id_type Tree::num_children(id_type node) const
8,687,196✔
1159
{
1160
    id_type count = 0;
8,687,196✔
1161
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
34,525,072✔
1162
        ++count;
25,837,876✔
1163
    return count;
8,687,184✔
1164
}
1165

1166
id_type Tree::child(id_type node, id_type pos) const
2,338,602✔
1167
{
1168
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
2,338,602✔
1169
    id_type count = 0;
2,338,596✔
1170
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
8,576,850✔
1171
    {
1172
        if(count++ == pos)
8,576,100✔
1173
            return i;
2,337,846✔
1174
    }
1175
    return NONE;
744✔
1176
}
1177

1178
id_type Tree::child_pos(id_type node, id_type ch) const
24✔
1179
{
1180
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
24✔
1181
    id_type count = 0;
24✔
1182
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
24✔
1183
    {
1184
        if(i == ch)
24✔
1185
            return count;
24✔
1186
        ++count;
×
1187
    }
1188
    return NONE;
×
1189
}
1190

1191
#if defined(__clang__)
1192
#   pragma clang diagnostic push
1193
#elif defined(__GNUC__)
1194
#   pragma GCC diagnostic push
1195
#   if __GNUC__ >= 6
1196
#       pragma GCC diagnostic ignored "-Wnull-dereference"
1197
#   endif
1198
#   if __GNUC__ > 9
1199
#       pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
1200
#   endif
1201
#endif
1202

1203
id_type Tree::find_child(id_type node, csubstr const& name) const
2,070,243✔
1204
{
1205
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
2,070,243✔
1206
    _RYML_ASSERT_VISIT_(m_callbacks, is_map(node), this, node);
2,070,231✔
1207
    if(get(node)->m_first_child == NONE)
2,070,225✔
1208
    {
1209
        _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child == NONE, this, node);
462✔
1210
        return NONE;
462✔
1211
    }
1212
    else
1213
    {
1214
        _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child != NONE, this, node);
2,069,763✔
1215
    }
1216
    for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
10,482,771✔
1217
    {
1218
        if(_p(i)->m_key.scalar == name)
20,962,818✔
1219
        {
1220
            return i;
2,068,401✔
1221
        }
1222
    }
1223
    return NONE;
1,362✔
1224
}
1225

1226
#if defined(__clang__)
1227
#   pragma clang diagnostic pop
1228
#elif defined(__GNUC__)
1229
#   pragma GCC diagnostic pop
1230
#endif
1231

1232
namespace {
1233
id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0)
2,196✔
1234
{
1235
    maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
2,196✔
1236
    for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
3,666✔
1237
    {
1238
        const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
1,470✔
1239
        maxdepth = d > maxdepth ? d : maxdepth;
1,470✔
1240
    }
1241
    return maxdepth;
2,190✔
1242
}
1243
}
1244

1245
id_type Tree::depth_desc(id_type node) const
732✔
1246
{
1247
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
732✔
1248
    return depth_desc_(*this, node);
726✔
1249
}
1250

1251
id_type Tree::depth_asc(id_type node) const
120✔
1252
{
1253
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
120✔
1254
    id_type depth = 0;
114✔
1255
    while(!is_root(node))
312✔
1256
    {
1257
        ++depth;
198✔
1258
        node = parent(node);
198✔
1259
    }
1260
    return depth;
108✔
1261
}
1262

1263
bool Tree::is_ancestor(id_type node, id_type ancestor) const
1,458✔
1264
{
1265
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1,458✔
1266
    id_type p = parent(node);
1,452✔
1267
    while(p != NONE)
3,390✔
1268
    {
1269
        if(p == ancestor)
2,298✔
1270
            return true;
360✔
1271
        p = parent(p);
1,938✔
1272
    }
1273
    return false;
1,092✔
1274
}
1275

1276

1277
//-----------------------------------------------------------------------------
1278

1279
void Tree::to_val(id_type node, csubstr val, type_bits more_flags)
15,666✔
1280
{
1281
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
15,666✔
1282
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node);
29,424✔
1283
    _set_flags(node, VAL|more_flags);
15,666✔
1284
    _p(node)->m_key.clear();
15,666✔
1285
    _p(node)->m_val = val;
15,666✔
1286
}
15,666✔
1287

1288
void Tree::to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags)
19,482✔
1289
{
1290
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
19,482✔
1291
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
38,964✔
1292
    _set_flags(node, KEYVAL|more_flags);
19,482✔
1293
    _p(node)->m_key = key;
19,482✔
1294
    _p(node)->m_val = val;
19,482✔
1295
}
19,482✔
1296

1297
void Tree::to_map(id_type node, type_bits more_flags)
6,120✔
1298
{
1299
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
6,120✔
1300
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node); // parent must not have children with keys
12,126✔
1301
    _set_flags(node, MAP|more_flags);
6,120✔
1302
    _p(node)->m_key.clear();
6,120✔
1303
    _p(node)->m_val.clear();
6,120✔
1304
}
6,120✔
1305

1306
void Tree::to_map(id_type node, csubstr key, type_bits more_flags)
1,878✔
1307
{
1308
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
1,878✔
1309
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
3,756✔
1310
    _set_flags(node, KEY|MAP|more_flags);
1,878✔
1311
    _p(node)->m_key = key;
1,878✔
1312
    _p(node)->m_val.clear();
1,878✔
1313
}
1,878✔
1314

1315
void Tree::to_seq(id_type node, type_bits more_flags)
2,412✔
1316
{
1317
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
2,412✔
1318
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_seq(node), this, node);
4,800✔
1319
    _set_flags(node, SEQ|more_flags);
2,412✔
1320
    _p(node)->m_key.clear();
2,412✔
1321
    _p(node)->m_val.clear();
2,412✔
1322
}
2,412✔
1323

1324
void Tree::to_seq(id_type node, csubstr key, type_bits more_flags)
1,956✔
1325
{
1326
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
1,956✔
1327
    _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
3,912✔
1328
    _set_flags(node, KEY|SEQ|more_flags);
1,956✔
1329
    _p(node)->m_key = key;
1,956✔
1330
    _p(node)->m_val.clear();
1,956✔
1331
}
1,956✔
1332

1333
void Tree::to_doc(id_type node, type_bits more_flags)
6,774✔
1334
{
1335
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
6,774✔
1336
    _set_flags(node, DOC|more_flags);
6,774✔
1337
    _p(node)->m_key.clear();
6,774✔
1338
    _p(node)->m_val.clear();
6,774✔
1339
}
6,774✔
1340

1341
void Tree::to_stream(id_type node, type_bits more_flags)
6✔
1342
{
1343
    _RYML_ASSERT_VISIT_(m_callbacks,  ! has_children(node), this, node);
6✔
1344
    _set_flags(node, STREAM|more_flags);
6✔
1345
    _p(node)->m_key.clear();
6✔
1346
    _p(node)->m_val.clear();
6✔
1347
}
6✔
1348

1349

1350
//-----------------------------------------------------------------------------
1351

1352
void Tree::clear_style(id_type node, bool recurse)
114✔
1353
{
1354
    NodeData *C4_RESTRICT d = _p(node);
114✔
1355
    d->m_type.clear_style();
114✔
1356
    if(!recurse)
114✔
1357
        return;
12✔
1358
    for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
192✔
1359
        clear_style(child, recurse);
90✔
1360
}
1361

1362
void Tree::set_style_conditionally(id_type node,
330✔
1363
                                   NodeType type_mask,
1364
                                   NodeType rem_style_flags,
1365
                                   NodeType add_style_flags,
1366
                                   bool recurse)
1367
{
1368
    NodeData *C4_RESTRICT d = _p(node);
330✔
1369
    if((d->m_type & type_mask) == type_mask)
1,320✔
1370
    {
1371
        d->m_type &= ~(NodeType)rem_style_flags;
576✔
1372
        d->m_type |= (NodeType)add_style_flags;
576✔
1373
    }
1374
    if(!recurse)
330✔
1375
        return;
12✔
1376
    for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
606✔
1377
        set_style_conditionally(child, type_mask, rem_style_flags, add_style_flags, recurse);
288✔
1378
}
1379

1380

1381
//-----------------------------------------------------------------------------
1382
id_type Tree::num_tag_directives() const
1,432,950✔
1383
{
1384
    // this assumes we have a very small number of tag directives
1385
    for(id_type i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)
1,449,576✔
1386
        if(m_tag_directives[i].handle.empty())
2,899,104✔
1387
            return i;
1,432,926✔
1388
    return RYML_MAX_TAG_DIRECTIVES;
24✔
1389
}
1390

1391
void Tree::clear_tag_directives()
6✔
1392
{
1393
    for(TagDirective &td : m_tag_directives)
30✔
1394
        td = {};
24✔
1395
}
6✔
1396

1397
id_type Tree::add_tag_directive(TagDirective const& td)
4,164✔
1398
{
1399
    _RYML_CHECK_BASIC_(m_callbacks, !td.handle.empty());
8,328✔
1400
    _RYML_CHECK_BASIC_(m_callbacks, !td.prefix.empty());
8,328✔
1401
    _RYML_CHECK_BASIC_(m_callbacks, td.handle.begins_with('!'));
4,158✔
1402
    _RYML_CHECK_BASIC_(m_callbacks, td.handle.ends_with('!'));
4,158✔
1403
    // https://yaml.org/spec/1.2.2/#rule-ns-word-char
1404
    _RYML_CHECK_BASIC_(m_callbacks, td.handle == '!' || td.handle == "!!" || td.handle.trim('!').first_not_of("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-") == npos);
13,698✔
1405
    id_type pos = num_tag_directives();
4,158✔
1406
    _RYML_CHECK_BASIC_(m_callbacks, pos < RYML_MAX_TAG_DIRECTIVES);
4,158✔
1407
    m_tag_directives[pos] = td;
4,146✔
1408
    return pos;
4,146✔
1409
}
1410

1411
namespace {
1412
bool _create_tag_directive_from_str(csubstr directive_, TagDirective *td, Tree *tree)
4,140✔
1413
{
1414
    _RYML_CHECK_BASIC_(tree->callbacks(), directive_.begins_with("%TAG "));
4,140✔
1415
    if(!td->create_from_str(directive_))
4,134✔
1416
    {
1417
        _RYML_ERR_BASIC_(tree->callbacks(), "invalid tag directive");
12✔
1418
    }
1419
    td->next_node_id = tree->size();
4,122✔
1420
    if(!tree->empty())
4,122✔
1421
    {
1422
        const id_type prev = tree->size() - 1;
4,122✔
1423
        if(tree->is_root(prev) && tree->type(prev) != NOTYPE && !tree->is_stream(prev))
7,152✔
1424
            ++td->next_node_id;
114✔
1425
    }
1426
    _c4dbgpf("%TAG: handle={} prefix={} next_node={}", td->handle, td->prefix, td->next_node_id);
1,374✔
1427
    return true;
4,122✔
1428
}
1429
} // namespace
1430

1431
bool Tree::add_tag_directive(csubstr directive_)
4,140✔
1432
{
1433
    TagDirective td;
4,140✔
1434
    if(_create_tag_directive_from_str(directive_, &td, this))
4,140✔
1435
    {
1436
        add_tag_directive(td);
4,122✔
1437
        return true;
4,110✔
1438
    }
1439
    return false;
×
1440
}
1441

1442
size_t Tree::resolve_tag(substr output, csubstr tag, id_type node_id) const
19,518✔
1443
{
1444
    // lookup from the end. We want to find the first directive that
1445
    // matches the tag and has a target node id leq than the given
1446
    // node_id.
1447
    for(id_type i = RYML_MAX_TAG_DIRECTIVES-1; i != (id_type)-1; --i)
89,544✔
1448
    {
1449
        auto const& td = m_tag_directives[i];
77,682✔
1450
        if(td.handle.empty())
155,364✔
1451
            continue;
60,246✔
1452
        if(tag.begins_with(td.handle) && td.next_node_id <= node_id)
17,436✔
1453
            return td.transform(tag, output, m_callbacks);
7,656✔
1454
    }
1455
    if(tag.begins_with('!'))
11,862✔
1456
    {
1457
        if(is_custom_tag(tag))
7,866✔
1458
        {
1459
            _RYML_ERR_VISIT_(m_callbacks, this, node_id, "tag directive not found");
12✔
1460
        }
1461
    }
1462
    return 0; // return 0 to signal that the tag is local and cannot be resolved
11,850✔
1463
}
1464

1465
namespace {
1466
csubstr _transform_tag(Tree *t, csubstr tag, id_type node)
6,654✔
1467
{
1468
    _c4dbgpf("[{}] resolving tag ~~~{}~~~", node, tag);
2,218✔
1469
    size_t required_size = t->resolve_tag(substr{}, tag, node);
6,654✔
1470
    if(!required_size)
6,654✔
1471
    {
1472
        if(tag.begins_with("!<"))
5,358✔
1473
            tag = tag.sub(1);
4,074✔
1474
        _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, tag);
1,786✔
1475
        return tag;
5,358✔
1476
    }
1477
    const char *prev_arena = t->arena().str;(void)prev_arena;
1,296✔
1478
    substr buf = t->alloc_arena(required_size);
1,296✔
1479
    _RYML_ASSERT_VISIT_(t->m_callbacks, t->arena().str == prev_arena, t, node);
1,296✔
1480
    size_t actual_size = t->resolve_tag(buf, tag, node);
1,296✔
1481
    _RYML_ASSERT_VISIT_(t->m_callbacks, actual_size <= required_size, t, node);
1,296✔
1482
    _c4dbgpf("[{}] resolved tag: ~~~{}~~~", node, buf.first(actual_size));
432✔
1483
    return buf.first(actual_size);
2,592✔
1484
}
1485
void _resolve_tags(Tree *t, id_type node)
15,150✔
1486
{
1487
    NodeData *C4_RESTRICT d = t->_p(node);
15,150✔
1488
    if(d->m_type & KEYTAG)
45,450✔
1489
        d->m_key.tag = _transform_tag(t, d->m_key.tag, node);
12✔
1490
    if(d->m_type & VALTAG)
45,450✔
1491
        d->m_val.tag = _transform_tag(t, d->m_val.tag, node);
6,642✔
1492
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
26,790✔
1493
        _resolve_tags(t, child);
11,640✔
1494
}
15,150✔
1495
size_t _count_resolved_tags_size(Tree const* t, id_type node)
15,282✔
1496
{
1497
    size_t sz = 0;
15,282✔
1498
    NodeData const* C4_RESTRICT d = t->_p(node);
15,282✔
1499
    if(d->m_type & KEYTAG)
45,846✔
1500
        sz += t->resolve_tag(substr{}, d->m_key.tag, node);
12✔
1501
    if(d->m_type & VALTAG)
45,846✔
1502
        sz += t->resolve_tag(substr{}, d->m_val.tag, node);
6,696✔
1503
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
26,880✔
1504
        sz += _count_resolved_tags_size(t, child);
11,724✔
1505
    return sz;
15,156✔
1506
}
1507
void _normalize_tags(Tree *t, id_type node)
126✔
1508
{
1509
    NodeData *C4_RESTRICT d = t->_p(node);
126✔
1510
    if(d->m_type & KEYTAG)
378✔
1511
        d->m_key.tag = normalize_tag(d->m_key.tag);
6✔
1512
    if(d->m_type & VALTAG)
378✔
1513
        d->m_val.tag = normalize_tag(d->m_val.tag);
60✔
1514
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
246✔
1515
        _normalize_tags(t, child);
120✔
1516
}
126✔
1517
void _normalize_tags_long(Tree *t, id_type node)
1,167,822✔
1518
{
1519
    NodeData *C4_RESTRICT d = t->_p(node);
1,167,822✔
1520
    if(d->m_type & KEYTAG)
3,503,466✔
1521
        d->m_key.tag = normalize_tag_long(d->m_key.tag);
8,454✔
1522
    if(d->m_type & VALTAG)
3,503,466✔
1523
        d->m_val.tag = normalize_tag_long(d->m_val.tag);
54,684✔
1524
    for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
2,023,206✔
1525
        _normalize_tags_long(t, child);
855,384✔
1526
}
1,167,822✔
1527
} // namespace
1528

1529
void Tree::resolve_tags()
3,564✔
1530
{
1531
    if(empty())
3,564✔
1532
        return;
6✔
1533
    size_t needed_size = _count_resolved_tags_size(this, root_id());
3,558✔
1534
    if(needed_size)
3,510✔
1535
        reserve_arena(arena_size() + needed_size);
888✔
1536
    _resolve_tags(this, root_id());
3,510✔
1537
}
1538

1539
void Tree::normalize_tags()
6✔
1540
{
1541
    if(empty())
6✔
1542
        return;
×
1543
    _normalize_tags(this, root_id());
6✔
1544
}
1545

1546
void Tree::normalize_tags_long()
312,438✔
1547
{
1548
    if(empty())
312,438✔
1549
        return;
×
1550
    _normalize_tags_long(this, root_id());
312,438✔
1551
}
1552

1553

1554
//-----------------------------------------------------------------------------
1555

1556
csubstr Tree::lookup_result::resolved() const
30✔
1557
{
1558
    csubstr p = path.first(path_pos);
30✔
1559
    if(p.ends_with('.'))
30✔
1560
        p = p.first(p.len-1);
36✔
1561
    return p;
30✔
1562
}
1563

1564
csubstr Tree::lookup_result::unresolved() const
3,984✔
1565
{
1566
    return path.sub(path_pos);
7,968✔
1567
}
1568

1569
void Tree::_advance(lookup_result *r, size_t more)
1,554✔
1570
{
1571
    r->path_pos += more;
1,554✔
1572
    if(r->path.sub(r->path_pos).begins_with('.'))
3,108✔
1573
        ++r->path_pos;
240✔
1574
}
1,554✔
1575

1576
Tree::lookup_result Tree::lookup_path(csubstr path, id_type start) const
258✔
1577
{
1578
    if(start == NONE)
258✔
1579
        start = root_id();
180✔
1580
    lookup_result r(path, start);
258✔
1581
    if(path.empty())
258✔
1582
        return r;
×
1583
    _lookup_path(&r);
258✔
1584
    if(r.target == NONE && r.closest == start)
258✔
1585
        r.closest = NONE;
18✔
1586
    return r;
258✔
1587
}
1588

1589
id_type Tree::lookup_path_or_modify(csubstr default_value, csubstr path, id_type start)
132✔
1590
{
1591
    id_type target = _lookup_path_or_create(path, start);
132✔
1592
    if(parent_is_map(target))
132✔
1593
        to_keyval(target, key(target), default_value);
84✔
1594
    else
1595
        to_val(target, default_value);
48✔
1596
    return target;
132✔
1597
}
1598

1599
id_type Tree::lookup_path_or_modify(Tree const *src, id_type src_node, csubstr path, id_type start)
6✔
1600
{
1601
    id_type target = _lookup_path_or_create(path, start);
6✔
1602
    merge_with(src, src_node, target);
6✔
1603
    return target;
6✔
1604
}
1605

1606
id_type Tree::_lookup_path_or_create(csubstr path, id_type start)
138✔
1607
{
1608
    if(start == NONE)
138✔
1609
        start = root_id();
138✔
1610
    lookup_result r(path, start);
138✔
1611
    _lookup_path(&r);
138✔
1612
    if(r.target != NONE)
138✔
1613
    {
1614
        C4_ASSERT(r.unresolved().empty());
144✔
1615
        return r.target;
72✔
1616
    }
1617
    _lookup_path_modify(&r);
66✔
1618
    return r.target;
66✔
1619
}
1620

1621
void Tree::_lookup_path(lookup_result *r) const
396✔
1622
{
1623
    C4_ASSERT( ! r->unresolved().empty());
792✔
1624
    _lookup_path_token parent{"", type(r->closest)};
396✔
1625
    id_type node;
1626
    do
1627
    {
1628
        node = _next_node(r, &parent);
1,386✔
1629
        if(node != NONE)
1,386✔
1630
            r->closest = node;
1,272✔
1631
        if(r->unresolved().empty())
2,772✔
1632
        {
1633
            r->target = node;
282✔
1634
            return;
282✔
1635
        }
1636
    } while(node != NONE);
1,104✔
1637
}
1638

1639
void Tree::_lookup_path_modify(lookup_result *r)
66✔
1640
{
1641
    C4_ASSERT( ! r->unresolved().empty());
132✔
1642
    _lookup_path_token parent{"", type(r->closest)};
66✔
1643
    id_type node;
1644
    do
1645
    {
1646
        node = _next_node_modify(r, &parent);
168✔
1647
        if(node != NONE)
168✔
1648
            r->closest = node;
168✔
1649
        if(r->unresolved().empty())
336✔
1650
        {
1651
            r->target = node;
66✔
1652
            return;
66✔
1653
        }
1654
    } while(node != NONE);
102✔
1655
}
1656

1657
id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const
1,386✔
1658
{
1659
    _lookup_path_token token = _next_token(r, *parent);
1,386✔
1660
    if( ! token)
1,386✔
1661
        return NONE;
×
1662

1663
    id_type node = NONE;
1,386✔
1664
    csubstr prev = token.value;
1,386✔
1665
    if(token.type == MAP || token.type == SEQ)
2,340✔
1666
    {
1667
        _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
756✔
1668
        //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1669
        _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1,512✔
1670
        node = find_child(r->closest, token.value);
756✔
1671
    }
1672
    else if(token.type == KEYVAL)
630✔
1673
    {
1674
        _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
528✔
1675
        if(is_map(r->closest))
528✔
1676
            node = find_child(r->closest, token.value);
258✔
1677
    }
1678
    else if(token.type == KEY)
366✔
1679
    {
1680
        _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
366✔
1681
        token.value = token.value.offs(1, 1).trim(' ');
366✔
1682
        id_type idx = 0;
366✔
1683
        _RYML_CHECK_BASIC_(m_callbacks, from_chars(token.value, &idx));
366✔
1684
        node = child(r->closest, idx);
366✔
1685
    }
1686
    else
1687
    {
1688
        C4_NEVER_REACH();
×
1689
    }
1690

1691
    if(node != NONE)
1,386✔
1692
    {
1693
        *parent = token;
1,272✔
1694
    }
1695
    else
1696
    {
1697
        csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
114✔
1698
        r->path_pos -= prev.len;
114✔
1699
        if(p.begins_with('.'))
114✔
1700
            r->path_pos -= 1u;
24✔
1701
    }
1702

1703
    return node;
1,386✔
1704
}
1705

1706
id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
168✔
1707
{
1708
    _lookup_path_token token = _next_token(r, *parent);
168✔
1709
    if( ! token)
168✔
1710
        return NONE;
×
1711

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

1809
    _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, r->closest);
168✔
1810
    *parent = token;
168✔
1811
    return node;
168✔
1812
}
1813

1814
/* types of tokens:
1815
 * - seeing "map."  ---> "map"/MAP
1816
 * - finishing "scalar" ---> "scalar"/KEYVAL
1817
 * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)
1818
 * - seeing "[n]" ---> "[n]"/KEY
1819
 */
1820
Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const
1,554✔
1821
{
1822
    csubstr unres = r->unresolved();
1,554✔
1823
    if(unres.empty())
1,554✔
1824
        return {};
×
1825

1826
    // is it an indexation like [0], [1], etc?
1827
    if(unres.begins_with('['))
1,554✔
1828
    {
1829
        size_t pos = unres.find(']');
420✔
1830
        if(pos == csubstr::npos)
420✔
1831
            return {};
×
1832
        csubstr idx = unres.first(pos + 1);
420✔
1833
        _advance(r, pos + 1);
420✔
1834
        return {idx, KEY};
420✔
1835
    }
1836

1837
    // no. so it must be a name
1838
    size_t pos = unres.first_of(".[");
1,134✔
1839
    if(pos == csubstr::npos)
1,134✔
1840
    {
1841
        _advance(r, unres.len);
312✔
1842
        NodeType t;
1843
        if(( ! parent) || parent.type.is_seq())
624✔
1844
            return {unres, VAL};
×
1845
        return {unres, KEYVAL};
312✔
1846
    }
1847

1848
    // it's either a map or a seq
1849
    _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '.' || unres[pos] == '[', this, r->closest);
1,176✔
1850
    if(unres[pos] == '.')
822✔
1851
    {
1852
        _RYML_ASSERT_VISIT_(m_callbacks, pos != 0, this, r->closest);
468✔
1853
        _advance(r, pos + 1);
468✔
1854
        return {unres.first(pos), MAP};
468✔
1855
    }
1856

1857
    _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '[', this, r->closest);
354✔
1858
    _advance(r, pos);
354✔
1859
    return {unres.first(pos), SEQ};
354✔
1860
}
1861

1862

1863
} // namespace yml
1864
} // namespace c4
1865

1866

1867
//-----------------------------------------------------------------------------
1868
//-----------------------------------------------------------------------------
1869
//-----------------------------------------------------------------------------
1870

1871
#include "c4/yml/event_handler_tree.hpp"
1872
#include "c4/yml/parse_engine.def.hpp"
1873
#include "c4/yml/parse.hpp"
1874

1875
namespace c4 {
1876
namespace yml {
1877

1878
Location Tree::location(Parser const& parser, id_type node) const
2,166✔
1879
{
1880
    // try hard to avoid getting the location from a null string.
1881
    Location loc;
2,166✔
1882
    if(_location_from_node(parser, node, &loc, 0))
2,166✔
1883
        return loc;
2,148✔
1884
    return parser.val_location(parser.source().str);
12✔
1885
}
1886

1887
bool Tree::_location_from_node(Parser const& parser, id_type node, Location *C4_RESTRICT loc, id_type level) const
2,298✔
1888
{
1889
    if(has_key(node))
2,298✔
1890
    {
1891
        csubstr k = key(node);
1,068✔
1892
        if(C4_LIKELY(k.str != nullptr))
1,068✔
1893
        {
1894
            _RYML_ASSERT_BASIC_(m_callbacks, k.is_sub(parser.source()));
2,028✔
1895
            _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(k));
2,028✔
1896
            *loc = parser.val_location(k.str);
1,014✔
1897
            return true;
1,008✔
1898
        }
1899
    }
1900

1901
    if(has_val(node))
1,284✔
1902
    {
1903
        csubstr v = val(node);
744✔
1904
        if(C4_LIKELY(v.str != nullptr))
744✔
1905
        {
1906
            _RYML_ASSERT_BASIC_(m_callbacks, v.is_sub(parser.source()));
1,224✔
1907
            _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(v));
1,224✔
1908
            *loc = parser.val_location(v.str);
612✔
1909
            return true;
612✔
1910
        }
1911
    }
1912

1913
    if(is_container(node))
672✔
1914
    {
1915
        if(_location_from_cont(parser, node, loc))
528✔
1916
            return true;
528✔
1917
    }
1918

1919
    if(type(node) != NOTYPE && level == 0)
288✔
1920
    {
1921
        // try the prev sibling
1922
        {
1923
            const id_type prev = prev_sibling(node);
66✔
1924
            if(prev != NONE)
66✔
1925
            {
1926
                if(_location_from_node(parser, prev, loc, level+1))
48✔
1927
                    return true;
12✔
1928
            }
1929
        }
1930
        // try the next sibling
1931
        {
1932
            const id_type next = next_sibling(node);
54✔
1933
            if(next != NONE)
54✔
1934
            {
1935
                if(_location_from_node(parser, next, loc, level+1))
42✔
1936
                    return true;
12✔
1937
            }
1938
        }
1939
        // try the parent
1940
        {
1941
            const id_type parent = this->parent(node);
42✔
1942
            if(parent != NONE)
42✔
1943
            {
1944
                if(_location_from_node(parser, parent, loc, level+1))
42✔
1945
                    return true;
42✔
1946
            }
1947
        }
1948
    }
1949
    return false;
78✔
1950
}
1951

1952
bool Tree::_location_from_cont(Parser const& parser, id_type node, Location *C4_RESTRICT loc) const
528✔
1953
{
1954
    _RYML_ASSERT_BASIC_(m_callbacks, is_container(node));
528✔
1955
    if(!is_stream(node))
528✔
1956
    {
1957
        const char *node_start = _p(node)->m_val.scalar.str;  // this was stored in the container
492✔
1958
        if(has_children(node))
492✔
1959
        {
1960
            id_type child = first_child(node);
420✔
1961
            if(has_key(child))
420✔
1962
            {
1963
                // when a map starts, the container was set after the key
1964
                csubstr k = key(child);
126✔
1965
                if(k.str && node_start > k.str)
126✔
1966
                    node_start = k.str;
96✔
1967
            }
1968
        }
1969
        *loc = parser.val_location(node_start);
492✔
1970
        return true;
492✔
1971
    }
1972
    else // it's a stream
1973
    {
1974
        *loc = parser.val_location(parser.source().str); // just return the front of the buffer
36✔
1975
    }
1976
    return true;
36✔
1977
}
1978

1979
} // namespace yml
1980
} // namespace c4
1981

1982

1983
C4_SUPPRESS_WARNING_GCC_CLANG_POP
1984
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