2 #include "c4/yml/detail/dbgprint.hpp"
7 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296)
8 C4_SUPPRESS_WARNING_MSVC(4702)
9 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
10 C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
11 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
22 substr rem(tree->m_arena.sub(tree->m_arena_pos));
26 rem = tree->_grow_arena(num);
28 _RYML_ASSERT_VISIT_(tree->m_callbacks, num <= rem.len, tree,
NONE);
30 return tree->_request_span(num);
38 else if(tree->m_arena.str ==
nullptr)
46 return tree->_request_span(0);
57 return NodeRef(
this, root_id());
71 _RYML_ASSERT_VISIT_(m_callbacks,
id !=
NONE &&
id >= 0 &&
id < m_cap,
this,
id);
76 _RYML_ASSERT_VISIT_(m_callbacks,
id !=
NONE &&
id >= 0 &&
id < m_cap,
this,
id);
81 _RYML_ASSERT_VISIT_(m_callbacks,
id !=
NONE &&
id >= 0 &&
id < m_cap,
this,
id);
87 return rootref()[
key];
91 return rootref()[
key];
174 m_callbacks = that.m_callbacks;
196 C4_SUPPRESS_WARNING_GCC_PUSH
197 #if defined(__GNUC__) && __GNUC__>= 8
198 C4_SUPPRESS_WARNING_GCC_WITH_PUSH(
"-Wclass-memaccess")
214 void 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));
234 arena.str = _RYML_CB_ALLOC_HINT(
m_callbacks,
char, that.m_arena.len, that.m_arena.str);
235 arena.len = that.m_arena.len;
243 void Tree::_move(Tree & that) noexcept
245 _RYML_ASSERT_VISIT_(m_callbacks, m_buf ==
nullptr,
this,
NONE);
246 _RYML_ASSERT_VISIT_(m_callbacks, m_arena.str ==
nullptr,
this,
NONE);
247 _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len == 0,
this,
NONE);
250 m_size = that.m_size;
251 m_free_head = that.m_free_head;
252 m_free_tail = that.m_free_tail;
253 m_arena = that.m_arena;
254 m_arena_pos = that.m_arena_pos;
256 m_tag_directives[i] = that.m_tag_directives[i];
260 void Tree::_relocate(substr next_arena)
271 n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
273 n->m_key.tag = _relocated(n->m_key.tag, next_arena);
275 n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
277 n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
279 n->m_val.tag = _relocated(n->m_val.tag, next_arena);
281 n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
286 td.prefix = _relocated(td.prefix, next_arena);
288 td.handle = _relocated(td.handle, next_arena);
307 _clear_range(first, del);
334 _clear_range(0,
m_cap);
352 void Tree::_claim_root()
365 _RYML_ASSERT_VISIT_(
m_callbacks, first >= 0 && first + num <=
m_cap,
this, first);
366 memset(
m_buf + first, 0, (
size_t)num *
sizeof(NodeData));
367 for(
id_type i = first, e = first + num; i < e; ++i)
370 NodeData *n =
m_buf + i;
372 n->m_next_sibling = i + 1;
377 C4_SUPPRESS_WARNING_GCC_POP
394 void Tree::_free_list_add(
id_type i)
397 NodeData &C4_RESTRICT w =
m_buf[i];
401 w.m_prev_sibling =
NONE;
409 void Tree::_free_list_rem(
id_type i)
448 C4_SUPPRESS_WARNING_GCC_PUSH
449 C4_SUPPRESS_WARNING_CLANG_PUSH
450 C4_SUPPRESS_WARNING_CLANG(
"-Wnull-dereference")
451 #if defined(__GNUC__)
453 C4_SUPPRESS_WARNING_GCC(
"-Wnull-dereference")
456 C4_SUPPRESS_WARNING_GCC(
"-Wanalyzer-fd-leak")
462 _RYML_ASSERT_VISIT_(
m_callbacks, ichild >= 0 && ichild <
m_cap,
this, ichild);
463 _RYML_ASSERT_VISIT_(
m_callbacks, iparent ==
NONE || (iparent >= 0 && iparent <
m_cap),
this, iparent);
464 _RYML_ASSERT_VISIT_(
m_callbacks, iprev_sibling ==
NONE || (iprev_sibling >= 0 && iprev_sibling <
m_cap),
this, iprev_sibling);
468 child->m_parent = iparent;
474 _RYML_ASSERT_VISIT_(
m_callbacks, ichild == 0,
this, ichild);
475 _RYML_ASSERT_VISIT_(
m_callbacks, iprev_sibling ==
NONE,
this, iprev_sibling);
482 NodeData *C4_RESTRICT
parent =
get(iparent);
483 NodeData *C4_RESTRICT psib =
get(iprev_sibling);
484 NodeData *C4_RESTRICT nsib =
get(inext_sibling);
489 child->m_prev_sibling =
id(psib);
490 psib->m_next_sibling =
id(
child);
491 _RYML_ASSERT_VISIT_(
m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling ==
NONE,
this, iprev_sibling);
497 child->m_next_sibling =
id(nsib);
498 nsib->m_prev_sibling =
id(
child);
499 _RYML_ASSERT_VISIT_(
m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling ==
NONE,
this, inext_sibling);
518 C4_SUPPRESS_WARNING_GCC_POP
519 C4_SUPPRESS_WARNING_CLANG_POP
523 void Tree::_rem_hierarchy(
id_type i)
527 NodeData &C4_RESTRICT w =
m_buf[i];
530 if(w.m_parent !=
NONE)
532 NodeData &C4_RESTRICT p =
m_buf[w.m_parent];
533 if(p.m_first_child == i)
537 if(p.m_last_child == i)
539 p.m_last_child = w.m_prev_sibling;
544 if(w.m_prev_sibling !=
NONE)
546 NodeData *C4_RESTRICT prev =
get(w.m_prev_sibling);
547 prev->m_next_sibling = w.m_next_sibling;
549 if(w.m_next_sibling !=
NONE)
551 NodeData *C4_RESTRICT next =
get(w.m_next_sibling);
552 next->m_prev_sibling = w.m_prev_sibling;
573 count = _do_reorder(&i, count);
597 _swap_hierarchy(n_, m_);
603 _copy_hierarchy(n_, m_);
611 _copy_hierarchy(m_, n_);
628 if(i == ib || i == ia)
635 if(i == ib || i == ia)
640 auto & C4_RESTRICT a = *
_p(ia);
641 auto & C4_RESTRICT b = *
_p(ib);
642 auto & C4_RESTRICT pa = *
_p(a.m_parent);
643 auto & C4_RESTRICT pb = *
_p(b.m_parent);
647 if((pa.m_first_child == ib && pa.m_last_child == ia)
649 (pa.m_first_child == ia && pa.m_last_child == ib))
651 std::swap(pa.m_first_child, pa.m_last_child);
655 bool changed =
false;
656 if(pa.m_first_child == ia)
658 pa.m_first_child = ib;
661 if(pa.m_last_child == ia)
663 pa.m_last_child = ib;
666 if(pb.m_first_child == ib && !changed)
668 pb.m_first_child = ia;
670 if(pb.m_last_child == ib && !changed)
672 pb.m_last_child = ia;
678 if(pa.m_first_child == ia)
679 pa.m_first_child = ib;
680 if(pa.m_last_child == ia)
681 pa.m_last_child = ib;
682 if(pb.m_first_child == ib)
683 pb.m_first_child = ia;
684 if(pb.m_last_child == ib)
685 pb.m_last_child = ia;
687 std::swap(a.m_first_child , b.m_first_child);
688 std::swap(a.m_last_child , b.m_last_child);
690 if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
691 a.m_next_sibling != ib && b.m_next_sibling != ia)
693 if(a.m_prev_sibling !=
NONE && a.m_prev_sibling != ib)
695 if(a.m_next_sibling !=
NONE && a.m_next_sibling != ib)
697 if(b.m_prev_sibling !=
NONE && b.m_prev_sibling != ia)
699 if(b.m_next_sibling !=
NONE && b.m_next_sibling != ia)
701 std::swap(a.m_prev_sibling, b.m_prev_sibling);
702 std::swap(a.m_next_sibling, b.m_next_sibling);
706 if(a.m_next_sibling == ib)
708 _RYML_ASSERT_VISIT_(
m_callbacks, b.m_prev_sibling == ia,
this, ia);
709 if(a.m_prev_sibling !=
NONE)
711 _RYML_ASSERT_VISIT_(
m_callbacks, a.m_prev_sibling != ib,
this, ib);
714 if(b.m_next_sibling !=
NONE)
716 _RYML_ASSERT_VISIT_(
m_callbacks, b.m_next_sibling != ia,
this, ia);
720 b.m_prev_sibling = a.m_prev_sibling;
721 b.m_next_sibling = ia;
722 a.m_prev_sibling = ib;
723 a.m_next_sibling = ns;
725 else if(a.m_prev_sibling == ib)
727 _RYML_ASSERT_VISIT_(
m_callbacks, b.m_next_sibling == ia,
this, ia);
728 if(b.m_prev_sibling !=
NONE)
730 _RYML_ASSERT_VISIT_(
m_callbacks, b.m_prev_sibling != ia,
this, ia);
733 if(a.m_next_sibling !=
NONE)
735 _RYML_ASSERT_VISIT_(
m_callbacks, a.m_next_sibling != ib,
this, ib);
739 a.m_prev_sibling = b.m_prev_sibling;
740 a.m_next_sibling = ib;
741 b.m_prev_sibling = ia;
742 b.m_next_sibling = ns;
749 _RYML_ASSERT_VISIT_(
m_callbacks, a.m_next_sibling != ia,
this, ia);
750 _RYML_ASSERT_VISIT_(
m_callbacks, a.m_prev_sibling != ia,
this, ia);
751 _RYML_ASSERT_VISIT_(
m_callbacks, b.m_next_sibling != ib,
this, ib);
752 _RYML_ASSERT_VISIT_(
m_callbacks, b.m_prev_sibling != ib,
this, ib);
754 if(a.m_parent != ib && b.m_parent != ia)
756 std::swap(a.m_parent, b.m_parent);
760 if(a.m_parent == ib && b.m_parent != ia)
762 a.m_parent = b.m_parent;
765 else if(a.m_parent != ib && b.m_parent == ia)
767 b.m_parent = a.m_parent;
780 auto const& C4_RESTRICT src = *
_p(src_);
781 auto & C4_RESTRICT dst = *
_p(dst_);
782 auto & C4_RESTRICT prt = *
_p(src.m_parent);
787 if(src.m_prev_sibling !=
NONE)
791 if(src.m_next_sibling !=
NONE)
795 if(prt.m_first_child == src_)
797 prt.m_first_child = dst_;
799 if(prt.m_last_child == src_)
801 prt.m_last_child = dst_;
803 dst.m_parent = src.m_parent;
804 dst.m_first_child = src.m_first_child;
805 dst.m_last_child = src.m_last_child;
806 dst.m_prev_sibling = src.m_prev_sibling;
807 dst.m_next_sibling = src.m_next_sibling;
813 NodeData &C4_RESTRICT n = *
_p(n_);
814 NodeData &C4_RESTRICT m = *
_p(m_);
815 std::swap(n.m_type, m.m_type);
816 std::swap(n.m_key, m.m_key);
817 std::swap(n.m_val, m.m_val);
825 _RYML_ASSERT_VISIT_(
m_callbacks, node != after,
this, node);
829 _rem_hierarchy(node);
830 _set_hierarchy(node,
parent(node), after);
838 _RYML_ASSERT_VISIT_(
m_callbacks, node != after,
this, node);
839 _RYML_ASSERT_VISIT_(
m_callbacks, new_parent !=
NONE,
this, new_parent);
840 _RYML_ASSERT_VISIT_(
m_callbacks, new_parent != node,
this, new_parent);
841 _RYML_ASSERT_VISIT_(
m_callbacks, new_parent != after,
this, new_parent);
844 _rem_hierarchy(node);
845 _set_hierarchy(node, new_parent, after);
850 _RYML_ASSERT_VISIT_(
m_callbacks, src !=
nullptr,
this, new_parent);
852 _RYML_ASSERT_VISIT_(
m_callbacks, new_parent !=
NONE,
this, new_parent);
853 _RYML_ASSERT_VISIT_(
m_callbacks, new_parent != after,
this, new_parent);
871 _copy_props_wo_key(next_doc, root);
878 _copy_props_wo_key(next_doc, root);
887 _copy_props_wo_key(next_doc, root);
888 _add_flags(next_doc,
DOC);
893 move(ch, next_doc, prev);
905 _RYML_ASSERT_VISIT_(
m_callbacks,
get(node) !=
nullptr,
this, node);
907 C4_SUPPRESS_WARNING_GCC_WITH_PUSH(
"-Wnull-dereference")
911 C4_SUPPRESS_WARNING_GCC_POP
916 _RYML_ASSERT_VISIT_(
m_callbacks,
get(ich) !=
nullptr,
this, node);
919 if(ich ==
get(node)->m_last_child)
951 _RYML_ASSERT_VISIT_(
m_callbacks, src !=
nullptr, src, node);
958 _copy_props(copy, src, node);
959 _set_hierarchy(copy,
parent, after);
973 _RYML_ASSERT_VISIT_(
m_callbacks, src !=
nullptr, src, node);
995 _RYML_ASSERT_VISIT_(
m_callbacks, src !=
nullptr, src, node);
998 _copy_props_wo_key(where, src, node);
1035 _c4dbgpf(
"duplicate_no_rep: {} -> {}/{}", i,
parent, prev);
1039 _c4dbgpf(
"duplicate_no_rep: {} is seq",
parent);
1044 _c4dbgpf(
"duplicate_no_rep: {} is map",
parent);
1049 csubstr srckey = src->
key(i);
1052 if(
key(j) == srckey)
1054 _c4dbgpf(
"duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i,
parent, j);
1056 dstnode_dup_pos = jcount;
1061 _c4dbgpf(
"duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos);
1062 if(dstnode_dup ==
NONE)
1064 _c4dbgpf(
"duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i,
parent, prev);
1069 if(after_pos !=
NONE && dstnode_dup_pos <= after_pos)
1073 _c4dbgpf(
"duplicate_no_dstnode_dup: replace {}/{} with {}/{}",
parent, dstnode_dup, node, i);
1074 if(prev == dstnode_dup)
1079 else if(prev ==
NONE)
1081 _c4dbgpf(
"duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup);
1085 else if(dstnode_dup != prev)
1089 _c4dbgpf(
"duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev);
1090 move(dstnode_dup, prev);
1105 _RYML_ASSERT_VISIT_(
m_callbacks, src !=
nullptr, src, src_node);
1106 if(src_node ==
NONE)
1108 if(dst_node ==
NONE)
1122 _copy_props(dst_node, src, src_node, mask_src);
1127 _copy_props_wo_key(dst_node, src, src_node, mask_src);
1130 else if(src->
is_seq(src_node))
1136 _clear_type(dst_node);
1146 _copy_props_wo_key(dch, src, sch);
1157 _clear_type(dst_node);
1170 _copy_props(dch, src, sch);
1192 rr->resolve(
this, clear_anchors);
1231 #if defined(__clang__)
1232 # pragma clang diagnostic push
1233 #elif defined(__GNUC__)
1234 # pragma GCC diagnostic push
1236 # pragma GCC diagnostic ignored "-Wnull-dereference"
1239 # pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
1247 if(
get(node)->m_first_child ==
NONE)
1266 #if defined(__clang__)
1267 # pragma clang diagnostic pop
1268 #elif defined(__GNUC__)
1269 # pragma GCC diagnostic pop
1275 maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
1276 for(
id_type child = t.first_child(
id); child !=
NONE; child = t.next_sibling(child))
1278 const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
1279 maxdepth = d > maxdepth ? d : maxdepth;
1288 return depth_desc_(*
this, node);
1323 _set_flags(node,
VAL|more_flags);
1332 _set_flags(node,
KEYVAL|more_flags);
1341 _set_flags(node,
MAP|more_flags);
1350 _set_flags(node,
KEY|
MAP|more_flags);
1359 _set_flags(node,
SEQ|more_flags);
1368 _set_flags(node,
KEY|
SEQ|more_flags);
1376 _set_flags(node,
DOC|more_flags);
1384 _set_flags(node,
STREAM|more_flags);
1395 d->m_type.clear_style();
1409 if((d->m_type & type_mask) == type_mask)
1411 d->m_type &= ~(
NodeType)rem_style_flags;
1412 d->m_type |= (
NodeType)add_style_flags;
1444 _RYML_CHECK_BASIC_(
m_callbacks, td.
handle ==
'!' || td.
handle ==
"!!" || td.
handle.trim(
'!').first_not_of(
"01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-") ==
npos);
1452 bool _create_tag_directive_from_str(csubstr directive_,
TagDirective *td,
Tree *tree)
1454 _RYML_CHECK_BASIC_(tree->
callbacks(), directive_.begins_with(
"%TAG "));
1457 _RYML_ERR_BASIC_(tree->
callbacks(),
"invalid tag directive");
1474 if(_create_tag_directive_from_str(directive_, &td,
this))
1495 if(tag.begins_with(
'!'))
1499 _RYML_ERR_VISIT_(
m_callbacks,
this, node_id,
"tag directive not found");
1506 csubstr _transform_tag(
Tree *t, csubstr tag,
id_type node)
1508 _c4dbgpf(
"[{}] resolving tag ~~~{}~~~", node, tag);
1509 size_t required_size = t->
resolve_tag(substr{}, tag, node);
1512 if(tag.begins_with(
"!<"))
1514 _c4dbgpf(
"[{}] resolved tag: ~~~{}~~~", node, tag);
1517 const char *prev_arena = t->
arena().str;(void)prev_arena;
1519 _RYML_ASSERT_VISIT_(t->
m_callbacks, t->
arena().str == prev_arena, t, node);
1520 size_t actual_size = t->
resolve_tag(buf, tag, node);
1521 _RYML_ASSERT_VISIT_(t->
m_callbacks, actual_size <= required_size, t, node);
1522 _c4dbgpf(
"[{}] resolved tag: ~~~{}~~~", node, buf.first(actual_size));
1523 return buf.first(actual_size);
1525 void _resolve_tags(Tree *t,
id_type node)
1527 NodeData *C4_RESTRICT d = t->_p(node);
1529 d->m_key.tag = _transform_tag(t, d->m_key.tag, node);
1531 d->m_val.tag = _transform_tag(t, d->m_val.tag, node);
1532 for(
id_type child = t->first_child(node); child !=
NONE; child = t->next_sibling(child))
1533 _resolve_tags(t, child);
1535 size_t _count_resolved_tags_size(Tree
const* t,
id_type node)
1538 NodeData
const* C4_RESTRICT d = t->_p(node);
1540 sz += t->resolve_tag(substr{}, d->m_key.tag, node);
1542 sz += t->resolve_tag(substr{}, d->m_val.tag, node);
1543 for(
id_type child = t->first_child(node); child !=
NONE; child = t->next_sibling(child))
1544 sz += _count_resolved_tags_size(t, child);
1547 void _normalize_tags(Tree *t,
id_type node)
1549 NodeData *C4_RESTRICT d = t->_p(node);
1554 for(
id_type child = t->first_child(node); child !=
NONE; child = t->next_sibling(child))
1555 _normalize_tags(t, child);
1557 void _normalize_tags_long(Tree *t,
id_type node)
1559 NodeData *C4_RESTRICT d = t->_p(node);
1564 for(
id_type child = t->first_child(node); child !=
NONE; child = t->next_sibling(child))
1565 _normalize_tags_long(t, child);
1573 size_t needed_size = _count_resolved_tags_size(
this,
root_id());
1576 _resolve_tags(
this,
root_id());
1583 _normalize_tags(
this,
root_id());
1590 _normalize_tags_long(
this,
root_id());
1599 if(p.ends_with(
'.'))
1600 p = p.first(p.len-1);
1606 return path.sub(path_pos);
1631 id_type target = _lookup_path_or_create(path, start);
1635 to_val(target, default_value);
1641 id_type target = _lookup_path_or_create(path, start);
1646 id_type Tree::_lookup_path_or_create(csubstr path,
id_type start)
1650 lookup_result r(path, start);
1657 _lookup_path_modify(&r);
1661 void Tree::_lookup_path(lookup_result *r)
const
1663 C4_ASSERT( ! r->unresolved().empty());
1664 _lookup_path_token
parent{
"",
type(r->closest)};
1668 node = _next_node(r, &
parent);
1671 if(r->unresolved().empty())
1676 }
while(node !=
NONE);
1679 void Tree::_lookup_path_modify(lookup_result *r)
1681 C4_ASSERT( ! r->unresolved().empty());
1682 _lookup_path_token
parent{
"",
type(r->closest)};
1686 node = _next_node_modify(r, &
parent);
1689 if(r->unresolved().empty())
1694 }
while(node !=
NONE);
1697 id_type Tree::_next_node(lookup_result * r, _lookup_path_token *
parent)
const
1699 _lookup_path_token token = _next_token(r, *
parent);
1704 csubstr prev = token.value;
1705 if(token.type ==
MAP || token.type ==
SEQ)
1707 _RYML_ASSERT_VISIT_(
m_callbacks, !token.value.begins_with(
'['),
this, r->closest);
1712 else if(token.type ==
KEYVAL)
1714 _RYML_ASSERT_VISIT_(
m_callbacks, r->unresolved().empty(),
this, r->closest);
1718 else if(token.type ==
KEY)
1720 _RYML_ASSERT_VISIT_(
m_callbacks, token.value.begins_with(
'[') && token.value.ends_with(
']'),
this, r->closest);
1721 token.value = token.value.offs(1, 1).trim(
' ');
1724 node =
child(r->closest, idx);
1737 csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
1738 r->path_pos -= prev.len;
1739 if(p.begins_with(
'.'))
1746 id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *
parent)
1748 _lookup_path_token token = _next_token(r, *
parent);
1753 if(token.type ==
MAP || token.type ==
SEQ)
1755 _RYML_ASSERT_VISIT_(
m_callbacks, !token.value.begins_with(
'['),
this, r->closest);
1773 node =
child(r->closest, pos);
1780 NodeData *n =
_p(node);
1781 n->m_key.scalar = token.value;
1785 else if(token.type ==
KEYVAL)
1787 _RYML_ASSERT_VISIT_(
m_callbacks, r->unresolved().empty(),
this, r->closest);
1797 _add_flags(r->closest,
MAP);
1800 NodeData *n =
_p(node);
1801 n->m_key.scalar = token.value;
1802 n->m_val.scalar =
"";
1805 else if(token.type ==
KEY)
1807 _RYML_ASSERT_VISIT_(
m_callbacks, token.value.begins_with(
'[') && token.value.ends_with(
']'),
this, r->closest);
1808 token.value = token.value.offs(1, 1).trim(
' ');
1816 csubstr k =
key(r->closest);
1817 _clear_type(r->closest);
1822 _clear_type(r->closest);
1827 node =
child(r->closest, idx);
1838 else if(
is_seq(r->closest))
1860 Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token
const&
parent)
const
1862 csubstr unres = r->unresolved();
1867 if(unres.begins_with(
'['))
1869 size_t pos = unres.find(
']');
1872 csubstr idx = unres.first(pos + 1);
1873 _advance(r, pos + 1);
1878 size_t pos = unres.first_of(
".[");
1881 _advance(r, unres.len);
1884 return {unres,
VAL};
1889 _RYML_ASSERT_VISIT_(
m_callbacks, unres[pos] ==
'.' || unres[pos] ==
'[',
this, r->closest);
1890 if(unres[pos] ==
'.')
1892 _RYML_ASSERT_VISIT_(
m_callbacks, pos != 0,
this, r->closest);
1893 _advance(r, pos + 1);
1894 return {unres.first(pos),
MAP};
1897 _RYML_ASSERT_VISIT_(
m_callbacks, unres[pos] ==
'[',
this, r->closest);
1899 return {unres.first(pos),
SEQ};
1922 if(_location_from_node(parser, node, &loc, 0))
1931 csubstr k =
key(node);
1932 if(C4_LIKELY(k.str !=
nullptr))
1934 _RYML_ASSERT_BASIC_(m_callbacks, k.is_sub(parser.
source()));
1935 _RYML_ASSERT_BASIC_(m_callbacks, parser.
source().is_super(k));
1943 csubstr v = val(node);
1944 if(C4_LIKELY(v.str !=
nullptr))
1946 _RYML_ASSERT_BASIC_(m_callbacks, v.is_sub(parser.
source()));
1947 _RYML_ASSERT_BASIC_(m_callbacks, parser.
source().is_super(v));
1953 if(is_container(node))
1955 if(_location_from_cont(parser, node, loc))
1959 if(type(node) !=
NOTYPE && level == 0)
1963 const id_type prev = prev_sibling(node);
1966 if(_location_from_node(parser, prev, loc, level+1))
1972 const id_type next = next_sibling(node);
1975 if(_location_from_node(parser, next, loc, level+1))
1981 const id_type parent = this->parent(node);
1984 if(_location_from_node(parser, parent, loc, level+1))
1992 bool Tree::_location_from_cont(
Parser const& parser,
id_type node, Location *C4_RESTRICT loc)
const
1994 _RYML_ASSERT_BASIC_(m_callbacks, is_container(node));
1995 if(!is_stream(node))
1997 const char *node_start = _p(node)->m_val.scalar.str;
1998 if(has_children(node))
2000 id_type child = first_child(node);
2004 csubstr k =
key(child);
2005 if(k.str && node_start > k.str)
2009 *loc = parser.val_location(node_start);
2014 *loc = parser.val_location(parser.source().str);
2023 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2024 C4_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...
This is the main driver of parsing logic: it scans the YAML or JSON source for tokens,...
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
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
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.
id_type prev_sibling(id_type node) const
NodeData * get(id_type node)
get a pointer to a node's NodeData. i can be NONE, in which case a nullptr is returned
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
bool is_map(id_type node) const
void clear_tag_directives()
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
Tree & operator=(Tree const &that)
void to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags=0)
bool is_root(id_type node) const
substr alloc_arena(size_t sz)
grow the tree's string arena by the given size and return a substr of the added portion
bool is_keyval(id_type node) const
TagDirective m_tag_directives[RYML_MAX_TAG_DIRECTIVES]
void to_doc(id_type node, type_bits more_flags=0)
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
Callbacks const & callbacks() const
size_t resolve_tag(substr output, csubstr tag, id_type node_id) const
resolve the given tag, appearing at node_id.
bool add_tag_directive(csubstr directive)
bool is_val(id_type node) const
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)
void to_stream(id_type node, type_bits more_flags=0)
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
void to_seq(id_type node, csubstr key, type_bits more_flags=0)
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
csubstr const & key(id_type node) const
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 index of a node belonging to this tree. n can be nullptr, in which case NONE is returned
void set_style_conditionally(id_type node, NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
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
bool has_val(id_type node) const
void to_map(id_type node, csubstr key, type_bits more_flags=0)
size_t arena_capacity() const
get the current capacity of the tree's internal arena
bool change_type(id_type node, NodeType type)
change the type of the node to one of MAP, SEQ or VAL.
void normalize_tags_long()
csubstr const & val(id_type node) const
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 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
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)
id_type duplicate_children(id_type node, id_type parent, id_type after)
recursively duplicate the node's children (but not the node)
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
size_t arena_size() const
get the current size of the tree's internal arena
id_type child(id_type node, id_type pos) const
bool has_child(id_type node, id_type ch) const
true if node has a child with id ch
NodeData * _p(id_type node)
An if-less form of get() that demands a valid node index. This function is implementation only; use a...
void to_val(id_type node, csubstr val, type_bits more_flags=0)
bool has_children(id_type node) const
true if node has any children key
#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
@ VAL_STYLE
mask of all the 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 all the scalar styles for key (not container styles!)
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree.
bool is_custom_tag(csubstr tag)
csubstr normalize_tag_long(csubstr tag)
csubstr normalize_tag(csubstr tag)
#define RYML_MAX_TAG_DIRECTIVES
the maximum number of tag directives in a Tree
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...
@ npos
a null string position
csubstr serialize_to_arena(Tree *tree, csubstr a)
size_t to_chars(substr buf, escaped_scalar e)
formatting implementation to escape a scalar with x
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
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 NodeType_e element with some syntactic sugar and predicates
bool has_key() const noexcept
bool is_seq() const noexcept
void rem(NodeType_e t) noexcept
bool is_map() const noexcept
void add(NodeType_e t) noexcept
bool is_val() const noexcept
Reusable object to resolve references/aliases in a Tree.
bool create_from_str(csubstr directive_)
leaves next_node_id unfilled
id_type next_node_id
The next node to which this tag directive applies.
size_t transform(csubstr tag, substr output, Callbacks const &callbacks, bool with_brackets=true) const
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