rapidyaml 0.14.0
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
tree.cpp
Go to the documentation of this file.
1#include "c4/yml/tree.hpp"
2#include "c4/yml/detail/dbgprint.hpp"
3#include "c4/yml/node.hpp"
5
6
7C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296/*expression is always 'boolean_value'*/)
8C4_SUPPRESS_WARNING_MSVC(4702/*unreachable code*/)
9C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
10C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
11C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
12// NOLINTBEGIN(modernize-avoid-c-style-cast)
13
14
15namespace c4 {
16namespace yml {
17
18
19csubstr serialize_to_arena(Tree * C4_RESTRICT tree, csubstr a)
20{
21 if(a.len > 0)
22 {
23 substr rem(tree->m_arena.sub(tree->m_arena_pos));
24 size_t num = to_chars(rem, a);
25 if(num > rem.len)
26 {
27 rem = tree->_grow_arena(num);
28 num = to_chars(rem, a);
29 _RYML_ASSERT_VISIT_(tree->m_callbacks, num <= rem.len, tree, NONE);
30 }
31 return tree->_request_span(num);
32 }
33 else
34 {
35 if(a.str == nullptr)
36 {
37 return csubstr{};
38 }
39 else if(tree->m_arena.str == nullptr)
40 {
41 // Arena is empty and we want to store a non-null
42 // zero-length string.
43 // Even though the string has zero length, we need
44 // some "memory" to store a non-nullptr string
45 tree->_grow_arena(1);
46 }
47 return tree->_request_span(0);
48 }
49}
50
51
52//-----------------------------------------------------------------------------
53//-----------------------------------------------------------------------------
54//-----------------------------------------------------------------------------
55
57{
58 return NodeRef(this, root_id());
59}
61{
62 return ConstNodeRef(this, root_id());
63}
64
66{
67 return ConstNodeRef(this, root_id());
68}
69
71{
72 _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
73 return NodeRef(this, id);
74}
76{
77 _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
78 return ConstNodeRef(this, id);
79}
81{
82 _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
83 return ConstNodeRef(this, id);
84}
85
86NodeRef Tree::operator[] (csubstr key)
87{
88 return rootref()[key];
89}
90ConstNodeRef Tree::operator[] (csubstr key) const
91{
92 return rootref()[key];
93}
94
95NodeRef Tree::operator[] (id_type i)
96{
97 return rootref()[i];
98}
99ConstNodeRef Tree::operator[] (id_type i) const
100{
101 return rootref()[i];
102}
103
105{
106 return ref(doc(i));
107}
109{
110 return cref(doc(i));
111}
113{
114 return cref(doc(i));
115}
116
117
118//-----------------------------------------------------------------------------
123
124Tree::Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb)
125 : m_buf(nullptr)
126 , m_cap(0)
127 , m_size(0)
130 , m_arena()
131 , m_arena_pos(0)
132 , m_callbacks(cb)
134{
135 if(node_capacity)
136 reserve(node_capacity);
139}
140
142{
143 _free();
144}
145
146
148{
149 _clear();
150 _copy(that);
151}
152
153Tree::Tree(Tree && that) noexcept : m_callbacks(that.m_callbacks)
154{
155 _clear();
156 _move(that);
157}
158
160{
161 if(&that != this)
162 {
163 _free();
165 _copy(that);
166 }
167 return *this;
168}
169
170Tree& Tree::operator= (Tree && that) noexcept
171{
172 if(&that != this)
173 {
174 _free();
175 m_callbacks = that.m_callbacks;
176 _move(that);
177 }
178 return *this;
179}
180
181void Tree::_free()
182{
183 if(m_buf)
184 {
185 _RYML_ASSERT_VISIT_(m_callbacks, m_cap > 0, this, NONE);
186 _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
187 }
188 if(m_arena.str)
189 {
190 _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len > 0, this, NONE);
191 _RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);
192 }
193 _clear();
194}
195
196
197C4_SUPPRESS_WARNING_GCC_PUSH
198#if defined(__GNUC__) && __GNUC__>= 8
199 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
200#endif
201
202void Tree::_clear()
203{
204 m_buf = nullptr;
205 m_cap = 0;
206 m_size = 0;
207 m_free_head = 0;
208 m_free_tail = 0;
209 m_arena = {};
210 m_arena_pos = 0;
211 m_tag_directives.clear();
212}
213
214void Tree::_copy(Tree const& that)
215{
216 _RYML_ASSERT_VISIT_(m_callbacks, m_buf == nullptr, this, NONE);
217 _RYML_ASSERT_VISIT_(m_callbacks, m_arena.str == nullptr, this, NONE);
218 _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len == 0, this, NONE);
219 if(that.m_cap)
220 {
221 m_buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)that.m_cap, that.m_buf);
222 memcpy(m_buf, that.m_buf, (size_t)that.m_cap * sizeof(NodeData));
223 }
224 m_cap = that.m_cap;
225 m_size = that.m_size;
226 m_free_head = that.m_free_head;
227 m_free_tail = that.m_free_tail;
228 m_arena_pos = that.m_arena_pos;
229 m_arena = that.m_arena;
230 m_tag_directives = that.m_tag_directives;
231 if(that.m_arena.str)
232 {
233 _RYML_ASSERT_VISIT_(m_callbacks, that.m_arena.len > 0, this, NONE);
235 arena.str = _RYML_CB_ALLOC_HINT(m_callbacks, char, that.m_arena.len, that.m_arena.str);
236 arena.len = that.m_arena.len;
237 _relocate(arena); // does a memcpy of the arena and updates nodes using the old arena
238 m_arena = arena;
239 }
240}
241
242void Tree::_move(Tree & that) noexcept
243{
244 _RYML_ASSERT_VISIT_(m_callbacks, m_buf == nullptr, this, NONE);
245 _RYML_ASSERT_VISIT_(m_callbacks, m_arena.str == nullptr, this, NONE);
246 _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len == 0, this, NONE);
247 m_buf = that.m_buf;
248 m_cap = that.m_cap;
249 m_size = that.m_size;
250 m_free_head = that.m_free_head;
251 m_free_tail = that.m_free_tail;
252 m_arena = that.m_arena;
253 m_arena_pos = that.m_arena_pos;
254 m_tag_directives = that.m_tag_directives;
255 that._clear();
256}
257
258void Tree::_relocate(substr next_arena)
259{
260 _RYML_ASSERT_VISIT_(m_callbacks, next_arena.not_empty(), this, NONE);
261 _RYML_ASSERT_VISIT_(m_callbacks, next_arena.len >= m_arena.len, this, NONE);
262 if(m_arena_pos)
263 {
264 memcpy(next_arena.str, m_arena.str, m_arena_pos);
265 }
266 for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n)
267 {
268 if(in_arena(n->m_key.scalar))
269 n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
270 if(in_arena(n->m_key.tag))
271 n->m_key.tag = _relocated(n->m_key.tag, next_arena);
272 if(in_arena(n->m_key.anchor))
273 n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
274 if(in_arena(n->m_val.scalar))
275 n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
276 if(in_arena(n->m_val.tag))
277 n->m_val.tag = _relocated(n->m_val.tag, next_arena);
278 if(in_arena(n->m_val.anchor))
279 n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
280 }
281 for(TagDirective &C4_RESTRICT td : m_tag_directives)
282 {
283 if(in_arena(td.prefix))
284 td.prefix = _relocated(td.prefix, next_arena);
285 if(in_arena(td.handle))
286 td.handle = _relocated(td.handle, next_arena);
287 }
288}
289
290
291//-----------------------------------------------------------------------------
293{
294 if(cap > m_cap)
295 {
296 NodeData *buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)cap, m_buf);
297 if(m_buf)
298 {
299 memcpy(buf, m_buf, (size_t)m_cap * sizeof(NodeData));
300 _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
301 }
302 id_type first = m_cap, del = cap - m_cap;
303 m_cap = cap;
304 m_buf = buf;
305 _clear_range(first, del);
306 if(m_free_head != NONE)
307 {
308 _RYML_ASSERT_VISIT_(m_callbacks, m_buf != nullptr, this, NONE);
309 _RYML_ASSERT_VISIT_(m_callbacks, m_free_tail != NONE, this, NONE);
310 m_buf[m_free_tail].m_next_sibling = first;
311 m_buf[first].m_prev_sibling = m_free_tail;
312 m_free_tail = cap-1;
313 }
314 else
315 {
316 _RYML_ASSERT_VISIT_(m_callbacks, m_free_tail == NONE, this, NONE);
317 m_free_head = first;
318 m_free_tail = cap-1;
319 }
320 _RYML_ASSERT_VISIT_(m_callbacks, m_free_head == NONE || (m_free_head >= 0 && m_free_head < cap), this, NONE);
321 _RYML_ASSERT_VISIT_(m_callbacks, m_free_tail == NONE || (m_free_tail >= 0 && m_free_tail < cap), this, NONE);
322
323 if( ! m_size)
324 _claim_root();
325 }
326}
327
328
329//-----------------------------------------------------------------------------
331{
332 _clear_range(0, m_cap);
333 m_size = 0;
334 if(m_buf)
335 {
336 _RYML_ASSERT_VISIT_(m_callbacks, m_cap >= 0, this, NONE);
337 m_free_head = 0;
338 m_free_tail = m_cap-1;
339 _claim_root();
340 }
341 else
342 {
345 }
346 m_tag_directives.clear();
347}
348
349void Tree::_claim_root()
350{
351 id_type r = _claim();
352 _RYML_ASSERT_VISIT_(m_callbacks, r == 0, this, r);
353 _set_hierarchy(r, NONE, NONE);
354}
355
356
357//-----------------------------------------------------------------------------
358void Tree::_clear_range(id_type first, id_type num)
359{
360 if(num == 0)
361 return; // prevent overflow when subtracting
362 _RYML_ASSERT_VISIT_(m_callbacks, first >= 0 && first + num <= m_cap, this, first);
363 memset(m_buf + first, 0, (size_t)num * sizeof(NodeData)); // TODO we should not need this
364 for(id_type i = first, e = first + num; i < e; ++i)
365 {
366 _clear(i);
367 NodeData *n = m_buf + i;
368 n->m_prev_sibling = i - 1;
369 n->m_next_sibling = i + 1;
370 }
371 m_buf[first + num - 1].m_next_sibling = NONE;
372}
373
374C4_SUPPRESS_WARNING_GCC_POP
375
376
377//-----------------------------------------------------------------------------
378void Tree::_release(id_type i)
379{
380 _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
381
382 _rem_hierarchy(i);
383 _free_list_add(i);
384 _clear(i);
385
386 --m_size;
387}
388
389//-----------------------------------------------------------------------------
390// add to the front of the free list
391void Tree::_free_list_add(id_type i)
392{
393 _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
394 NodeData &C4_RESTRICT w = m_buf[i];
395
396 w.m_parent = NONE;
397 w.m_next_sibling = m_free_head;
398 w.m_prev_sibling = NONE;
399 if(m_free_head != NONE)
400 m_buf[m_free_head].m_prev_sibling = i;
401 m_free_head = i;
402 if(m_free_tail == NONE)
404}
405
406void Tree::_free_list_rem(id_type i)
407{
408 if(m_free_head == i)
410 _rem_hierarchy(i);
411}
412
413//-----------------------------------------------------------------------------
415{
416 if(m_free_head == NONE || m_buf == nullptr)
417 {
418 id_type sz = 2 * m_cap;
419 sz = sz ? sz : 16;
420 reserve(sz);
421 _RYML_ASSERT_VISIT_(m_callbacks, m_free_head != NONE, this, NONE);
422 }
423
424 _RYML_ASSERT_VISIT_(m_callbacks, m_size < m_cap, this, NONE);
425 _RYML_ASSERT_VISIT_(m_callbacks, m_free_head >= 0 && m_free_head < m_cap, this, NONE);
426
427 id_type ichild = m_free_head;
428 NodeData *child = m_buf + ichild;
429
430 ++m_size;
431 m_free_head = child->m_next_sibling;
432 if(m_free_head == NONE)
433 {
435 _RYML_ASSERT_VISIT_(m_callbacks, m_size == m_cap, this, NONE);
436 }
437
438 _clear(ichild);
439
440 return ichild;
441}
442
443//-----------------------------------------------------------------------------
444
445C4_SUPPRESS_WARNING_GCC_PUSH
446C4_SUPPRESS_WARNING_CLANG_PUSH
447C4_SUPPRESS_WARNING_CLANG("-Wnull-dereference")
448#if defined(__GNUC__)
449#if (__GNUC__ >= 6)
450C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
451#endif
452#if (__GNUC__ > 9)
453C4_SUPPRESS_WARNING_GCC("-Wanalyzer-fd-leak")
454#endif
455#endif
456
457void Tree::_set_hierarchy(id_type ichild, id_type iparent, id_type iprev_sibling)
458{
459 _RYML_ASSERT_VISIT_(m_callbacks, ichild >= 0 && ichild < m_cap, this, ichild);
460 _RYML_ASSERT_VISIT_(m_callbacks, iparent == NONE || (iparent >= 0 && iparent < m_cap), this, iparent);
461 _RYML_ASSERT_VISIT_(m_callbacks, iprev_sibling == NONE || (iprev_sibling >= 0 && iprev_sibling < m_cap), this, iprev_sibling);
462
463 NodeData *C4_RESTRICT child = _p(ichild);
464
465 child->m_parent = iparent;
466 child->m_prev_sibling = NONE;
467 child->m_next_sibling = NONE;
468
469 if(iparent == NONE)
470 {
471 _RYML_ASSERT_VISIT_(m_callbacks, ichild == 0, this, ichild);
472 _RYML_ASSERT_VISIT_(m_callbacks, iprev_sibling == NONE, this, iprev_sibling);
473 }
474
475 if(iparent == NONE)
476 return;
477
478 id_type inext_sibling = iprev_sibling != NONE ? next_sibling(iprev_sibling) : first_child(iparent);
479 NodeData *C4_RESTRICT parent = get(iparent);
480 NodeData *C4_RESTRICT psib = get(iprev_sibling);
481 NodeData *C4_RESTRICT nsib = get(inext_sibling);
482
483 if(psib)
484 {
485 _RYML_ASSERT_VISIT_(m_callbacks, next_sibling(iprev_sibling) == id(nsib), this, iprev_sibling);
486 child->m_prev_sibling = id(psib);
487 psib->m_next_sibling = id(child);
488 _RYML_ASSERT_VISIT_(m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling == NONE, this, iprev_sibling);
489 }
490
491 if(nsib)
492 {
493 _RYML_ASSERT_VISIT_(m_callbacks, prev_sibling(inext_sibling) == id(psib), this, inext_sibling);
494 child->m_next_sibling = id(nsib);
495 nsib->m_prev_sibling = id(child);
496 _RYML_ASSERT_VISIT_(m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling == NONE, this, inext_sibling);
497 }
498
499 if(parent->m_first_child == NONE)
500 {
501 _RYML_ASSERT_VISIT_(m_callbacks, parent->m_last_child == NONE, this, parent->m_last_child);
502 parent->m_first_child = id(child);
503 parent->m_last_child = id(child);
504 }
505 else
506 {
507 if(child->m_next_sibling == parent->m_first_child)
508 parent->m_first_child = id(child);
509
510 if(child->m_prev_sibling == parent->m_last_child)
511 parent->m_last_child = id(child);
512 }
513}
514
515C4_SUPPRESS_WARNING_GCC_POP
516C4_SUPPRESS_WARNING_CLANG_POP
517
518
519//-----------------------------------------------------------------------------
520void Tree::_rem_hierarchy(id_type i)
521{
522 _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
523
524 NodeData &C4_RESTRICT w = m_buf[i];
525
526 // remove from the parent
527 if(w.m_parent != NONE)
528 {
529 NodeData &C4_RESTRICT p = m_buf[w.m_parent];
530 if(p.m_first_child == i)
531 {
532 p.m_first_child = w.m_next_sibling;
533 }
534 if(p.m_last_child == i)
535 {
536 p.m_last_child = w.m_prev_sibling;
537 }
538 }
539
540 // remove from the used list
541 if(w.m_prev_sibling != NONE)
542 {
543 NodeData *C4_RESTRICT prev = get(w.m_prev_sibling);
544 prev->m_next_sibling = w.m_next_sibling;
545 }
546 if(w.m_next_sibling != NONE)
547 {
548 NodeData *C4_RESTRICT next = get(w.m_next_sibling);
549 next->m_prev_sibling = w.m_prev_sibling;
550 }
551}
552
553//-----------------------------------------------------------------------------
554/** @cond dev */
555id_type Tree::_do_reorder(id_type *node, id_type count)
556{
557 // swap this node if it's not in place
558 if(*node != count)
559 {
560 _swap(*node, count);
561 *node = count;
562 }
563 ++count; // bump the count from this node
564
565 // now descend in the hierarchy
566 for(id_type i = first_child(*node); i != NONE; i = next_sibling(i))
567 {
568 // this child may have been relocated to a different index,
569 // so get an updated version
570 count = _do_reorder(&i, count);
571 }
572 return count;
573}
574/** @endcond */
575
577{
578 id_type r = root_id();
579 _do_reorder(&r, 0);
580}
581
582
583//-----------------------------------------------------------------------------
584/** @cond dev */
585void Tree::_swap(id_type n_, id_type m_)
586{
587 _RYML_ASSERT_VISIT_(m_callbacks, (parent(n_) != NONE) || type(n_) == NOTYPE, this, n_);
588 _RYML_ASSERT_VISIT_(m_callbacks, (parent(m_) != NONE) || type(m_) == NOTYPE, this, m_);
589 NodeType tn = type(n_);
590 NodeType tm = type(m_);
591 if(tn != NOTYPE && tm != NOTYPE)
592 {
593 _swap_props(n_, m_);
594 _swap_hierarchy(n_, m_);
595 }
596 else if(tn == NOTYPE && tm != NOTYPE)
597 {
598 _copy_props(n_, m_);
599 _free_list_rem(n_);
600 _copy_hierarchy(n_, m_);
601 _clear(m_);
602 _free_list_add(m_);
603 }
604 else if(tn != NOTYPE && tm == NOTYPE)
605 {
606 _copy_props(m_, n_);
607 _free_list_rem(m_);
608 _copy_hierarchy(m_, n_);
609 _clear(n_);
610 _free_list_add(n_);
611 }
612 else
613 {
614 C4_NEVER_REACH();
615 }
616}
617
618//-----------------------------------------------------------------------------
619void Tree::_swap_hierarchy(id_type ia, id_type ib)
620{
621 if(ia == ib) return;
622
623 for(id_type i = first_child(ia); i != NONE; i = next_sibling(i))
624 {
625 if(i == ib || i == ia)
626 continue;
627 _p(i)->m_parent = ib;
628 }
629
630 for(id_type i = first_child(ib); i != NONE; i = next_sibling(i))
631 {
632 if(i == ib || i == ia)
633 continue;
634 _p(i)->m_parent = ia;
635 }
636
637 auto & C4_RESTRICT a = *_p(ia);
638 auto & C4_RESTRICT b = *_p(ib);
639 auto & C4_RESTRICT pa = *_p(a.m_parent);
640 auto & C4_RESTRICT pb = *_p(b.m_parent);
641
642 if(&pa == &pb)
643 {
644 if((pa.m_first_child == ib && pa.m_last_child == ia)
645 ||
646 (pa.m_first_child == ia && pa.m_last_child == ib))
647 {
648 std::swap(pa.m_first_child, pa.m_last_child);
649 }
650 else
651 {
652 bool changed = false;
653 if(pa.m_first_child == ia)
654 {
655 pa.m_first_child = ib;
656 changed = true;
657 }
658 if(pa.m_last_child == ia)
659 {
660 pa.m_last_child = ib;
661 changed = true;
662 }
663 if(pb.m_first_child == ib && !changed)
664 {
665 pb.m_first_child = ia;
666 }
667 if(pb.m_last_child == ib && !changed)
668 {
669 pb.m_last_child = ia;
670 }
671 }
672 }
673 else
674 {
675 if(pa.m_first_child == ia)
676 pa.m_first_child = ib;
677 if(pa.m_last_child == ia)
678 pa.m_last_child = ib;
679 if(pb.m_first_child == ib)
680 pb.m_first_child = ia;
681 if(pb.m_last_child == ib)
682 pb.m_last_child = ia;
683 }
684 std::swap(a.m_first_child , b.m_first_child);
685 std::swap(a.m_last_child , b.m_last_child);
686
687 if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
688 a.m_next_sibling != ib && b.m_next_sibling != ia)
689 {
690 if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib)
691 _p(a.m_prev_sibling)->m_next_sibling = ib;
692 if(a.m_next_sibling != NONE && a.m_next_sibling != ib)
693 _p(a.m_next_sibling)->m_prev_sibling = ib;
694 if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia)
695 _p(b.m_prev_sibling)->m_next_sibling = ia;
696 if(b.m_next_sibling != NONE && b.m_next_sibling != ia)
697 _p(b.m_next_sibling)->m_prev_sibling = ia;
698 std::swap(a.m_prev_sibling, b.m_prev_sibling);
699 std::swap(a.m_next_sibling, b.m_next_sibling);
700 }
701 else
702 {
703 if(a.m_next_sibling == ib) // n will go after m
704 {
705 _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling == ia, this, ia);
706 if(a.m_prev_sibling != NONE)
707 {
708 _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ib, this, ib);
709 _p(a.m_prev_sibling)->m_next_sibling = ib;
710 }
711 if(b.m_next_sibling != NONE)
712 {
713 _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ia, this, ia);
714 _p(b.m_next_sibling)->m_prev_sibling = ia;
715 }
716 id_type ns = b.m_next_sibling;
717 b.m_prev_sibling = a.m_prev_sibling;
718 b.m_next_sibling = ia;
719 a.m_prev_sibling = ib;
720 a.m_next_sibling = ns;
721 }
722 else if(a.m_prev_sibling == ib) // m will go after n
723 {
724 _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling == ia, this, ia);
725 if(b.m_prev_sibling != NONE)
726 {
727 _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling != ia, this, ia);
728 _p(b.m_prev_sibling)->m_next_sibling = ia;
729 }
730 if(a.m_next_sibling != NONE)
731 {
732 _RYML_ASSERT_VISIT_(m_callbacks, a.m_next_sibling != ib, this, ib);
733 _p(a.m_next_sibling)->m_prev_sibling = ib;
734 }
735 id_type ns = b.m_prev_sibling;
736 a.m_prev_sibling = b.m_prev_sibling;
737 a.m_next_sibling = ib;
738 b.m_prev_sibling = ia;
739 b.m_next_sibling = ns;
740 }
741 else
742 {
743 C4_NEVER_REACH();
744 }
745 }
746 _RYML_ASSERT_VISIT_(m_callbacks, a.m_next_sibling != ia, this, ia);
747 _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ia, this, ia);
748 _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ib, this, ib);
749 _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling != ib, this, ib);
750
751 if(a.m_parent != ib && b.m_parent != ia)
752 {
753 std::swap(a.m_parent, b.m_parent);
754 }
755 else
756 {
757 if(a.m_parent == ib && b.m_parent != ia)
758 {
759 a.m_parent = b.m_parent;
760 b.m_parent = ia;
761 }
762 else if(a.m_parent != ib && b.m_parent == ia)
763 {
764 b.m_parent = a.m_parent;
765 a.m_parent = ib;
766 }
767 else
768 {
769 C4_NEVER_REACH();
770 }
771 }
772}
773
774//-----------------------------------------------------------------------------
775void Tree::_copy_hierarchy(id_type dst_, id_type src_)
776{
777 auto const& C4_RESTRICT src = *_p(src_);
778 auto & C4_RESTRICT dst = *_p(dst_);
779 auto & C4_RESTRICT prt = *_p(src.m_parent);
780 for(id_type i = src.m_first_child; i != NONE; i = next_sibling(i))
781 {
782 _p(i)->m_parent = dst_;
783 }
784 if(src.m_prev_sibling != NONE)
785 {
786 _p(src.m_prev_sibling)->m_next_sibling = dst_;
787 }
788 if(src.m_next_sibling != NONE)
789 {
790 _p(src.m_next_sibling)->m_prev_sibling = dst_;
791 }
792 if(prt.m_first_child == src_)
793 {
794 prt.m_first_child = dst_;
795 }
796 if(prt.m_last_child == src_)
797 {
798 prt.m_last_child = dst_;
799 }
800 dst.m_parent = src.m_parent;
801 dst.m_first_child = src.m_first_child;
802 dst.m_last_child = src.m_last_child;
803 dst.m_prev_sibling = src.m_prev_sibling;
804 dst.m_next_sibling = src.m_next_sibling;
805}
806
807//-----------------------------------------------------------------------------
808void Tree::_swap_props(id_type n_, id_type m_)
809{
810 NodeData &C4_RESTRICT n = *_p(n_);
811 NodeData &C4_RESTRICT m = *_p(m_);
812 std::swap(n.m_type, m.m_type);
813 std::swap(n.m_key, m.m_key);
814 std::swap(n.m_val, m.m_val);
815}
816/** @endcond */
817
818//-----------------------------------------------------------------------------
819void Tree::move(id_type node, id_type after)
820{
821 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
822 _RYML_ASSERT_VISIT_(m_callbacks, node != after, this, node);
823 _RYML_ASSERT_VISIT_(m_callbacks, ! is_root(node), this, node);
824 _RYML_ASSERT_VISIT_(m_callbacks, (after == NONE) || (has_sibling(node, after) && has_sibling(after, node)), this, node);
825
826 _rem_hierarchy(node);
827 _set_hierarchy(node, parent(node), after);
828}
829
830//-----------------------------------------------------------------------------
831
832void Tree::move(id_type node, id_type new_parent, id_type after)
833{
834 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
835 _RYML_ASSERT_VISIT_(m_callbacks, node != after, this, node);
836 _RYML_ASSERT_VISIT_(m_callbacks, new_parent != NONE, this, new_parent);
837 _RYML_ASSERT_VISIT_(m_callbacks, new_parent != node, this, new_parent);
838 _RYML_ASSERT_VISIT_(m_callbacks, new_parent != after, this, new_parent);
839 _RYML_ASSERT_VISIT_(m_callbacks, ! is_root(node), this, node);
840
841 _rem_hierarchy(node);
842 _set_hierarchy(node, new_parent, after);
843}
844
845id_type Tree::move(Tree *src, id_type node, id_type new_parent, id_type after)
846{
847 _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, this, new_parent);
848 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, new_parent);
849 _RYML_ASSERT_VISIT_(m_callbacks, new_parent != NONE, this, new_parent);
850 _RYML_ASSERT_VISIT_(m_callbacks, new_parent != after, this, new_parent);
851
852 id_type dup = duplicate(src, node, new_parent, after);
853 src->remove(node);
854 return dup;
855}
856
858{
859 id_type root = root_id();
860 if(is_stream(root))
861 return;
862 _c4dbgpf("set_root_as_stream. rootty={}", type(root).type);
863 bool empty_root = ((type(root) & (SEQ|MAP|VAL)) == 0);
864 for(TagDirective &C4_RESTRICT td : m_tag_directives)
865 {
866 if(td.doc_id >= m_cap || _p(td.doc_id)->m_parent == NONE)
867 {
868 _c4dbgpf("tagd[{}]: id={}->NONE", &td-m_tag_directives.m_directives, td.doc_id);
869 td.doc_id = NONE;
870 }
871 }
872 // don't use _add_flags() because it's checked and will fail
873 id_type next_doc;
874 if(!has_children(root))
875 {
876 if(is_container(root))
877 {
878 next_doc = append_child(root);
879 _copy_props_wo_key(next_doc, root);
880 _p(next_doc)->m_type.add(DOC);
881 }
882 else
883 {
884 _p(root)->m_type.add(SEQ);
885 next_doc = append_child(root);
886 _copy_props_wo_key(next_doc, root);
887 _p(next_doc)->m_type.add(DOC);
888 _p(next_doc)->m_type.rem(SEQ);
889 }
890 }
891 else
892 {
893 _RYML_ASSERT_VISIT_(m_callbacks, !has_key(root), this, root);
894 next_doc = append_child(root);
895 _copy_props_wo_key(next_doc, root);
896 _add_flags(next_doc, DOC);
897 for(id_type prev = NONE, ch = first_child(root), next = next_sibling(ch); ch != NONE; )
898 {
899 if(ch == next_doc)
900 break;
901 move(ch, next_doc, prev);
902 prev = ch;
903 ch = next;
904 next = next_sibling(next);
905 }
906 }
907 _p(root)->m_type = STREAM;
908 for(TagDirective &C4_RESTRICT td : m_tag_directives)
909 {
910 id_type id = (td.doc_id != NONE) ? next_doc : (empty_root ? first_child(root) : m_free_head);
911 _c4dbgpf("tagd[{}]: id={}->{}", &td-m_tag_directives.m_directives, td.doc_id, id);
912 td.doc_id = id;
913 }
914}
915
916
917//-----------------------------------------------------------------------------
919{
920 _RYML_ASSERT_VISIT_(m_callbacks, get(node) != nullptr, this, node);
921 C4_SUPPRESS_WARNING_GCC_PUSH
922 #if defined(__GNUC__) && __GNUC__ >= 6
923 C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
924 #endif
925 id_type ich = get(node)->m_first_child;
926 while(ich != NONE)
927 {
928 remove_children(ich);
929 _RYML_ASSERT_VISIT_(m_callbacks, get(ich) != nullptr, this, node);
930 id_type next = get(ich)->m_next_sibling;
931 _release(ich);
932 if(ich == get(node)->m_last_child)
933 break;
934 ich = next;
935 }
936 C4_SUPPRESS_WARNING_GCC_POP
937}
938
940{
941 _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() || type.is_map() || type.is_seq(), this, node);
942 _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1, this, node);
943 _RYML_ASSERT_VISIT_(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()), this, node);
944 NodeData *d = _p(node);
945 if(type.is_map() && is_map(node))
946 return false;
947 else if(type.is_seq() && is_seq(node))
948 return false;
949 else if(type.is_val() && is_val(node))
950 return false;
952 remove_children(node);
953 return true;
954}
955
956
957//-----------------------------------------------------------------------------
959{
960 return duplicate(this, node, parent, after);
961}
962
964{
965 _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
966 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
967 _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
968 _RYML_ASSERT_VISIT_(m_callbacks, ! src->is_root(node), src, node);
969
970 id_type copy = _claim();
971
972 _copy_props(copy, src, node);
973 _set_hierarchy(copy, parent, after);
974 duplicate_children(src, node, copy, NONE);
975
976 return copy;
977}
978
979//-----------------------------------------------------------------------------
981{
982 return duplicate_children(this, node, parent, after);
983}
984
986{
987 _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
988 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
989 _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
990 _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
991
992 id_type prev = after;
993 for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
994 {
995 prev = duplicate(src, i, parent, prev);
996 }
997
998 return prev;
999}
1000
1001//-----------------------------------------------------------------------------
1003{
1004 duplicate_contents(this, node, where);
1005}
1006
1007void Tree::duplicate_contents(Tree const *src, id_type node, id_type where)
1008{
1009 _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
1010 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1011 _RYML_ASSERT_VISIT_(m_callbacks, where != NONE, this, where);
1012 _copy_props_wo_key(where, src, node);
1013 duplicate_children(src, node, where, last_child(where));
1014}
1015
1016//-----------------------------------------------------------------------------
1021
1023{
1024 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1025 _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
1026 _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
1027
1028 // don't loop using pointers as there may be a relocation
1029
1030 // find the position where "after" is
1031 id_type after_pos = NONE;
1032 if(after != NONE)
1033 {
1034 for(id_type i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))
1035 {
1036 if(i == after)
1037 {
1038 after_pos = icount;
1039 break;
1040 }
1041 }
1042 _RYML_ASSERT_VISIT_(m_callbacks, after_pos != NONE, this, node);
1043 }
1044
1045 // for each child to be duplicated...
1046 id_type prev = after;
1047 for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
1048 {
1049 _c4dbgpf("duplicate_no_rep: {} -> {}/{}", i, parent, prev);
1050 _RYML_CHECK_VISIT_(m_callbacks, this != src || (parent != i && !is_ancestor(parent, i)), this, parent);
1051 if(is_seq(parent))
1052 {
1053 _c4dbgpf("duplicate_no_rep: {} is seq", parent);
1054 prev = duplicate(src, i, parent, prev);
1055 }
1056 else
1057 {
1058 _c4dbgpf("duplicate_no_rep: {} is map", parent);
1059 _RYML_ASSERT_VISIT_(m_callbacks, is_map(parent), this, parent);
1060 // does the parent already have a node with key equal to that of the current duplicate?
1061 id_type dstnode_dup = NONE, dstnode_dup_pos = NONE;
1062 {
1063 csubstr srckey = src->key(i);
1064 for(id_type j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j))
1065 {
1066 if(key(j) == srckey)
1067 {
1068 _c4dbgpf("duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i, parent, j);
1069 dstnode_dup = j;
1070 dstnode_dup_pos = jcount;
1071 break;
1072 }
1073 }
1074 }
1075 _c4dbgpf("duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos);
1076 if(dstnode_dup == NONE) // there is no repetition; just duplicate
1077 {
1078 _c4dbgpf("duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i, parent, prev);
1079 prev = duplicate(src, i, parent, prev);
1080 }
1081 else // yes, there is a repetition
1082 {
1083 if(after_pos != NONE && dstnode_dup_pos <= after_pos)
1084 {
1085 // the dst duplicate is located before the node which will be inserted,
1086 // and will be overridden by the duplicate. So replace it.
1087 _c4dbgpf("duplicate_no_dstnode_dup: replace {}/{} with {}/{}", parent, dstnode_dup, node, i);
1088 if(prev == dstnode_dup)
1089 prev = prev_sibling(dstnode_dup);
1090 remove(dstnode_dup);
1091 prev = duplicate(src, i, parent, prev);
1092 }
1093 else if(prev == NONE)
1094 {
1095 _c4dbgpf("duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup);
1096 // first iteration with prev = after = NONE and dstnode_dupetition
1097 prev = dstnode_dup;
1098 }
1099 else if(dstnode_dup != prev)
1100 {
1101 // dstnode_dup is located after the node which will be inserted
1102 // and overrides it. So move the dstnode_dup into this node's place.
1103 _c4dbgpf("duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev);
1104 move(dstnode_dup, prev);
1105 prev = dstnode_dup;
1106 }
1107 } // there's a dstnode_dupetition
1108 }
1109 }
1110
1111 return prev;
1112}
1113
1114
1115//-----------------------------------------------------------------------------
1116
1117void Tree::merge_with(Tree const *src, id_type src_node, id_type dst_node)
1118{
1119 _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, src_node);
1120 if(src_node == NONE)
1121 src_node = src->root_id();
1122 if(dst_node == NONE)
1123 dst_node = root_id();
1124 _RYML_ASSERT_VISIT_(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node), src, src_node);
1125 if(src->has_val(src_node))
1126 {
1127 type_bits mask_src = ~STYLE; // keep the existing style if it is already a val
1128 if( ! has_val(dst_node))
1129 {
1130 if(has_children(dst_node))
1131 remove_children(dst_node);
1132 mask_src |= VAL_STYLE; // copy the src style
1133 }
1134 if(src->is_keyval(src_node))
1135 {
1136 _copy_props(dst_node, src, src_node, mask_src);
1137 }
1138 else
1139 {
1140 _RYML_ASSERT_VISIT_(m_callbacks, src->is_val(src_node), src, src_node);
1141 _copy_props_wo_key(dst_node, src, src_node, mask_src);
1142 }
1143 }
1144 else if(src->is_seq(src_node))
1145 {
1146 if( ! is_seq(dst_node))
1147 {
1148 if(has_children(dst_node))
1149 remove_children(dst_node);
1150 _clear_type(dst_node);
1151 if(src->has_key(src_node))
1152 to_seq(dst_node, src->key(src_node));
1153 else
1154 to_seq(dst_node);
1155 _p(dst_node)->m_type = src->_p(src_node)->m_type;
1156 }
1157 for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
1158 {
1159 id_type dch = append_child(dst_node);
1160 _copy_props_wo_key(dch, src, sch);
1161 merge_with(src, sch, dch);
1162 }
1163 }
1164 else
1165 {
1166 _RYML_ASSERT_VISIT_(m_callbacks, src->is_map(src_node), src, src_node);
1167 if( ! is_map(dst_node))
1168 {
1169 if(has_children(dst_node))
1170 remove_children(dst_node);
1171 _clear_type(dst_node);
1172 if(src->has_key(src_node))
1173 to_map(dst_node, src->key(src_node));
1174 else
1175 to_map(dst_node);
1176 _p(dst_node)->m_type = src->_p(src_node)->m_type;
1177 }
1178 for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
1179 {
1180 id_type dch = find_child(dst_node, src->key(sch));
1181 if(dch == NONE)
1182 {
1183 dch = append_child(dst_node);
1184 _copy_props(dch, src, sch);
1185 }
1186 merge_with(src, sch, dch);
1187 }
1188 }
1189}
1190
1191
1192//-----------------------------------------------------------------------------
1193
1194void Tree::resolve(bool clear_anchors)
1195{
1196 if(m_size == 0)
1197 return;
1199 resolve(&rr, clear_anchors);
1200}
1201
1202void Tree::resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors)
1203{
1204 if(m_size == 0)
1205 return;
1206 rr->resolve(this, clear_anchors);
1207}
1208
1209
1210//-----------------------------------------------------------------------------
1211
1213{
1214 id_type count = 0;
1215 for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1216 ++count;
1217 return count;
1218}
1219
1221{
1222 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1223 id_type count = 0;
1224 for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1225 {
1226 if(count++ == pos)
1227 return i;
1228 }
1229 return NONE;
1230}
1231
1233{
1234 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1235 id_type count = 0;
1236 for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1237 {
1238 if(i == ch)
1239 return count;
1240 ++count;
1241 }
1242 return NONE;
1243}
1244
1245#if defined(__clang__)
1246# pragma clang diagnostic push
1247#elif defined(__GNUC__)
1248# pragma GCC diagnostic push
1249# if __GNUC__ >= 6
1250# pragma GCC diagnostic ignored "-Wnull-dereference"
1251# endif
1252# if __GNUC__ > 9
1253# pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
1254# endif
1255#endif
1256
1257id_type Tree::find_child(id_type node, csubstr const& name) const
1258{
1259 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1260 _RYML_ASSERT_VISIT_(m_callbacks, is_map(node), this, node);
1261 if(get(node)->m_first_child == NONE)
1262 {
1263 _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child == NONE, this, node);
1264 return NONE;
1265 }
1266 else
1267 {
1268 _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child != NONE, this, node);
1269 }
1270 for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1271 {
1272 if(_p(i)->m_key.scalar == name)
1273 {
1274 return i;
1275 }
1276 }
1277 return NONE;
1278}
1279
1280#if defined(__clang__)
1281# pragma clang diagnostic pop
1282#elif defined(__GNUC__)
1283# pragma GCC diagnostic pop
1284#endif
1285
1286namespace {
1287id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0)
1288{
1289 maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
1290 for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
1291 {
1292 const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
1293 maxdepth = d > maxdepth ? d : maxdepth;
1294 }
1295 return maxdepth;
1296}
1297}
1298
1300{
1301 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1302 return depth_desc_(*this, node);
1303}
1304
1306{
1307 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1308 id_type depth = 0;
1309 while(!is_root(node))
1310 {
1311 ++depth;
1312 node = parent(node);
1313 }
1314 return depth;
1315}
1316
1317bool Tree::is_ancestor(id_type node, id_type ancestor) const
1318{
1319 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1320 id_type p = parent(node);
1321 while(p != NONE)
1322 {
1323 if(p == ancestor)
1324 return true;
1325 p = parent(p);
1326 }
1327 return false;
1328}
1329
1330
1331//-----------------------------------------------------------------------------
1332
1334{
1335 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1336 _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node);
1337 _set_flags(node, VAL|more_flags);
1338 _p(node)->m_key.clear();
1339 _p(node)->m_val = val;
1340}
1341
1343{
1344 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1345 _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1346 _set_flags(node, KEYVAL|more_flags);
1347 _p(node)->m_key = key;
1348 _p(node)->m_val = val;
1349}
1350
1351void Tree::to_map(id_type node, type_bits more_flags)
1352{
1353 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1354 _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node); // parent must not have children with keys
1355 _set_flags(node, MAP|more_flags);
1356 _p(node)->m_key.clear();
1357 _p(node)->m_val.clear();
1358}
1359
1361{
1362 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1363 _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1364 _set_flags(node, KEY|MAP|more_flags);
1365 _p(node)->m_key = key;
1366 _p(node)->m_val.clear();
1367}
1368
1369void Tree::to_seq(id_type node, type_bits more_flags)
1370{
1371 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1372 _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_seq(node), this, node);
1373 _set_flags(node, SEQ|more_flags);
1374 _p(node)->m_key.clear();
1375 _p(node)->m_val.clear();
1376}
1377
1379{
1380 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1381 _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1382 _set_flags(node, KEY|SEQ|more_flags);
1383 _p(node)->m_key = key;
1384 _p(node)->m_val.clear();
1385}
1386
1387void Tree::to_doc(id_type node, type_bits more_flags)
1388{
1389 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1390 _set_flags(node, DOC|more_flags);
1391 _p(node)->m_key.clear();
1392 _p(node)->m_val.clear();
1393}
1394
1395void Tree::to_stream(id_type node, type_bits more_flags)
1396{
1397 _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1398 _set_flags(node, STREAM|more_flags);
1399 _p(node)->m_key.clear();
1400 _p(node)->m_val.clear();
1401}
1402
1403
1404//-----------------------------------------------------------------------------
1405
1406void Tree::clear_style(id_type node, bool recurse)
1407{
1408 NodeData *C4_RESTRICT d = _p(node);
1409 d->m_type.clear_style();
1410 if(!recurse)
1411 return;
1412 for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
1413 clear_style(child, recurse);
1414}
1415
1417 NodeType type_mask,
1418 NodeType rem_style_flags,
1419 NodeType add_style_flags,
1420 bool recurse)
1421{
1422 NodeData *C4_RESTRICT d = _p(node);
1423 if((d->m_type & type_mask) == type_mask)
1424 {
1425 d->m_type &= ~(NodeType)rem_style_flags;
1426 d->m_type |= (NodeType)add_style_flags;
1427 }
1428 if(!recurse)
1429 return;
1430 for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
1431 set_style_conditionally(child, type_mask, rem_style_flags, add_style_flags, recurse);
1432}
1433
1434
1435//-----------------------------------------------------------------------------
1437{
1438 return m_tag_directives.size();
1439}
1440
1442{
1443 m_tag_directives.clear();
1444}
1445
1447{
1448 _RYML_CHECK_BASIC_(m_callbacks,
1449 !handle.empty()
1450 &&
1451 !prefix.empty()
1452 &&
1453 is_valid_tag_handle(handle)
1454 &&
1455 m_tag_directives.add(handle, prefix, id));
1456}
1457
1458size_t Tree::resolve_tag(substr output, csubstr tag, id_type node_id) const
1459{
1460 size_t reqsz = 0;
1461 m_tag_directives.resolve(output, &reqsz, tag, node_id, Location{}, callbacks());
1462 return reqsz;
1463}
1464
1465namespace {
1466// return the extra size needed for the arena to accomodate the resolved tag
1467size_t _transform_tag(Tree *t, id_type node_id, id_type doc_id, TagCache &cache, csubstr tag, csubstr *resolved)
1468{
1469 _c4dbgpf("tag: doc={} node={} resolving tag ~~~{}~~~", doc_id, node_id, tag);
1470 (void)node_id;
1471 size_t reqsize = 0;
1472 if(tag.begins_with('<'))
1473 {
1474 *resolved = tag;
1475 }
1476 else
1477 {
1478 _RYML_ASSERT_VISIT_(t->callbacks(), !tag.begins_with("!<"), t, node_id); // this should have been handled elsewhere
1479 TagCache::LookupResult ret = cache.find(tag, doc_id);
1480 if(ret)
1481 {
1482 _c4dbgpf("tag: doc={} node={} resolving tag: found in cache[{}]: {}", doc_id, node_id, ret.pos, _prs(ret.resolved));
1483 *resolved = ret.resolved;
1484 }
1485 else
1486 {
1487 _c4dbgpf("tag: doc={} node={} tag not in cache ~~~{}~~~", doc_id, node_id, tag);
1488 substr buf = t->m_arena.sub(t->m_arena_pos);
1489 reqsize = t->resolve_tag(buf, tag, doc_id);
1490 if(!reqsize)
1491 {
1492 *resolved = tag;
1493 }
1494 else if(reqsize <= buf.len)
1495 {
1496 t->m_arena_pos += reqsize;
1497 *resolved = buf.first(reqsize);
1498 cache.add(tag, *resolved, doc_id, ret.pos);
1499 reqsize = 0;
1500 }
1501 else
1502 {
1503 _c4dbgpf("tag: doc={} node={} extra size needed: {}", doc_id, node_id, reqsize);
1504 }
1505 _c4dbgpf("tag: doc={} node={} resolved tag: ~~~{}~~~", doc_id, node_id, *resolved);
1506 }
1507 }
1508 return reqsize;
1509}
1510size_t _resolve_tags(Tree *t, id_type node, id_type doc_id, TagCache &cache, bool all=true)
1511{
1512 NodeData *C4_RESTRICT d = t->_p(node);
1513 size_t extra_size = 0;
1514 if((d->m_type & KEYTAG) && (all || is_custom_tag(d->m_key.tag)))
1515 extra_size += _transform_tag(t, node, doc_id, cache, d->m_key.tag, &d->m_key.tag);
1516 if((d->m_type & VALTAG) && (all || is_custom_tag(d->m_val.tag)))
1517 extra_size += _transform_tag(t, node, doc_id, cache, d->m_val.tag, &d->m_val.tag);
1518 for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1519 extra_size += _resolve_tags(t, child, doc_id, cache);
1520 return extra_size;
1521}
1522size_t _resolve_tags(Tree *t, TagCache &cache, bool all)
1523{
1524 id_type r = t->root_id();
1525 size_t extra_size = 0;
1526 if(!t->is_stream(r))
1527 extra_size += _resolve_tags(t, r, r, cache, all);
1528 else
1529 for(id_type doc_id = t->first_child(r); doc_id != NONE; doc_id = t->next_sibling(doc_id))
1530 extra_size += _resolve_tags(t, doc_id, doc_id, cache, all);
1531 return extra_size;
1532}
1533void _normalize_tags(Tree *t, id_type node)
1534{
1535 NodeData *C4_RESTRICT d = t->_p(node);
1536 if(d->m_type & KEYTAG)
1537 d->m_key.tag = normalize_tag(d->m_key.tag);
1538 if(d->m_type & VALTAG)
1539 d->m_val.tag = normalize_tag(d->m_val.tag);
1540 for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1541 _normalize_tags(t, child);
1542}
1543void _normalize_tags_long(Tree *t, id_type node)
1544{
1545 NodeData *C4_RESTRICT d = t->_p(node);
1546 if(d->m_type & KEYTAG)
1547 d->m_key.tag = normalize_tag_long(d->m_key.tag);
1548 if(d->m_type & VALTAG)
1549 d->m_val.tag = normalize_tag_long(d->m_val.tag);
1550 for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1551 _normalize_tags_long(t, child);
1552}
1553} // namespace
1554
1555void Tree::resolve_tags(TagCache &cache, bool all)
1556{
1557 if(empty())
1558 return;
1559 // try to resolve. While doing so, get the extra size needed for
1560 // the arena, if the arena is currently too small.
1561 size_t extra_size = _resolve_tags(this, cache, all);
1562 // if the arena requires extra size, grow it and then resolve the
1563 // missing entries
1564 if(extra_size)
1565 {
1566 _c4dbgpf("tag: extrasize={} -- retry! {}->{}", extra_size, m_arena.len, m_arena.len + extra_size);
1567 _grow_arena(extra_size);
1568 extra_size = _resolve_tags(this, cache, all);
1569 _RYML_ASSERT_BASIC_(callbacks(), extra_size == 0);
1570 }
1571}
1572
1574{
1575 if(empty())
1576 return;
1577 _normalize_tags(this, root_id());
1578}
1579
1581{
1582 if(empty())
1583 return;
1584 _normalize_tags_long(this, root_id());
1585}
1586
1587
1588//-----------------------------------------------------------------------------
1589
1591{
1592 csubstr p = path.first(path_pos);
1593 if(p.ends_with('.'))
1594 p = p.first(p.len-1);
1595 return p;
1596}
1597
1599{
1600 return path.sub(path_pos);
1601}
1602
1603void Tree::_advance(lookup_result *r, size_t more)
1604{
1605 r->path_pos += more;
1606 if(r->path.sub(r->path_pos).begins_with('.'))
1607 ++r->path_pos;
1608}
1609
1611{
1612 if(start == NONE)
1613 start = root_id();
1614 lookup_result r(path, start);
1615 if(path.empty())
1616 return r;
1617 _lookup_path(&r);
1618 if(r.target == NONE && r.closest == start)
1619 r.closest = NONE;
1620 return r;
1621}
1622
1624{
1625 id_type target = _lookup_path_or_create(path, start);
1626 if(parent_is_map(target))
1627 to_keyval(target, key(target), default_value);
1628 else
1629 to_val(target, default_value);
1630 return target;
1631}
1632
1634{
1635 id_type target = _lookup_path_or_create(path, start);
1636 merge_with(src, src_node, target);
1637 return target;
1638}
1639
1640id_type Tree::_lookup_path_or_create(csubstr path, id_type start)
1641{
1642 if(start == NONE)
1643 start = root_id();
1644 lookup_result r(path, start);
1645 _lookup_path(&r);
1646 if(r.target != NONE)
1647 {
1648 C4_ASSERT(r.unresolved().empty());
1649 return r.target;
1650 }
1651 _lookup_path_modify(&r);
1652 return r.target;
1653}
1654
1655void Tree::_lookup_path(lookup_result *r) const
1656{
1657 C4_ASSERT( ! r->unresolved().empty());
1658 _lookup_path_token parent{"", type(r->closest)};
1659 id_type node;
1660 do
1661 {
1662 node = _next_node(r, &parent);
1663 if(node != NONE)
1664 r->closest = node;
1665 if(r->unresolved().empty())
1666 {
1667 r->target = node;
1668 return;
1669 }
1670 } while(node != NONE);
1671}
1672
1673void Tree::_lookup_path_modify(lookup_result *r)
1674{
1675 C4_ASSERT( ! r->unresolved().empty());
1676 _lookup_path_token parent{"", type(r->closest)};
1677 id_type node;
1678 do
1679 {
1680 node = _next_node_modify(r, &parent);
1681 if(node != NONE)
1682 r->closest = node;
1683 if(r->unresolved().empty())
1684 {
1685 r->target = node;
1686 return;
1687 }
1688 } while(node != NONE);
1689}
1690
1691id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const
1692{
1693 _lookup_path_token token = _next_token(r, *parent);
1694 if( ! token)
1695 return NONE;
1696
1697 id_type node = NONE;
1698 csubstr prev = token.value;
1699 if(token.type == MAP || token.type == SEQ)
1700 {
1701 _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
1702 //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1703 _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1704 node = find_child(r->closest, token.value);
1705 }
1706 else if(token.type == KEYVAL)
1707 {
1708 _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
1709 if(is_map(r->closest))
1710 node = find_child(r->closest, token.value);
1711 }
1712 else if(token.type == KEY)
1713 {
1714 _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
1715 token.value = token.value.offs(1, 1).trim(' ');
1716 id_type idx = 0;
1717 _RYML_CHECK_BASIC_(m_callbacks, from_chars(token.value, &idx));
1718 node = child(r->closest, idx);
1719 }
1720 else
1721 {
1722 C4_NEVER_REACH();
1723 }
1724
1725 if(node != NONE)
1726 {
1727 *parent = token;
1728 }
1729 else
1730 {
1731 csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
1732 r->path_pos -= prev.len;
1733 if(p.begins_with('.'))
1734 r->path_pos -= 1u;
1735 }
1736
1737 return node;
1738}
1739
1740id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
1741{
1742 _lookup_path_token token = _next_token(r, *parent);
1743 if( ! token)
1744 return NONE;
1745
1746 id_type node = NONE;
1747 if(token.type == MAP || token.type == SEQ)
1748 {
1749 _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
1750 //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1751 if( ! is_container(r->closest))
1752 {
1753 if(has_key(r->closest))
1754 to_map(r->closest, key(r->closest));
1755 else
1756 to_map(r->closest);
1757 }
1758 else
1759 {
1760 if(is_map(r->closest))
1761 {
1762 node = find_child(r->closest, token.value);
1763 }
1764 else
1765 {
1766 id_type pos = NONE;
1767 _RYML_CHECK_BASIC_(m_callbacks, c4::atox(token.value, &pos));
1768 _RYML_ASSERT_VISIT_(m_callbacks, pos != NONE, this, r->closest);
1769 node = child(r->closest, pos);
1770 }
1771 }
1772 if(node == NONE)
1773 {
1774 _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1775 node = append_child(r->closest);
1776 NodeData *n = _p(node);
1777 n->m_key.scalar = token.value;
1778 n->m_type.add(KEY);
1779 }
1780 }
1781 else if(token.type == KEYVAL)
1782 {
1783 _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
1784 if(is_map(r->closest))
1785 {
1786 node = find_child(r->closest, token.value);
1787 if(node == NONE)
1788 node = append_child(r->closest);
1789 }
1790 else
1791 {
1792 _RYML_ASSERT_VISIT_(m_callbacks, !is_seq(r->closest), this, r->closest);
1793 _add_flags(r->closest, MAP);
1794 node = append_child(r->closest);
1795 }
1796 NodeData *n = _p(node);
1797 n->m_key.scalar = token.value;
1798 n->m_val.scalar = "";
1799 n->m_type.add(KEYVAL);
1800 }
1801 else if(token.type == KEY)
1802 {
1803 _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
1804 token.value = token.value.offs(1, 1).trim(' ');
1805 id_type idx;
1806 if( ! from_chars(token.value, &idx))
1807 return NONE;
1808 if( ! is_container(r->closest))
1809 {
1810 if(has_key(r->closest))
1811 {
1812 csubstr k = key(r->closest);
1813 _clear_type(r->closest);
1814 to_seq(r->closest, k);
1815 }
1816 else
1817 {
1818 _clear_type(r->closest);
1819 to_seq(r->closest);
1820 }
1821 }
1822 _RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest), this, r->closest);
1823 node = child(r->closest, idx);
1824 if(node == NONE)
1825 {
1826 _RYML_ASSERT_VISIT_(m_callbacks, num_children(r->closest) <= idx, this, r->closest);
1827 for(id_type i = num_children(r->closest); i <= idx; ++i)
1828 {
1829 node = append_child(r->closest);
1830 if(i < idx)
1831 {
1832 if(is_map(r->closest))
1833 to_keyval(node, /*"~"*/{}, /*"~"*/{});
1834 else if(is_seq(r->closest))
1835 to_val(node, /*"~"*/{});
1836 }
1837 }
1838 }
1839 }
1840 else
1841 {
1842 C4_NEVER_REACH();
1843 }
1844
1845 _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, r->closest);
1846 *parent = token;
1847 return node;
1848}
1849
1850/* types of tokens:
1851 * - seeing "map." ---> "map"/MAP
1852 * - finishing "scalar" ---> "scalar"/KEYVAL
1853 * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)
1854 * - seeing "[n]" ---> "[n]"/KEY
1855 */
1856Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const
1857{
1858 csubstr unres = r->unresolved();
1859 if(unres.empty())
1860 return {};
1861
1862 // is it an indexation like [0], [1], etc?
1863 if(unres.begins_with('['))
1864 {
1865 size_t pos = unres.find(']');
1866 if(pos == csubstr::npos)
1867 return {};
1868 csubstr idx = unres.first(pos + 1);
1869 _advance(r, pos + 1);
1870 return {idx, KEY};
1871 }
1872
1873 // no. so it must be a name
1874 size_t pos = unres.first_of(".[");
1875 if(pos == csubstr::npos)
1876 {
1877 _advance(r, unres.len);
1878 NodeType t;
1879 if(( ! parent) || parent.type.is_seq())
1880 return {unres, VAL};
1881 return {unres, KEYVAL};
1882 }
1883
1884 // it's either a map or a seq
1885 _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '.' || unres[pos] == '[', this, r->closest);
1886 if(unres[pos] == '.')
1887 {
1888 _RYML_ASSERT_VISIT_(m_callbacks, pos != 0, this, r->closest);
1889 _advance(r, pos + 1);
1890 return {unres.first(pos), MAP};
1891 }
1892
1893 _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '[', this, r->closest);
1894 _advance(r, pos);
1895 return {unres.first(pos), SEQ};
1896}
1897
1898
1899} // namespace yml
1900} // namespace c4
1901
1902
1903//-----------------------------------------------------------------------------
1904//-----------------------------------------------------------------------------
1905//-----------------------------------------------------------------------------
1906
1909#include "c4/yml/parse.hpp"
1910
1911namespace c4 {
1912namespace yml {
1913
1914Location Tree::location(Parser const& parser, id_type node) const
1915{
1916 // try hard to avoid getting the location from a null string.
1917 Location loc;
1918 if(_location_from_node(parser, node, &loc, 0))
1919 return loc;
1920 return parser.val_location(parser.source().str);
1921}
1922
1923bool Tree::_location_from_node(Parser const& parser, id_type node, Location *C4_RESTRICT loc, id_type level) const
1924{
1925 if(has_key(node))
1926 {
1927 csubstr k = key(node);
1928 if(C4_LIKELY(k.str != nullptr))
1929 {
1930 _RYML_ASSERT_BASIC_(m_callbacks, k.is_sub(parser.source()));
1931 _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(k));
1932 *loc = parser.val_location(k.str);
1933 return true;
1934 }
1935 }
1936
1937 if(has_val(node))
1938 {
1939 csubstr v = val(node);
1940 if(C4_LIKELY(v.str != nullptr))
1941 {
1942 _RYML_ASSERT_BASIC_(m_callbacks, v.is_sub(parser.source()));
1943 _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(v));
1944 *loc = parser.val_location(v.str);
1945 return true;
1946 }
1947 }
1948
1949 if(is_container(node))
1950 {
1951 if(_location_from_cont(parser, node, loc))
1952 return true;
1953 }
1954
1955 if(type(node) != NOTYPE && level == 0)
1956 {
1957 // try the prev sibling
1958 {
1959 const id_type prev = prev_sibling(node);
1960 if(prev != NONE)
1961 {
1962 if(_location_from_node(parser, prev, loc, level+1))
1963 return true;
1964 }
1965 }
1966 // try the next sibling
1967 {
1968 const id_type next = next_sibling(node);
1969 if(next != NONE)
1970 {
1971 if(_location_from_node(parser, next, loc, level+1))
1972 return true;
1973 }
1974 }
1975 // try the parent
1976 {
1977 const id_type parent = this->parent(node);
1978 if(parent != NONE)
1979 {
1980 if(_location_from_node(parser, parent, loc, level+1))
1981 return true;
1982 }
1983 }
1984 }
1985 return false;
1986}
1987
1988bool Tree::_location_from_cont(Parser const& parser, id_type node, Location *C4_RESTRICT loc) const
1989{
1990 _RYML_ASSERT_BASIC_(m_callbacks, is_container(node));
1991 if(!is_stream(node))
1992 {
1993 const char *node_start = _p(node)->m_val.scalar.str; // this was stored in the container
1994 if(has_children(node))
1995 {
1996 id_type child = first_child(node);
1997 if(has_key(child))
1998 {
1999 // when a map starts, the container was set after the key
2000 csubstr k = key(child);
2001 if(k.str && node_start > k.str)
2002 node_start = k.str;
2003 }
2004 }
2005 *loc = parser.val_location(node_start);
2006 return true;
2007 }
2008 else // it's a stream
2009 {
2010 *loc = parser.val_location(parser.source().str); // just return the front of the buffer
2011 }
2012 return true;
2013}
2014
2015} // namespace yml
2016} // namespace c4
2017
2018
2019// NOLINTEND(modernize-avoid-c-style-cast)
2020C4_SUPPRESS_WARNING_GCC_CLANG_POP
2021C4_SUPPRESS_WARNING_MSVC_POP
Holds a pointer to an existing tree, and a node id.
Definition node.hpp:827
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition node.hpp:967
Location val_location(const char *val) const
Given a pointer to a buffer position, get the location.
csubstr source() const
Get the latest YAML buffer parsed by this object.
NodeData * m_buf
Definition tree.hpp:1331
void move(id_type node, id_type after)
change the node's position in the parent
Definition tree.cpp:819
NodeData * _p(id_type node)
An if-less form of get() that demands a valid node index. This function is implementation only; use a...
Definition tree.hpp:331
id_type duplicate(id_type node, id_type new_parent, id_type after)
recursively duplicate a node from this tree into a new parent, placing it after one of its children
Definition tree.cpp:958
void clear()
clear the tree and zero every node
Definition tree.cpp:330
id_type m_free_head
Definition tree.hpp:1335
lookup_result lookup_path(csubstr path, id_type start=NONE) const
for example foo.bar[0].baz
Definition tree.cpp:1610
csubstr const & key(id_type node) const
Definition tree.hpp:387
id_type lookup_path_or_modify(csubstr default_value, csubstr path, id_type start=NONE)
defaulted lookup: lookup path; if the lookup fails, recursively modify the tree so that the correspon...
Definition tree.cpp:1623
id_type first_child(id_type node) const
Definition tree.hpp:512
bool is_stream(id_type node) const
Definition tree.hpp:410
NodeType type(id_type node) const
Definition tree.hpp:384
void set_root_as_stream()
ensure the first node is a stream.
Definition tree.cpp:857
id_type root_id() const
Get the id of the root node. The tree must not be empty.
Definition tree.hpp:337
NodeRef rootref()
Get the root as a NodeRef.
Definition tree.cpp:56
void resolve_tags(TagCache &cache, bool all=true)
Resolve tags in the tree such as "!!str" -> "<tag:yaml.org,2002:str>", "!foo" -> "<!...
Definition tree.cpp:1555
id_type prev_sibling(id_type node) const
Definition tree.hpp:506
void reserve_arena(size_t arena_cap=RYML_DEFAULT_TREE_ARENA_CAPACITY)
ensure the tree's internal string arena is at least the given capacity
Definition tree.hpp:973
size_t m_arena_pos
Definition tree.hpp:1339
bool is_map(id_type node) const
Definition tree.hpp:413
void clear_tag_directives()
Definition tree.cpp:1441
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
Definition tree.cpp:292
csubstr const & val(id_type node) const
Definition tree.hpp:393
Tree & operator=(Tree const &that)
Definition tree.cpp:159
void to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags=0)
Definition tree.cpp:1342
TagDirectives m_tag_directives
Definition tree.hpp:1343
bool is_root(id_type node) const
Definition tree.hpp:462
NodeRef ref(id_type node)
Get a NodeRef of a node by id.
Definition tree.cpp:70
bool is_keyval(id_type node) const
Definition tree.hpp:418
id_type m_size
Definition tree.hpp:1333
void to_doc(id_type node, type_bits more_flags=0)
Definition tree.cpp:1387
bool has_key(id_type node) const
Definition tree.hpp:415
id_type depth_asc(id_type node) const
O(log(num_tree_nodes)) get the ascending depth of the node: number of levels between root and node.
Definition tree.cpp:1305
bool in_arena(csubstr s) const
return true if the given substring is part of the tree's string arena
Definition tree.hpp:889
id_type parent(id_type node) const
Definition tree.hpp:504
size_t resolve_tag(substr output, csubstr tag, id_type node_id) const
resolve the given tag, appearing at node_id.
Definition tree.cpp:1458
bool is_val(id_type node) const
Definition tree.hpp:417
bool empty() const
Definition tree.hpp:284
id_type child_pos(id_type node, id_type ch) const
Definition tree.cpp:1232
id_type append_child(id_type parent)
create and insert a node as the last child of parent
Definition tree.hpp:721
void clear_style(id_type node, bool recurse=false)
Definition tree.cpp:1406
void to_stream(id_type node, type_bits more_flags=0)
Definition tree.cpp:1395
bool has_sibling(id_type node, id_type sib) const
true if node has a sibling with id sib
Definition tree.hpp:480
id_type next_sibling(id_type node) const
Definition tree.hpp:507
void to_seq(id_type node, csubstr key, type_bits more_flags=0)
Definition tree.cpp:1378
id_type depth_desc(id_type node) const
O(num_tree_nodes) get the descending depth of the node: number of levels between node and deepest chi...
Definition tree.cpp:1299
id_type num_tag_directives() const
Definition tree.cpp:1436
bool parent_is_seq(id_type node) const
Definition tree.hpp:428
ConstNodeRef crootref() const
Get the root as a ConstNodeRef.
Definition tree.cpp:65
id_type duplicate_children_no_rep(id_type node, id_type parent, id_type after)
duplicate the node's children (but not the node) in a new parent, but omit repetitions where a duplic...
Definition tree.cpp:1017
id_type m_cap
Definition tree.hpp:1332
id_type last_child(id_type node) const
Definition tree.hpp:513
id_type id(NodeData const *n) const
get the index of a node belonging to this tree. n can be nullptr, in which case NONE is returned
Definition tree.hpp:302
ConstNodeRef cdocref(id_type i) const
get the i-th document of the stream
Definition tree.cpp:112
void set_style_conditionally(id_type node, NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
Definition tree.cpp:1416
substr m_arena
Definition tree.hpp:1338
void normalize_tags()
Definition tree.cpp:1573
NodeRef docref(id_type i)
get the i-th document of the stream
Definition tree.cpp:104
void reorder()
reorder the tree in memory so that all the nodes are stored in a linear sequence when visited in dept...
Definition tree.cpp:576
void remove_children(id_type node)
remove all the node's children, but keep the node itself
Definition tree.cpp:918
bool is_ancestor(id_type node, id_type ancestor) const
true when ancestor is parent or parent of a parent of node
Definition tree.cpp:1317
bool has_val(id_type node) const
Definition tree.hpp:416
void to_map(id_type node, csubstr key, type_bits more_flags=0)
Definition tree.cpp:1360
Callbacks const & callbacks() const
Definition tree.hpp:290
size_t arena_capacity() const
get the current capacity of the tree's internal arena
Definition tree.hpp:878
id_type doc(id_type i) const
gets the i document node index.
Definition tree.hpp:532
bool change_type(id_type node, NodeType type)
change the type of the node to one of MAP, SEQ or VAL.
Definition tree.cpp:939
id_type m_free_tail
Definition tree.hpp:1336
void normalize_tags_long()
Definition tree.cpp:1580
void resolve(ReferenceResolver *rr, bool clear_anchors=true)
Resolve references (aliases <- anchors), by forwarding to ReferenceResolver::resolve(); refer to Refe...
Definition tree.cpp:1202
bool is_seq(id_type node) const
Definition tree.hpp:414
bool parent_is_map(id_type node) const
Definition tree.hpp:429
void remove(id_type node)
remove an entire branch at once: ie remove the children and the node itself
Definition tree.hpp:753
id_type find_child(id_type node, csubstr const &key) const
Definition tree.cpp:1257
Location location(Parser const &p, id_type node) const
Get the location of a node from the parse used to parse this tree.
Definition tree.cpp:1914
void duplicate_contents(id_type node, id_type where)
Definition tree.cpp:1002
NodeData * get(id_type node)
get a pointer to a node's NodeData. i can be NONE, in which case a nullptr is returned
Definition tree.hpp:312
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
Definition tree.cpp:1446
id_type duplicate_children(id_type node, id_type parent, id_type after)
recursively duplicate the node's children (but not the node)
Definition tree.cpp:980
id_type num_children(id_type node) const
O(num_children).
Definition tree.cpp:1212
csubstr arena() const
get the current arena
Definition tree.hpp:884
void merge_with(Tree const *src, id_type src_node=NONE, id_type dst_root=NONE)
Definition tree.cpp:1117
id_type _claim()
Definition tree.cpp:414
bool is_container(id_type node) const
Definition tree.hpp:412
id_type child(id_type node, id_type pos) const
Definition tree.cpp:1220
bool has_child(id_type node, id_type ch) const
true if node has a child with id ch
Definition tree.hpp:473
ConstNodeRef cref(id_type node) const
Get a NodeRef of a node by id.
Definition tree.cpp:80
Callbacks m_callbacks
Definition tree.hpp:1341
void to_val(id_type node, csubstr val, type_bits more_flags=0)
Definition tree.cpp:1333
bool has_children(id_type node) const
true if node has any children key
Definition tree.hpp:477
#define RYML_DEFAULT_TREE_CAPACITY
default capacity for the tree when not set explicitly
Definition common.hpp:16
#define RYML_DEFAULT_TREE_ARENA_CAPACITY
default capacity for the tree's arena when not set explicitly
Definition common.hpp:21
bool atox(csubstr s, uint8_t *v) noexcept
bool from_chars(csubstr buf, uint8_t *v) noexcept
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition node_type.hpp:30
@ NOTYPE
no node type or style is set
Definition node_type.hpp:36
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition node_type.hpp:39
@ STREAM
a stream: a seq of docs
Definition node_type.hpp:42
@ KEY
is member of a map
Definition node_type.hpp:37
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
Definition node_type.hpp:93
@ KEYTAG
the key has a tag
Definition node_type.hpp:47
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition node_type.hpp:38
@ VALTAG
the val has a tag
Definition node_type.hpp:48
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
Definition node_type.hpp:40
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
Definition node_type.hpp:92
@ CONTAINER_STYLE
Definition node_type.hpp:97
@ DOC
a document
Definition node_type.hpp:41
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree.
Definition fwd.hpp:19
size_t to_chars(ryml::substr buf, vec2< T > v)
basic_substring< char > substr
a mutable string view
Definition substr.hpp:2356
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2357
bool is_valid_tag_handle(csubstr handle)
Definition tag.cpp:210
bool is_custom_tag(csubstr tag)
is a tag of the form !handle!tag?
Definition tag.cpp:9
csubstr normalize_tag_long(csubstr tag)
Definition tag.cpp:31
csubstr normalize_tag(csubstr tag)
Definition tag.cpp:19
csubstr serialize_to_arena(Tree *tree, csubstr a)
Definition tree.cpp:19
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
Definition common.hpp:249
@ NONE
an index to none
Definition common.hpp:256
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition common.cpp:14
Node classes.
bool begins_with(const C c) const noexcept
true if the first character of the string is c
Definition substr.hpp:851
size_t len
the length of the substring
Definition substr.hpp:218
bool ends_with(const C c) const noexcept
true if the last character of the string is c
Definition substr.hpp:895
size_t first_of(const C c, size_t start=0) const
Definition substr.hpp:935
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
Definition substr.hpp:530
basic_substring sub(size_t first) const noexcept
return [first,len[
Definition substr.hpp:503
bool empty() const noexcept
Definition substr.hpp:356
bool is_super(ro_substr const that) const noexcept
true if that is a substring of *this (ie, from the same buffer)
Definition substr.hpp:485
C * str
a restricted pointer to the first character of the substring
Definition substr.hpp:216
bool is_sub(ro_substr const that) const noexcept
true if *this is a substring of that (ie, from the same buffer)
Definition substr.hpp:479
A c-style callbacks class to customize behavior on errors or allocation.
Definition common.hpp:546
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition common.hpp:289
contains the data for each YAML node.
Definition tree.hpp:230
NodeType m_type
Definition tree.hpp:231
id_type m_next_sibling
Definition tree.hpp:239
id_type m_parent
Definition tree.hpp:236
NodeScalar m_key
Definition tree.hpp:233
id_type m_prev_sibling
Definition tree.hpp:240
id_type m_first_child
Definition tree.hpp:237
NodeScalar m_val
Definition tree.hpp:234
void clear() noexcept
Definition tree.hpp:145
wraps a NodeType_e element with some syntactic sugar and predicates
void rem(NodeType_e t) noexcept
void add(NodeType_e t) noexcept
Reusable object to resolve references/aliases in a Tree.
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
Definition tag.hpp:71
LookupResult find(csubstr tag, id_type doc_id, id_type linear_threshold=Entries::sso_size) const noexcept
Definition tag.cpp:537
void add(csubstr tag, csubstr resolved, id_type doc_id, const_iterator pos) RYML_NOEXCEPT
Definition tag.cpp:594
csubstr unresolved() const
get the part ot the input path that was unresolved
Definition tree.cpp:1598
csubstr resolved() const
get the part ot the input path that was resolved
Definition tree.cpp:1590