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