1#ifndef C4_YML_TREE_HPP_
4#ifndef C4_YML_DETAIL_DBGPRINT_HPP_
5#include "c4/yml/detail/dbgprint.hpp"
7#ifndef C4_YML_NODE_HPP_
10#ifndef C4_YML_REFERENCE_RESOLVERS_HPP_
15C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296)
16C4_SUPPRESS_WARNING_MSVC(4702)
17C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wold-style-cast")
18C4_SUPPRESS_WARNING_GCC(
"-Wtype-limits")
19C4_SUPPRESS_WARNING_GCC(
"-Wuseless-cast")
35 if(scalar.
str ==
nullptr)
47 return tree->_request_span(0);
197C4_SUPPRESS_WARNING_GCC_PUSH
198#if defined(__GNUC__) && __GNUC__>= 8
199 C4_SUPPRESS_WARNING_GCC_WITH_PUSH(
"-Wclass-memaccess")
214void Tree::_copy(
Tree const& that)
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));
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;
242void Tree::_move(
Tree & that)
noexcept
244 RYML_ASSERT_VISIT_CB_(m_callbacks, m_buf ==
nullptr,
this,
NONE);
245 RYML_ASSERT_VISIT_CB_(m_callbacks, m_arena.str ==
nullptr,
this,
NONE);
246 RYML_ASSERT_VISIT_CB_(m_callbacks, m_arena.len == 0,
this,
NONE);
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;
258void Tree::_relocate(
substr next_arena)
260 RYML_ASSERT_VISIT_CB_(
m_callbacks, next_arena.not_empty(),
this,
NONE);
269 n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
271 n->m_key.tag = _relocated(n->m_key.tag, next_arena);
273 n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
275 n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
277 n->m_val.tag = _relocated(n->m_val.tag, next_arena);
279 n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
284 td.prefix = _relocated(td.prefix, next_arena);
286 td.handle = _relocated(td.handle, next_arena);
305 _clear_range(first, del);
332 _clear_range(0,
m_cap);
349void Tree::_claim_root()
352 RYML_ASSERT_VISIT_CB_(
m_callbacks, r == 0,
this, r);
362 RYML_ASSERT_VISIT_CB_(
m_callbacks, first >= 0 && first + num <=
m_cap,
this, first);
363 memset(
m_buf + first, 0, (
size_t)num *
sizeof(NodeData));
364 for(
id_type i = first, e = first + num; i < e; ++i)
367 NodeData *n =
m_buf + i;
369 n->m_next_sibling = i + 1;
374C4_SUPPRESS_WARNING_GCC_POP
391void Tree::_free_list_add(
id_type i)
394 NodeData &C4_RESTRICT w =
m_buf[i];
398 w.m_prev_sibling =
NONE;
406void Tree::_free_list_rem(
id_type i)
447 C4_SUPPRESS_WARNING_PUSH
448 C4_SUPPRESS_WARNING_CLANG(
"-Wnull-dereference")
449 #if defined(__GNUC__)
451 C4_SUPPRESS_WARNING_GCC(
"-Wnull-dereference")
454 C4_SUPPRESS_WARNING_GCC(
"-Wanalyzer-fd-leak")
457 RYML_ASSERT_VISIT_CB_(
m_callbacks, ichild >= 0 && ichild <
m_cap,
this, ichild);
458 RYML_ASSERT_VISIT_CB_(
m_callbacks, iparent ==
NONE || (iparent >= 0 && iparent <
m_cap),
this, iparent);
459 RYML_ASSERT_VISIT_CB_(
m_callbacks, iprev_sibling ==
NONE || (iprev_sibling >= 0 && iprev_sibling <
m_cap),
this, iprev_sibling);
461 NodeData *C4_RESTRICT
child =
_p(ichild);
463 child->m_parent = iparent;
469 RYML_ASSERT_VISIT_CB_(
m_callbacks, ichild == 0,
this, ichild);
470 RYML_ASSERT_VISIT_CB_(
m_callbacks, iprev_sibling ==
NONE,
this, iprev_sibling);
477 NodeData *C4_RESTRICT
parent =
get(iparent);
478 NodeData *C4_RESTRICT psib =
get(iprev_sibling);
479 NodeData *C4_RESTRICT nsib =
get(inext_sibling);
484 child->m_prev_sibling =
id(psib);
485 psib->m_next_sibling =
id(
child);
486 RYML_ASSERT_VISIT_CB_(
m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling ==
NONE,
this, iprev_sibling);
492 child->m_next_sibling =
id(nsib);
493 nsib->m_prev_sibling =
id(
child);
494 RYML_ASSERT_VISIT_CB_(
m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling ==
NONE,
this, inext_sibling);
511 C4_SUPPRESS_WARNING_POP
517void Tree::_rem_hierarchy(
id_type i)
521 NodeData &C4_RESTRICT w =
m_buf[i];
524 if(w.m_parent !=
NONE)
526 NodeData &C4_RESTRICT p =
m_buf[w.m_parent];
527 if(p.m_first_child == i)
529 p.m_first_child = w.m_next_sibling;
531 if(p.m_last_child == i)
533 p.m_last_child = w.m_prev_sibling;
538 if(w.m_prev_sibling !=
NONE)
540 NodeData *C4_RESTRICT prev =
get(w.m_prev_sibling);
541 prev->m_next_sibling = w.m_next_sibling;
543 if(w.m_next_sibling !=
NONE)
545 NodeData *C4_RESTRICT next =
get(w.m_next_sibling);
546 next->m_prev_sibling = w.m_prev_sibling;
567 count = _do_reorder(&i, count);
591 _swap_hierarchy(n_, m_);
597 _copy_hierarchy(n_, m_);
605 _copy_hierarchy(m_, n_);
622 if(i == ib || i == ia)
629 if(i == ib || i == ia)
634 auto & C4_RESTRICT a = *
_p(ia);
635 auto & C4_RESTRICT b = *
_p(ib);
636 auto & C4_RESTRICT pa = *
_p(a.m_parent);
637 auto & C4_RESTRICT pb = *
_p(b.m_parent);
641 if((pa.m_first_child == ib && pa.m_last_child == ia)
643 (pa.m_first_child == ia && pa.m_last_child == ib))
645 std::swap(pa.m_first_child, pa.m_last_child);
649 bool changed =
false;
650 if(pa.m_first_child == ia)
652 pa.m_first_child = ib;
655 if(pa.m_last_child == ia)
657 pa.m_last_child = ib;
660 if(pb.m_first_child == ib && !changed)
662 pb.m_first_child = ia;
664 if(pb.m_last_child == ib && !changed)
666 pb.m_last_child = ia;
672 if(pa.m_first_child == ia)
673 pa.m_first_child = ib;
674 if(pa.m_last_child == ia)
675 pa.m_last_child = ib;
676 if(pb.m_first_child == ib)
677 pb.m_first_child = ia;
678 if(pb.m_last_child == ib)
679 pb.m_last_child = ia;
681 std::swap(a.m_first_child , b.m_first_child);
682 std::swap(a.m_last_child , b.m_last_child);
684 if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
685 a.m_next_sibling != ib && b.m_next_sibling != ia)
687 if(a.m_prev_sibling !=
NONE && a.m_prev_sibling != ib)
689 if(a.m_next_sibling !=
NONE && a.m_next_sibling != ib)
691 if(b.m_prev_sibling !=
NONE && b.m_prev_sibling != ia)
693 if(b.m_next_sibling !=
NONE && b.m_next_sibling != ia)
695 std::swap(a.m_prev_sibling, b.m_prev_sibling);
696 std::swap(a.m_next_sibling, b.m_next_sibling);
700 if(a.m_next_sibling == ib)
702 RYML_ASSERT_VISIT_CB_(
m_callbacks, b.m_prev_sibling == ia,
this, ia);
703 if(a.m_prev_sibling !=
NONE)
705 RYML_ASSERT_VISIT_CB_(
m_callbacks, a.m_prev_sibling != ib,
this, ib);
708 if(b.m_next_sibling !=
NONE)
710 RYML_ASSERT_VISIT_CB_(
m_callbacks, b.m_next_sibling != ia,
this, ia);
714 b.m_prev_sibling = a.m_prev_sibling;
715 b.m_next_sibling = ia;
716 a.m_prev_sibling = ib;
717 a.m_next_sibling = ns;
719 else if(a.m_prev_sibling == ib)
721 RYML_ASSERT_VISIT_CB_(
m_callbacks, b.m_next_sibling == ia,
this, ia);
722 if(b.m_prev_sibling !=
NONE)
724 RYML_ASSERT_VISIT_CB_(
m_callbacks, b.m_prev_sibling != ia,
this, ia);
727 if(a.m_next_sibling !=
NONE)
729 RYML_ASSERT_VISIT_CB_(
m_callbacks, a.m_next_sibling != ib,
this, ib);
733 a.m_prev_sibling = b.m_prev_sibling;
734 a.m_next_sibling = ib;
735 b.m_prev_sibling = ia;
736 b.m_next_sibling = ns;
743 RYML_ASSERT_VISIT_CB_(
m_callbacks, a.m_next_sibling != ia,
this, ia);
744 RYML_ASSERT_VISIT_CB_(
m_callbacks, a.m_prev_sibling != ia,
this, ia);
745 RYML_ASSERT_VISIT_CB_(
m_callbacks, b.m_next_sibling != ib,
this, ib);
746 RYML_ASSERT_VISIT_CB_(
m_callbacks, b.m_prev_sibling != ib,
this, ib);
748 if(a.m_parent != ib && b.m_parent != ia)
750 std::swap(a.m_parent, b.m_parent);
754 if(a.m_parent == ib && b.m_parent != ia)
756 a.m_parent = b.m_parent;
759 else if(a.m_parent != ib && b.m_parent == ia)
761 b.m_parent = a.m_parent;
774 auto const& C4_RESTRICT src = *
_p(src_);
775 auto & C4_RESTRICT dst = *
_p(dst_);
776 auto & C4_RESTRICT prt = *
_p(src.m_parent);
781 if(src.m_prev_sibling !=
NONE)
785 if(src.m_next_sibling !=
NONE)
789 if(prt.m_first_child == src_)
791 prt.m_first_child = dst_;
793 if(prt.m_last_child == src_)
795 prt.m_last_child = dst_;
797 dst.m_parent = src.m_parent;
798 dst.m_first_child = src.m_first_child;
799 dst.m_last_child = src.m_last_child;
800 dst.m_prev_sibling = src.m_prev_sibling;
801 dst.m_next_sibling = src.m_next_sibling;
807 NodeData &C4_RESTRICT n = *
_p(n_);
808 NodeData &C4_RESTRICT m = *
_p(m_);
809 std::swap(n.m_type, m.m_type);
810 std::swap(n.m_key, m.m_key);
811 std::swap(n.m_val, m.m_val);
820 RYML_ASSERT_VISIT_CB_(
m_callbacks, node != after,
this, node);
824 _rem_hierarchy(node);
825 _set_hierarchy(node,
parent(node), after);
833 RYML_ASSERT_VISIT_CB_(
m_callbacks, node != after,
this, node);
834 RYML_ASSERT_VISIT_CB_(
m_callbacks, new_parent !=
NONE,
this, new_parent);
835 RYML_ASSERT_VISIT_CB_(
m_callbacks, new_parent != node,
this, new_parent);
836 RYML_ASSERT_VISIT_CB_(
m_callbacks, new_parent != after,
this, new_parent);
839 _rem_hierarchy(node);
840 _set_hierarchy(node, new_parent, after);
845 RYML_ASSERT_VISIT_CB_(
m_callbacks, src !=
nullptr,
this, new_parent);
847 RYML_ASSERT_VISIT_CB_(
m_callbacks, new_parent !=
NONE,
this, new_parent);
848 RYML_ASSERT_VISIT_CB_(
m_callbacks, new_parent != after,
this, new_parent);
861 _c4dbgpf(
"set_root_as_stream. rootty={}",
type(root).m_bits);
865 if(td.doc_id >=
m_cap ||
_p(td.doc_id)->m_parent ==
NONE)
867 _c4dbgpf(
"tagd[{}]: id={}->NONE", &td-
m_tag_directives.m_directives, td.doc_id);
878 _copy_props_wo_key(next_doc, root);
885 _copy_props_wo_key(next_doc, root);
894 _copy_props_wo_key(next_doc, root);
895 _add_flags(next_doc,
DOC);
900 move(ch, next_doc, prev);
910 _c4dbgpf(
"tagd[{}]: id={}->{}", &td-
m_tag_directives.m_directives, td.doc_id,
id);
919 RYML_ASSERT_VISIT_CB_(
m_callbacks,
get(node) !=
nullptr,
this, node);
920 C4_SUPPRESS_WARNING_GCC_PUSH
921 #if defined(__GNUC__) && __GNUC__ >= 6
922 C4_SUPPRESS_WARNING_GCC(
"-Wnull-dereference")
928 RYML_ASSERT_VISIT_CB_(
m_callbacks,
get(ich) !=
nullptr,
this, node);
931 if(ich ==
get(node)->m_last_child)
935 C4_SUPPRESS_WARNING_GCC_POP
967 RYML_ASSERT_VISIT_CB_(
m_callbacks, src !=
nullptr, src, node);
974 _copy_props(copy, src, node);
975 _set_hierarchy(copy,
parent, after);
990 RYML_ASSERT_VISIT_CB_(
m_callbacks, src !=
nullptr, src, node);
1012 RYML_ASSERT_VISIT_CB_(
m_callbacks, src !=
nullptr, src, node);
1015 _copy_props_wo_key(where, src, node);
1053 _c4dbgpf(
"duplicate_no_rep: {} -> {}/{}", i,
parent, prev);
1057 _c4dbgpf(
"duplicate_no_rep: {} is seq",
parent);
1062 _c4dbgpf(
"duplicate_no_rep: {} is map",
parent);
1070 if(
key(j) == srckey)
1072 _c4dbgpf(
"duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i,
parent, j);
1074 dstnode_dup_pos = jcount;
1079 _c4dbgpf(
"duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos);
1080 if(dstnode_dup ==
NONE)
1082 _c4dbgpf(
"duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i,
parent, prev);
1087 if(after_pos !=
NONE && dstnode_dup_pos <= after_pos)
1091 _c4dbgpf(
"duplicate_no_dstnode_dup: replace {}/{} with {}/{}",
parent, dstnode_dup, node, i);
1092 if(prev == dstnode_dup)
1097 else if(prev ==
NONE)
1099 _c4dbgpf(
"duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup);
1103 else if(dstnode_dup != prev)
1107 _c4dbgpf(
"duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev);
1108 move(dstnode_dup, prev);
1123 RYML_ASSERT_VISIT_CB_(
m_callbacks, src !=
nullptr, src, src_node);
1124 if(src_node ==
NONE)
1126 if(dst_node ==
NONE)
1142 _copy_props(dst_node, src, src_node, mask_src);
1147 _copy_props_wo_key(dst_node, src, src_node, mask_src);
1156 _clear_type(dst_node);
1165 _copy_props_wo_key(dch, src, sch);
1176 _clear_type(dst_node);
1188 _copy_props(dch, src, sch);
1210 rr->resolve(
this, clear_anchors);
1251 C4_SUPPRESS_WARNING_PUSH
1252 #if defined(__clang__)
1253 #elif defined(__GNUC__)
1255 C4_SUPPRESS_WARNING_GCC(
"-Wnull-dereference")
1258 C4_SUPPRESS_WARNING_GCC(
"-Wanalyzer-null-dereference")
1262 RYML_ASSERT_VISIT_CB_(
m_callbacks,
_p(node)->m_type.m_bits &
MAP,
this, node);
1265 if(
_p(i)->m_key.scalar == name)
1269 C4_SUPPRESS_WARNING_POP
1276 maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
1277 for(
id_type child = t.first_child(
id); child !=
NONE; child = t.next_sibling(child))
1279 const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
1280 maxdepth = d > maxdepth ? d : maxdepth;
1289 return depth_desc_(*
this, node);
1327 nd->m_type =
VAL|more_flags;
1337 NodeData* C4_RESTRICT nd =
_p(node);
1338 nd->m_type =
KEYVAL|more_flags;
1346 NodeData* C4_RESTRICT nd =
_p(node);
1347 nd->m_type =
MAP|more_flags;
1356 NodeData* C4_RESTRICT nd =
_p(node);
1357 nd->m_type =
KEY|
MAP|more_flags;
1366 NodeData* C4_RESTRICT nd =
_p(node);
1367 nd->m_type =
SEQ|more_flags;
1376 NodeData* C4_RESTRICT nd =
_p(node);
1377 nd->m_type =
KEY|
SEQ|more_flags;
1385 NodeData* C4_RESTRICT nd =
_p(node);
1386 nd->m_type =
DOC|more_flags;
1394 NodeData* C4_RESTRICT nd =
_p(node);
1395 nd->m_type =
STREAM|more_flags;
1407 d->m_type.clear_style();
1421 if((d->m_type & type_mask) == type_mask)
1423 d->m_type &= ~(
NodeType)rem_style_flags;
1424 d->m_type |= (
NodeType)add_style_flags;
1467 _c4dbgpf(
"tag: doc={} node={} resolving tag ~~~{}~~~", doc_id, node_id, tag);
1477 TagCache::LookupResult ret = cache.
find(tag, doc_id);
1480 _c4dbgpf(
"tag: doc={} node={} resolving tag: found in cache[{}]: {}", doc_id, node_id, ret.pos, prs_(ret.resolved));
1481 *resolved = ret.resolved;
1485 _c4dbgpf(
"tag: doc={} node={} tag not in cache ~~~{}~~~", doc_id, node_id, tag);
1492 else if(reqsize <= buf.len)
1495 *resolved = buf.
first(reqsize);
1496 cache.
add(tag, *resolved, doc_id, ret.pos);
1501 _c4dbgpf(
"tag: doc={} node={} extra size needed: {}", doc_id, node_id, reqsize);
1503 _c4dbgpf(
"tag: doc={} node={} resolved tag: ~~~{}~~~", doc_id, node_id, *resolved);
1510 NodeData *C4_RESTRICT d = t->_p(node);
1511 size_t extra_size = 0;
1513 extra_size += _transform_tag(t, node, doc_id, cache, d->m_key.tag, &d->m_key.tag);
1515 extra_size += _transform_tag(t, node, doc_id, cache, d->m_val.tag, &d->m_val.tag);
1516 for(
id_type child = t->first_child(node); child !=
NONE; child = t->next_sibling(child))
1517 extra_size += _resolve_tags(t, child, doc_id, cache);
1520size_t _resolve_tags(
Tree *t,
TagCache &cache,
bool all)
1523 size_t extra_size = 0;
1524 if(!t->is_stream(r))
1525 extra_size += _resolve_tags(t, r, r, cache, all);
1527 for(
id_type doc_id = t->first_child(r); doc_id !=
NONE; doc_id = t->next_sibling(doc_id))
1528 extra_size += _resolve_tags(t, doc_id, doc_id, cache, all);
1533 NodeData *C4_RESTRICT d = t->_p(node);
1538 for(
id_type child = t->first_child(node); child !=
NONE; child = t->next_sibling(child))
1539 _normalize_tags(t, child);
1543 NodeData *C4_RESTRICT d = t->_p(node);
1548 for(
id_type child = t->first_child(node); child !=
NONE; child = t->next_sibling(child))
1549 _normalize_tags_long(t, child);
1559 size_t extra_size = _resolve_tags(
this, cache, all);
1564 _c4dbgpf(
"tag: extrasize={} -- retry! {}->{}", extra_size,
m_arena.len,
m_arena.len + extra_size);
1565 _grow_arena(extra_size);
1566 extra_size = _resolve_tags(
this, cache, all);
1567 RYML_ASSERT_BASIC_CB_(
callbacks(), extra_size == 0);
1575 _normalize_tags(
this,
root_id());
1582 _normalize_tags_long(
this,
root_id());
1623 id_type target = _lookup_path_or_create(path, start);
1624 set_val(target, default_value);
1630 id_type target = _lookup_path_or_create(path, start);
1639 lookup_result r(path, start);
1646 _lookup_path_modify(&r);
1650void Tree::_lookup_path(lookup_result *r)
const
1652 C4_ASSERT( ! r->unresolved().empty());
1653 _lookup_path_token
parent{
"",
type(r->closest)};
1657 node = _next_node(r, &
parent);
1660 if(r->unresolved().empty())
1665 }
while(node !=
NONE);
1670 C4_ASSERT( ! r->unresolved().empty());
1671 _lookup_path_token
parent{
"",
type(r->closest)};
1675 node = _next_node_modify(r, &
parent);
1678 if(r->unresolved().empty())
1683 }
while(node !=
NONE);
1688 _lookup_path_token token = _next_token(r, *
parent);
1694 if(token.type ==
MAP || token.type ==
SEQ)
1696 RYML_ASSERT_VISIT_CB_(
m_callbacks, !token.value.begins_with(
'['),
this, r->closest);
1701 else if(token.type ==
KEYVAL)
1703 RYML_ASSERT_VISIT_CB_(
m_callbacks, r->unresolved().empty(),
this, r->closest);
1707 else if(token.type ==
KEY)
1709 RYML_ASSERT_VISIT_CB_(
m_callbacks, token.value.begins_with(
'[') && token.value.ends_with(
']'),
this, r->closest);
1710 token.value = token.value.offs(1, 1).trim(
' ');
1713 node =
child(r->closest, idx);
1726 csubstr p = r->path.
sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
1727 r->path_pos -= prev.
len;
1728 if(p.begins_with(
'.'))
1737 _lookup_path_token token = _next_token(r, *
parent);
1742 NodeType ty =
type(r->closest);
1743 if(token.type ==
MAP || token.type ==
SEQ)
1745 RYML_ASSERT_VISIT_CB_(
m_callbacks, !token.value.begins_with(
'['),
this, r->closest);
1747 if( ! ty.is_container())
1762 node =
child(r->closest, pos);
1769 NodeData *n =
_p(node);
1770 n->m_key.scalar = token.value;
1774 else if(token.type ==
KEYVAL)
1776 RYML_ASSERT_VISIT_CB_(
m_callbacks, r->unresolved().empty(),
this, r->closest);
1785 RYML_ASSERT_VISIT_CB_(
m_callbacks, !ty.is_seq(),
this, r->closest);
1786 _add_flags(r->closest,
MAP);
1789 NodeData *n =
_p(node);
1790 n->m_key.scalar = token.value;
1791 n->m_val.scalar =
"";
1794 else if(token.type ==
KEY)
1796 RYML_ASSERT_VISIT_CB_(
m_callbacks, token.value.begins_with(
'[') && token.value.ends_with(
']'),
this, r->closest);
1797 token.value = token.value.offs(1, 1).trim(
' ');
1808 node =
child(r->closest, idx);
1849Tree::_lookup_path_token Tree::_next_token(
lookup_result *r, _lookup_path_token
const&
parent)
const
1851 csubstr unres = r->unresolved();
1856 if(unres.begins_with(
'['))
1858 size_t pos = unres.find(
']');
1862 _advance(r, pos + 1);
1870 _advance(r, unres.len);
1873 return {unres,
VAL};
1878 RYML_ASSERT_VISIT_CB_(
m_callbacks, unres[pos] ==
'.' || unres[pos] ==
'[',
this, r->closest);
1879 if(unres[pos] ==
'.')
1881 RYML_ASSERT_VISIT_CB_(
m_callbacks, pos != 0,
this, r->closest);
1882 _advance(r, pos + 1);
1883 return {unres.first(pos),
MAP};
1886 RYML_ASSERT_VISIT_CB_(
m_callbacks, unres[pos] ==
'[',
this, r->closest);
1888 return {unres.first(pos),
SEQ};
1900#ifndef C4_YML_EVENT_HANDLER_TREE_HPP_
1903#ifndef C4_YML_PARSE_ENGINE_DEF_HPP_
1906#ifndef C4_YML_PARSE_HPP_
1917 if(_location_from_node(parser, node, &loc, 0))
1928 if C4_LIKELY(k.
str !=
nullptr)
1940 if C4_LIKELY(v.str !=
nullptr)
1951 if(_location_from_cont(parser, node, loc))
1962 if(_location_from_node(parser, prev, loc, level+1))
1971 if(_location_from_node(parser, next, loc, level+1))
1980 if(_location_from_node(parser,
parent, loc, level+1))
2001 if(k.str && node_start > k.str)
2005 *loc = parser.val_location(node_start);
2010 *loc = parser.val_location(parser.source().str);
2020C4_SUPPRESS_WARNING_GCC_CLANG_POP
2021C4_SUPPRESS_WARNING_MSVC_POP
Holds a pointer to an existing tree, and a node id.
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
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.
void move(id_type node, id_type after)
change the node's position in the parent
NodeData * _p(id_type node)
An if-less form of get() that demands a valid node index. This function is implementation only; use a...
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
void clear()
clear the tree and zero every node
lookup_result lookup_path(csubstr path, id_type start=NONE) const
for example foo.bar[0].baz
csubstr const & key(id_type node) const
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...
id_type first_child(id_type node) const
bool is_stream(id_type node) const
NodeType type(id_type node) const
void set_root_as_stream()
ensure the first node is a stream.
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 ...
NodeRef rootref()
Get the root as a NodeRef . Note that a non-const Tree implicitly converts to NodeRef.
void resolve_tags(TagCache &cache, bool all=true)
Resolve tags in the tree such as "!!str" -> "<tag:yaml.org,2002:str>", "!foo" -> "<!...
id_type prev_sibling(id_type node) const
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
void set_val(id_type node, csubstr val) RYML_NOEXCEPT
bool is_map(id_type node) const
void clear_tag_directives()
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
csubstr const & val(id_type node) const
Tree & operator=(Tree const &that)
TagDirectives m_tag_directives
bool is_root(id_type node) const
NodeRef ref(id_type node)
Get a NodeRef of a node by id.
bool has_key(id_type node) const
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.
bool in_arena(csubstr s) const
return true if the given substring is part of the tree's string arena
id_type parent(id_type node) const
size_t resolve_tag(substr output, csubstr tag, id_type node_id) const
resolve the given tag, appearing at node_id.
bool empty() const
Query for zero size.
void set_seq(id_type node) RYML_NOEXCEPT
id_type child_pos(id_type node, id_type ch) const
id_type append_child(id_type parent)
create and insert a node as the last child of parent
void clear_style(id_type node, bool recurse=false)
bool has_sibling(id_type node, id_type sib) const
true if node has a sibling with id sib
id_type next_sibling(id_type node) const
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...
id_type num_tag_directives() const
bool parent_is_seq(id_type node) const
ConstNodeRef crootref() const
Get the root as a ConstNodeRef . Note that Tree implicitly converts to ConstNodeRef.
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...
id_type last_child(id_type node) const
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 ...
ConstNodeRef cdocref(id_type i) const
get the i-th document of the stream
void set_style_conditionally(id_type node, NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
NodeRef docref(id_type i)
get the i-th document of the stream
void reorder()
reorder the tree in memory so that all the nodes are stored in a linear sequence when visited in dept...
void remove_children(id_type node)
remove all the node's children, but keep the node itself
bool is_ancestor(id_type node, id_type ancestor) const
true when ancestor is parent or parent of a parent of node
Callbacks const & callbacks() const
size_t arena_capacity() const
get the current capacity of the tree's internal arena
id_type doc(id_type i) const
gets the i document node index.
bool change_type(id_type node, NodeType type)
void normalize_tags_long()
void resolve(ReferenceResolver *rr, bool clear_anchors=true)
Resolve references (aliases <- anchors), by forwarding to ReferenceResolver::resolve(); refer to Refe...
bool is_seq(id_type node) const
bool parent_is_map(id_type node) const
void set_map(id_type node) RYML_NOEXCEPT
void remove(id_type node)
remove an entire branch at once: ie remove the children and the node itself
id_type find_child(id_type node, csubstr const &key) const
find child by name, or NONE if no child is found with this key like Tree::child(),...
Location location(Parser const &p, id_type node) const
Get the location of a node from the parse used to parse this tree.
void duplicate_contents(id_type node, id_type where)
NodeData * get(id_type node)
get a pointer to a node's NodeData. node can be NONE, in which case a nullptr is returned
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
id_type duplicate_children(id_type node, id_type parent, id_type after)
recursively duplicate the node's children (but not the node)
void set_key(id_type node, csubstr key) RYML_NOEXCEPT
id_type num_children(id_type node) const
O(num_children).
csubstr arena() const
get the current arena
void merge_with(Tree const *src, id_type src_node=NONE, id_type dst_root=NONE)
bool is_container(id_type node) const
id_type child(id_type node, id_type pos) const
find child by position, or NONE if there are less than pos children posi
bool has_child(id_type node, id_type ch) const
true if node has a child with id ch
ConstNodeRef cref(id_type node) const
Get a NodeRef of a node by id.
bool has_children(id_type node) const
true if node has any children
#define RYML_DEFAULT_TREE_CAPACITY
default capacity for the tree when not set explicitly
#define RYML_DEFAULT_TREE_ARENA_CAPACITY
default capacity for the tree's arena when not set explicitly
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
@ NOTYPE
no node type or style is set
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
@ STREAM
a stream: a seq of docs
@ KEY
the scalar to the left of : in a map's member
@ VAL_STYLE
mask of VALQUO|VAL_PLAIN : all the val scalar styles for val (not container styles!...
@ KEYTAG
the key has a tag
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
@ VALTAG
the val has a tag
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
@ 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
@ CONTAINER_STYLE
mask of CONTAINER_STYLE_FLOW|CONTAINER_STYLE_BLOCK : all container style flags
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree (see Event Ha...
csubstr serialize_to_arena_str(Tree *tree, csubstr scalar)
Serialize a string type (as specified by c4::is_string) to a tree's arena, ensuring that there is an ...
csubstr serialize_to_arena_scalar(Tree *tree, T const &scalar)
Serialize a scalar to the tree's arena.
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
bool is_valid_tag_handle(csubstr handle)
bool is_custom_tag(csubstr tag)
is a tag of the form !handle!tag?
csubstr normalize_tag_long(csubstr tag)
csubstr normalize_tag(csubstr tag)
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...
bool begins_with(const C c) const noexcept
true if the first character of the string is c
size_t len
the length of the substring
bool ends_with(const C c) const noexcept
true if the last character of the string is c
size_t first_of(const C c, size_t start=0) const
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
basic_substring sub(size_t first) const noexcept
return [first,len[
bool empty() const noexcept
bool is_super(ro_substr const that) const noexcept
true if that is a substring of *this (ie, from the same buffer)
C * str
a restricted pointer to the first character of the substring
bool is_sub(ro_substr const that) const noexcept
true if *this is a substring of that (ie, from the same buffer)
A c-style callbacks class to customize behavior on errors or allocation.
holds a source or yaml file position, for example when an error is detected; See also location_format...
contains the data for each YAML node.
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
bool has_key() const noexcept
bool is_seq() const noexcept
void rem(type_bits t) noexcept
bool has_val() const noexcept
bool is_map() const noexcept
bool is_container() const noexcept
void add(type_bits t) noexcept
bool is_keyval() const noexcept
bool is_val() const noexcept
bool is_stream() const noexcept
Reusable object to resolve references/aliases in a Tree.
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
LookupResult find(csubstr tag, id_type doc_id, id_type linear_threshold=Entries::sso_size) const noexcept
void add(csubstr tag, csubstr resolved, id_type doc_id, const_iterator pos) RYML_NOEXCEPT
csubstr unresolved() const
get the part ot the input path that was unresolved
csubstr resolved() const
get the part ot the input path that was resolved