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_
15 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296)
16 C4_SUPPRESS_WARNING_MSVC(4702)
17 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
18 C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
19 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
31 return serialize_to_arena_scalar<csubstr>(tree, scalar);
35 if(scalar.
str ==
nullptr)
47 return tree->_request_span(0);
58 return NodeRef(
this, root_id());
72 RYML_ASSERT_VISIT_CB_(m_callbacks,
id !=
NONE &&
id >= 0 &&
id < m_cap,
this,
id);
77 RYML_ASSERT_VISIT_CB_(m_callbacks,
id !=
NONE &&
id >= 0 &&
id < m_cap,
this,
id);
82 RYML_ASSERT_VISIT_CB_(m_callbacks,
id !=
NONE &&
id >= 0 &&
id < m_cap,
this,
id);
88 return rootref()[key];
92 return crootref()[key];
101 return crootref()[i];
197 C4_SUPPRESS_WARNING_GCC_PUSH
198 #if defined(__GNUC__) && __GNUC__>= 8
199 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));
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;
242 void 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;
258 void 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);
346 m_tag_directives.clear();
349 void 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;
374 C4_SUPPRESS_WARNING_GCC_POP
391 void Tree::_free_list_add(
id_type i)
394 NodeData &C4_RESTRICT w =
m_buf[i];
398 w.m_prev_sibling =
NONE;
406 void 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;
464 child->m_prev_sibling =
NONE;
465 child->m_next_sibling =
NONE;
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);
497 if(parent->m_first_child ==
NONE)
499 RYML_ASSERT_VISIT_CB_(
m_callbacks, parent->m_last_child ==
NONE,
this, parent->m_last_child);
500 parent->m_first_child =
id(child);
501 parent->m_last_child =
id(child);
505 if(child->m_next_sibling == parent->m_first_child)
506 parent->m_first_child =
id(child);
508 if(child->m_prev_sibling == parent->m_last_child)
509 parent->m_last_child =
id(child);
511 C4_SUPPRESS_WARNING_POP
517 void 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)
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);
777 for(
id_type i = src.m_first_child; i !=
NONE; i = next_sibling(i))
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);
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")
924 id_type ich =
get(node)->m_first_child;
928 RYML_ASSERT_VISIT_CB_(
m_callbacks,
get(ich) !=
nullptr,
this, node);
929 id_type next =
get(ich)->m_next_sibling;
931 if(ich ==
get(node)->m_last_child)
935 C4_SUPPRESS_WARNING_GCC_POP
962 return duplicate(
this, node, parent, after);
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);
1054 RYML_CHECK_VISIT_CB_(
m_callbacks,
this != src || (parent != i && !
is_ancestor(parent, i)),
this, parent);
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)
1094 remove(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);
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();
1410 for(
id_type child = d->m_first_child; child !=
NONE; child = next_sibling(child))
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;
1428 for(
id_type child = d->m_first_child; child !=
NONE; child = next_sibling(child))
1436 return m_tag_directives.size();
1441 m_tag_directives.clear();
1453 m_tag_directives.add(handle, prefix,
id));
1459 m_tag_directives.resolve(output, &reqsz, tag, node_id,
Location{},
callbacks());
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);
1508 size_t _resolve_tags(Tree *t,
id_type node,
id_type doc_id, TagCache &cache,
bool all=
true)
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);
1520 size_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);
1531 void _normalize_tags(Tree *t,
id_type node)
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);
1541 void _normalize_tags_long(Tree *t,
id_type node)
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());
1598 return path.
sub(path_pos);
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);
1650 void 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);
1668 void Tree::_lookup_path_modify(lookup_result *r)
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);
1686 id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent)
const
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(
'.'))
1735 id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
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);
1849 Tree::_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);
1867 size_t pos = unres.first_of(
".[");
1870 _advance(r, unres.len);
1872 if(( ! parent) || parent.type.is_seq())
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)
1930 RYML_ASSERT_BASIC_CB_(m_callbacks, k.
is_sub(parser.
source()));
1940 if C4_LIKELY(v.str !=
nullptr)
1942 RYML_ASSERT_BASIC_CB_(m_callbacks, v.is_sub(parser.
source()));
1951 if(_location_from_cont(parser, node, loc))
1955 if(type(node) !=
NOTYPE && level == 0)
1959 const id_type prev = prev_sibling(node);
1962 if(_location_from_node(parser, prev, loc, level+1))
1968 const id_type next = next_sibling(node);
1971 if(_location_from_node(parser, next, loc, level+1))
1977 const id_type parent = this->parent(node);
1980 if(_location_from_node(parser, parent, loc, level+1))
1988 bool Tree::_location_from_cont(
Parser const& parser,
id_type node, Location *C4_RESTRICT loc)
const
1990 RYML_ASSERT_BASIC_CB_(m_callbacks, type(node).is_container());
1991 if(!type(node).is_stream())
1993 const char *node_start = _p(node)->m_val.scalar.str;
1994 if(has_children(node))
1996 id_type child = first_child(node);
1997 if(type(child).has_key())
2001 if(k.str && node_start > k.str)
2005 *loc = parser.val_location(node_start);
2010 *loc = parser.val_location(parser.source().str);
2020 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2021 C4_SUPPRESS_WARNING_MSVC_POP
csubstr const & key(id_type node) const
csubstr const & val(id_type node) const
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 ...
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_val(id_type node, csubstr val) RYML_NOEXCEPT
bool is_super(ro_substr const that) const noexcept
true if that is a substring of *this (ie, from the same buffer)
bool is_valid_tag_handle(csubstr handle)
bool is_container(id_type node) const
id_type first_child(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...
void add(type_bits t) noexcept
LookupResult find(csubstr tag, id_type doc_id, id_type linear_threshold=Entries::sso_size) const noexcept
csubstr resolved() const
get the part ot the input path that was resolved
Location val_location(const char *val) const
Given a pointer to a buffer position, get the location.
void duplicate_contents(id_type node, id_type where)
void normalize_tags_long()
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 set_map(id_type node) RYML_NOEXCEPT
bool empty() const
Query for zero size.
contains the data for each YAML node.
id_type last_child(id_type node) const
bool is_val() const noexcept
#define RYML_DEFAULT_TREE_CAPACITY
default capacity for the tree when not set explicitly
id_type parent(id_type node) const
bool atox(csubstr s, uint8_t *v) noexcept
C * str
a restricted pointer to the first character of the substring
A c-style callbacks class to customize behavior on errors or allocation.
void merge_with(Tree const *src, id_type src_node=NONE, id_type dst_root=NONE)
bool ends_with(const C c) const noexcept
true if the last character of the string is c
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...
void move(id_type node, id_type after)
change the node's position in the parent
bool is_map() const noexcept
bool is_map(id_type node) const
csubstr arena() const
get the current arena
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags...
bool is_stream() const noexcept
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
TagDirectives m_tag_directives
size_t resolve_tag(substr output, csubstr tag, id_type node_id) const
resolve the given tag, appearing at node_id.
bool has_key(id_type node) const
#define RYML_DEFAULT_TREE_ARENA_CAPACITY
default capacity for the tree's arena when not set explicitly
bool from_chars(csubstr buf, uint8_t *v) noexcept
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 ...
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
csubstr source() const
Get the latest YAML buffer parsed by this object.
bool has_children(id_type node) const
true if node has any children
void reorder()
reorder the tree in memory so that all the nodes are stored in a linear sequence when visited in dept...
bool has_val() const noexcept
bool is_seq() const noexcept
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
id_type append_child(id_type parent)
create and insert a node as the last child of parent
id_type prev_sibling(id_type node) const
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...
void resolve(ReferenceResolver *rr, bool clear_anchors=true)
Resolve references (aliases <- anchors), by forwarding to ReferenceResolver::resolve(); refer to Refe...
id_type num_children(id_type node) const
O(num_children)
csubstr normalize_tag_long(csubstr tag)
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 in_arena(csubstr s) const
return true if the given substring is part of the tree's string arena
bool is_keyval() const noexcept
basic_substring sub(size_t first) const noexcept
return [first,len[
bool is_seq(id_type node) const
void clear_style(id_type node, bool recurse=false)
Callbacks const & callbacks() const
void set_root_as_stream()
ensure the first node is a stream.
csubstr normalize_tag(csubstr tag)
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
NodeType type(id_type node) const
holds a source or yaml file position, for example when an error is detected; See also location_format...
bool has_sibling(id_type node, id_type sib) const
true if node has a sibling with id sib
bool parent_is_map(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
Holds a pointer to an existing tree, and a node id.
the scalar to the left of : in a map's member
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
mask of KEYQUO|KEY_PLAIN : all the key scalar styles for key (not container styles!) ...
id_type next_sibling(id_type node) const
id_type num_tag_directives() const
bool parent_is_seq(id_type node) const
no node type or style is set
size_t len
the length of the substring
id_type child_pos(id_type node, id_type ch) const
void set_style_conditionally(id_type node, NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
void add(csubstr tag, csubstr resolved, id_type doc_id, const_iterator pos) RYML_NOEXCEPT
bool has_key() const noexcept
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...
This is the main driver of parsing logic: it scans the YAML or JSON source for tokens, and emits the appropriate sequence of parsing events to its event handler.
csubstr unresolved() const
get the part ot the input path that was unresolved
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 ...
bool change_type(id_type node, NodeType type)
void remove(id_type node)
remove an entire branch at once: ie remove the children and the node itself
bool empty() const noexcept
Tree & operator=(Tree const &that)
void resolve_tags(TagCache &cache, bool all=true)
Resolve tags in the tree such as "!!str" -> "", "!foo" -> "" and custom ...
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
void remove_children(id_type node)
remove all the node's children, but keep the node itself
Reusable object to resolve references/aliases in a Tree.
bool is_custom_tag(csubstr tag)
is a tag of the form !handle!tag?
size_t find(const C c, size_t start_pos=0) const
void set_key(id_type node, csubstr key) RYML_NOEXCEPT
void rem(type_bits t) noexcept
void clear()
clear the tree and zero every node
bool is_root(id_type node) const
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
bool is_ancestor(id_type node, id_type ancestor) const
true when ancestor is parent or parent of a parent of node
bool is_container() const noexcept
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
bool has_child(id_type node, id_type ch) const
true if node has a child with id ch
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
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 ...
bool begins_with(const C c) const noexcept
true if the first character of the string is c
mask of VALQUO|VAL_PLAIN : all the val scalar styles for val (not container styles!) ...
mask of SCALAR_STYLE | CONTAINER_STYLE : all style flags
a seq: a parent of VAL/SEQ/MAP nodes
void set_seq(id_type node) RYML_NOEXCEPT
void clear_tag_directives()
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 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(), but return a ReadResult with the status
Location location(Parser const &p, id_type node) const
Get the location of a node from the parse used to parse this tree.
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...
bool is_sub(ro_substr const that) const noexcept
true if *this is a substring of that (ie, from the same buffer)
lookup_result lookup_path(csubstr path, id_type start=NONE) const
for example foo.bar[0].baz