1#ifndef C4_YML_TREE_HPP_
2#define C4_YML_TREE_HPP_
9#ifndef C4_LANGUAGE_HPP_
10#include "c4/language.hpp"
12#ifndef C4_YML_FWD_HPP_
15#ifndef C4_YML_COMMON_HPP_
18#ifndef C4_YML_NODE_TYPE_HPP_
21#ifndef C4_YML_TAG_HPP_
24#ifndef C4_YML_ERROR_HPP_
27#ifndef C4_YML_SCALAR_CHARCONV_HPP_
35C4_SUPPRESS_WARNING_PUSH
36C4_SUPPRESS_WARNING_GCC(
"-Wtype-limits")
37C4_SUPPRESS_WARNING_GCC(
"-Wuseless-cast")
38C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wold-style-cast")
39#if defined(__GNUC__) && (__GNUC__ >= 6)
40C4_SUPPRESS_WARNING_GCC(
"-Wnull-dereference")
42C4_SUPPRESS_WARNING_CLANG(
"-Wnull-dereference")
43C4_SUPPRESS_WARNING_CLANG(
"-Wtautological-compare")
44C4_SUPPRESS_WARNING_MSVC(4127)
45C4_SUPPRESS_WARNING_MSVC(4296)
46C4_SUPPRESS_WARNING_MSVC(4251)
56using _is_string_nocvref = is_string<typename detail::_remove_cvref<T>::type>;
83#if (C4_CPP >= 17) || defined(__DOXYGEN__)
111 if constexpr (_is_string_nocvref<T>::value)
120C4_ALWAYS_INLINE
auto serialize_to_arena(Tree * tree, T
const& scalar)
121 ->
typename std::enable_if<_is_string_nocvref<T>::value,
csubstr>::type
123 return serialize_to_arena_str(tree,
to_csubstr(scalar));
127C4_ALWAYS_INLINE
auto serialize_to_arena(Tree * tree, T
const& scalar)
128 ->
typename std::enable_if< ! _is_string_nocvref<T>::value, csubstr>::type
130 return serialize_to_arena_scalar<T>(tree, scalar);
149template<
class T>
void write(Tree * tree, id_type
id, T
const& v);
150template<
class T>
void write_key(Tree *, id_type
id, T
const& v);
152template<
class T> C4_NODISCARD C4_ALWAYS_INLINE ReadResult
read(Tree
const* tree, id_type
id, T * v);
153template<
class T> C4_NODISCARD C4_ALWAYS_INLINE ReadResult read_key(Tree
const* tree, id_type
id, T * v);
154template<
class Wrapper> C4_NODISCARD C4_ALWAYS_INLINE ReadResult
read(Tree
const* tree, id_type
id, Wrapper
const& w);
155template<
class Wrapper> C4_NODISCARD C4_ALWAYS_INLINE ReadResult read_key(Tree
const* tree, id_type
id, Wrapper
const& w);
186 template<
size_t N,
size_t M>
206 csubstr trimmed = ref.begins_with(
'*') ? ref.sub(1) : ref;
208 if((!has_scalar) || !
scalar.ends_with(trimmed))
212static_assert(std::is_trivially_copyable<NodeScalar>::value,
"must be trivially copyable");
220struct RYML_DEPRECATED(
"") NodeInit
230 NodeInit() : type(NOTYPE), key(), val() {}
232 NodeInit(type_bits t) : type(t), key(), val() {}
234 NodeInit(NodeScalar
const& v) : type(
VAL), key(), val(v) { _add_flags(); }
236 NodeInit(NodeScalar
const& v, type_bits t) : type(t|
VAL), key(), val(v) { _add_flags(); }
238 NodeInit( NodeScalar
const& k, NodeScalar
const& v) : type(
KEYVAL), key(k), val(v) { _add_flags(); }
240 NodeInit(type_bits t, NodeScalar
const& k, NodeScalar
const& v) : type(t), key(k), val(v) { _add_flags(); }
242 NodeInit(type_bits t, NodeScalar
const& k ) : type(t), key(k), val( ) { _add_flags(KEY); }
253 void _add_flags(type_bits more_flags=0)
255 type = (type.m_bits|more_flags);
256 if( ! key.tag.empty())
257 type = (type.m_bits|
KEYTAG);
258 if( ! val.tag.empty())
259 type = (type.m_bits|
VALTAG);
260 if( ! key.anchor.empty())
262 if( ! val.anchor.empty())
269 RYML_ASSERT_BASIC_(key.scalar.empty() == ((type & KEY) == 0));
271 RYML_ASSERT_BASIC_(key.tag.empty() == ((type & KEYTAG) == 0));
273 RYML_ASSERT_BASIC_(((type & VAL) != 0) || val.scalar.empty());
275 RYML_ASSERT_BASIC_(val.tag.empty() == ((type & VALTAG) == 0));
300static_assert(std::is_trivially_copyable<NodeData>::value,
"must be trivially copyable");
325 Tree& operator= (
Tree && that) noexcept;
478 C4_ALWAYS_INLINE
bool is_doc(
id_type node)
const {
return _p(node)->m_type.is_doc(); }
480 C4_ALWAYS_INLINE
bool is_map(
id_type node)
const {
return _p(node)->m_type.is_map(); }
481 C4_ALWAYS_INLINE
bool is_seq(
id_type node)
const {
return _p(node)->m_type.is_seq(); }
484 C4_ALWAYS_INLINE
bool is_val(
id_type node)
const {
return _p(node)->m_type.is_val(); }
493 C4_ALWAYS_INLINE
bool is_ref(
id_type node)
const {
return _p(node)->m_type.is_ref(); }
517 RYML_DEPRECATED(
"use has_key_anchor()") bool
is_key_anchor(
id_type node)
const {
return _p(node)->m_type.has_key_anchor(); }
518 RYML_DEPRECATED(
"use has_val_anchor()") bool
is_val_anchor(
id_type node)
const {
return _p(node)->m_type.has_val_anchor(); }
519 RYML_DEPRECATED(
"use has_anchor()") bool
is_anchor(
id_type node)
const {
return _p(node)->m_type.has_anchor(); }
520 RYML_DEPRECATED(
"use has_anchor_or_ref()") bool
is_anchor_or_ref(
id_type node)
const {
return _p(node)->m_type.has_anchor() ||
_p(node)->m_type.is_ref(); }
631 RYML_DEPRECATED(
"use one of .is_flow_ml{1,n,x}()")
662 void clear_style(
id_type node,
bool recurse=
false);
663 void set_style_conditionally(
id_type node,
685 _p(node)->m_type |=
DOC;
694 nd->m_val.scalar =
val;
701 nd->m_type |=
VAL|more_flags;
702 nd->m_val.scalar =
val;
710 nd->m_key.scalar =
key;
716 nd->m_type |=
KEY|more_flags;
717 nd->m_key.scalar =
key;
723 _p(node)->m_type |=
SEQ;
727 RYML_ASSERT_VISIT_CB_(
m_callbacks, ((
_p(node)->m_type|more_flags) & (
VAL|
MAP)) == 0,
this, node);
728 _p(node)->m_type |=
SEQ|more_flags;
734 _p(node)->m_type |=
MAP;
738 RYML_ASSERT_VISIT_CB_(
m_callbacks, ((
_p(node)->m_type|more_flags) & (
VAL|
SEQ)) == 0,
this, node);
739 _p(node)->m_type |=
MAP|more_flags;
760 C4_NORETURN C4_NO_INLINE C4_COLD
761 void err_visit_(
id_type node)
const
763 RYML_ERR_VISIT_CB_(m_callbacks,
this, node,
"invalid node");
774 if C4_LIKELY(node !=
NONE && node < m_cap && node >= 0)
784 if C4_LIKELY(node !=
NONE && node < m_cap && node >= 0)
787 _p(node)->m_type |= more_flags;
796 if C4_LIKELY(node !=
NONE && node < m_cap && node >= 0)
806 if C4_LIKELY(node !=
NONE && node < m_cap && node >= 0)
809 _p(node)->m_type |= more_flags;
833 _p(node)->m_type |= more_flags;
847 _p(node)->m_type |= more_flags;
871 C4_ALWAYS_INLINE
void load(
id_type node, T * v,
bool check_readable=
true)
const
873 const bool can_read_val = (node !=
NONE && node < m_cap && node >= 0 && (
_p(node)->m_type & (
VAL|
MAP|
SEQ)));
874 RYML_ASSERT_VISIT_CB_(
m_callbacks, can_read_val,
this, node);
875 if C4_LIKELY(!check_readable || can_read_val)
887 template<
class Wrapper>
888 C4_ALWAYS_INLINE
void load(
id_type node, Wrapper
const& w,
bool check_readable=
true)
const
890 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
891 const bool can_read_val = (node !=
NONE && node < m_cap && node >= 0 && (
_p(node)->m_type & (
VAL|
MAP|
SEQ)));
892 RYML_ASSERT_VISIT_CB_(
m_callbacks, can_read_val,
this, node);
893 if C4_LIKELY(!check_readable || can_read_val)
914 const bool can_read_key = (node !=
NONE && node < m_cap && node >= 0 && (
_p(node)->m_type &
KEY));
915 RYML_ASSERT_VISIT_CB_(
m_callbacks, can_read_key,
this, node);
916 if C4_LIKELY(!check_readable || can_read_key)
928 template<
class Wrapper>
929 C4_ALWAYS_INLINE
void load_key(
id_type node, Wrapper
const& w,
bool check_readable=
true)
const
931 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
932 bool can_read_key = (node !=
NONE && node < m_cap && node >= 0 && (
_p(node)->m_type &
KEY));
933 RYML_ASSERT_VISIT_CB_(
m_callbacks, can_read_key,
this, node);
934 if C4_LIKELY(!check_readable || can_read_key)
963 template<
class Wrapper>
966 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
984 template<
class Wrapper>
987 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
1030 template<
class Wrapper>
1072 template<
class Wrapper>
1112 void resolve(
bool clear_anchors=
true);
1133 void resolve_tags(
TagCache &cache,
bool all=
true);
1134 void normalize_tags();
1135 void normalize_tags_long();
1137 id_type num_tag_directives()
const;
1139 void clear_tag_directives();
1147 size_t needed =
resolve_tag(output, tag, node_id);
1148 return needed <= output.
len ? output.
first(needed) : output;
1154 RYML_DEPRECATED(
"use c4::yml::tag_directive_const_iterator") typedef
TagDirective const* tag_directive_const_iterator;
1209 void remove_children(
id_type node);
1244 void set_root_as_stream();
1376 C4_SUPPRESS_WARNING_GCC_PUSH
1377 #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10)
1378 C4_SUPPRESS_WARNING_GCC(
"-Wstringop-overflow=")
1379 C4_SUPPRESS_WARNING_GCC(
"-Wrestrict")
1383 C4_SUPPRESS_WARNING_GCC_POP
1401 substr s = _request_span(sz);
1415 buf.
len = arena_cap;
1432 substr _grow_arena(
size_t more)
1434 size_t cap = m_arena.len + more;
1436 cap = cap < 2 * m_arena.len ? 2 * m_arena.len : cap;
1438 return m_arena.sub(m_arena_pos);
1441 substr _request_span(
size_t sz)
1443 RYML_ASSERT_VISIT_CB_(m_callbacks, m_arena_pos + sz <= m_arena.len,
this, NONE);
1445 s = m_arena.
sub(m_arena_pos, sz);
1450 substr _relocated(csubstr s, substr next_arena)
const
1452 RYML_ASSERT_VISIT_CB_(m_callbacks, m_arena.is_super(s) || s.len == 0,
this, NONE);
1453 RYML_ASSERT_VISIT_CB_(m_callbacks, m_arena.sub(0, m_arena_pos).is_super(s) || s.len == 0,
this, NONE);
1454 auto pos = (s.str - m_arena.str);
1455 substr r(next_arena.str + pos, s.len);
1456 RYML_ASSERT_VISIT_CB_(m_callbacks, r.str - next_arena.str == pos,
this, NONE);
1457 RYML_ASSERT_VISIT_CB_(m_callbacks, next_arena.sub(0, m_arena_pos).is_super(r) || r.len == 0,
this, NONE);
1505 struct _lookup_path_token
1509 _lookup_path_token() : value(), type() {}
1510 _lookup_path_token(
csubstr v, NodeType t) : value(v), type(t) {}
1511 operator bool()
const {
return type != NOTYPE; }
1515 id_type _lookup_path_or_create(csubstr path, id_type start);
1517 void _lookup_path (lookup_result *r)
const;
1518 void _lookup_path_modify(lookup_result *r);
1520 id_type _next_node (lookup_result *r, _lookup_path_token *parent)
const;
1521 id_type _next_node_modify(lookup_result *r, _lookup_path_token *parent);
1523 static void _advance(lookup_result *r,
size_t more);
1525 _lookup_path_token _next_token(lookup_result *r, _lookup_path_token
const& parent)
const;
1531 void _copy(Tree
const& that);
1532 void _move(Tree & that)
noexcept;
1534 void _relocate(substr next_arena);
1540 #if ! RYML_USE_ASSERT
1541 C4_ALWAYS_INLINE
void _check_next_flags(id_type, type_bits) {}
1543 void _check_next_flags(id_type node, type_bits f)
1545 NodeData *n = _p(node);
1550 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (f & SEQ) == 0,
this, node,
"cannot mark simultaneously as map and seq");
1551 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (f & VAL) == 0,
this, node,
"cannot mark simultaneously as map and val");
1552 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (o & SEQ) == 0,
this, node,
"cannot turn a seq into a map; clear first");
1553 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (o & VAL) == 0,
this, node,
"cannot turn a val into a map; clear first");
1557 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (f & MAP) == 0,
this, node,
"cannot mark simultaneously as seq and map");
1558 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (f & VAL) == 0,
this, node,
"cannot mark simultaneously as seq and val");
1559 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (o & MAP) == 0,
this, node,
"cannot turn a map into a seq; clear first");
1560 RYML_ASSERT_VISIT_MSG_CB_(m_callbacks, (o & VAL) == 0,
this, node,
"cannot turn a val into a seq; clear first");
1564 RYML_ASSERT_VISIT_CB_(m_callbacks, !is_root(node),
this, node);
1565 RYML_ASSERT_VISIT_CB_(m_callbacks, is_map(parent(node)),
this, node);
1567 if((f & VAL) && !is_root(node))
1569 auto pid = parent(node); C4_UNUSED(pid);
1570 RYML_ASSERT_VISIT_CB_(m_callbacks, is_map(pid) || is_seq(pid),
this, node);
1575 void _add_flags(id_type node, type_bits f) { NodeData *d = _p(node);
type_bits fb = f | d->m_type; _check_next_flags(node, fb); d->m_type = fb; }
1576 void _rem_flags(id_type node, type_bits f) { NodeData *d = _p(node);
type_bits fb = d->m_type & ~f; _check_next_flags(node, fb); d->m_type = fb; }
1578 id_type _do_reorder(id_type *node, id_type count);
1580 void _swap(id_type n_, id_type m_);
1581 void _swap_props(id_type n_, id_type m_);
1582 void _swap_hierarchy(id_type n_, id_type m_);
1583 void _copy_hierarchy(id_type dst_, id_type src_);
1585 void _copy_props(id_type dst_, id_type src_)
1587 _copy_props(dst_,
this, src_);
1590 void _copy_props_wo_key(id_type dst_, id_type src_)
1592 _copy_props_wo_key(dst_,
this, src_);
1595 void _copy_props(id_type dst_, Tree
const* that_tree, id_type src_)
1597 NodeData & C4_RESTRICT dst = *_p(dst_);
1598 NodeData
const& C4_RESTRICT src = *that_tree->_p(src_);
1599 dst.m_type = src.m_type;
1600 dst.m_key = src.m_key;
1601 dst.m_val = src.m_val;
1604 void _copy_props(id_type dst_, Tree
const* that_tree, id_type src_, type_bits src_mask)
1606 NodeData & C4_RESTRICT dst = *_p(dst_);
1607 NodeData
const& C4_RESTRICT src = *that_tree->_p(src_);
1608 dst.m_type = (src.m_type & src_mask) | (dst.m_type & ~src_mask);
1609 dst.m_key = src.m_key;
1610 dst.m_val = src.m_val;
1613 void _copy_props_wo_key(id_type dst_, Tree
const* that_tree, id_type src_)
1615 auto & C4_RESTRICT dst = *_p(dst_);
1616 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1617 dst.m_type = (src.m_type & ~KEYMASK_) | (dst.m_type & KEYMASK_);
1618 dst.m_val = src.m_val;
1621 void _copy_props_wo_key(id_type dst_, Tree
const* that_tree, id_type src_, type_bits src_mask)
1623 auto & C4_RESTRICT dst = *_p(dst_);
1624 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1625 dst.m_type = (src.m_type & ((~KEYMASK_)|src_mask)) | (dst.m_type & (KEYMASK_|~src_mask));
1626 dst.m_val = src.m_val;
1629 void _clear_type(id_type node)
1631 _p(node)->m_type =
NOTYPE;
1634 void _clear(id_type node)
1636 auto *C4_RESTRICT n = _p(node);
1641 n->m_first_child =
NONE;
1642 n->m_last_child =
NONE;
1645 void _clear_key(id_type node)
1647 _p(node)->m_key.clear();
1648 _rem_flags(node, KEY);
1651 void _clear_val(id_type node)
1653 _p(node)->m_val.clear();
1654 _rem_flags(node, VAL);
1661 void _clear_range(id_type first, id_type num);
1665 void _release(id_type node);
1666 void _free_list_add(id_type node);
1667 void _free_list_rem(id_type node);
1669 void _set_hierarchy(id_type node, id_type parent, id_type after_sibling);
1670 void _rem_hierarchy(id_type node);
1693 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
1694 C4_SUPPRESS_WARNING_MSVC_PUSH
1695 C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wdeprecated")
1696 C4_SUPPRESS_WARNING_GCC_CLANG(
"-Wdeprecated-declarations")
1697 C4_SUPPRESS_WARNING_MSVC(4996)
1698 RYML_DEPRECATED(
"use .type().type_str(buf)") const
char* type_str(
id_type node)
const {
return NodeType::type_str(
_p(node)->m_type); }
1699 RYML_DEPRECATED(
"use has_other_siblings()") static
bool has_siblings(
id_type ) {
return true; }
1700 RYML_DEPRECATED(
"use set_key()+set_val()") void to_keyval(id_type node,
csubstr key,
csubstr val, type_bits more_flags=0);
1701 RYML_DEPRECATED(
"use set_key()+set_map()")
void to_map(id_type node,
csubstr key, type_bits more_flags=0);
1702 RYML_DEPRECATED(
"use set_key()+set_seq()")
void to_seq(id_type node,
csubstr key, type_bits more_flags=0);
1703 RYML_DEPRECATED(
"use set_val()")
void to_val(id_type node,
csubstr val, type_bits more_flags=0);
1704 RYML_DEPRECATED(
"use set_map()")
void to_map(id_type node, type_bits more_flags=0);
1705 RYML_DEPRECATED(
"use set_seq()")
void to_seq(id_type node, type_bits more_flags=0);
1706 RYML_DEPRECATED(
"use set_doc()")
void to_doc(id_type node, type_bits more_flags=0);
1707 RYML_DEPRECATED(
"use set_stream()")
void to_stream(id_type node, type_bits more_flags=0);
1708 RYML_DEPRECATED(
"use resolve_tags(TagCache&)")
void resolve_tags() { TagCache cache; resolve_tags(cache); }
1709 RYML_DEPRECATED(
"") void _set(id_type node, NodeInit const& i)
1711 RYML_ASSERT_VISIT_CB_(m_callbacks, i._check(),
this, node);
1712 NodeData *n = _p(node);
1713 RYML_ASSERT_VISIT_CB_(m_callbacks, n->m_key.scalar.empty() || i.key.scalar.empty() || i.key.scalar == n->m_key.scalar,
this, node);
1714 _add_flags(node, i.type);
1715 if(n->m_key.scalar.empty())
1717 if( ! i.key.scalar.empty())
1719 set_key(node, i.key.scalar);
1722 n->m_key.tag = i.key.tag;
1725 RYML_DEPRECATED(
"") void _set_key(id_type node, NodeScalar const& key, NodeType more_flags=0)
1727 _p(node)->m_key = key;
1728 _add_flags(node, KEY|more_flags);
1730 RYML_DEPRECATED(
"") void _set_val(id_type node, NodeScalar const& val, NodeType more_flags=0)
1732 _p(node)->m_val = val;
1733 _add_flags(node, VAL|more_flags);
1735 C4_SUPPRESS_WARNING_MSVC_POP
1736 C4_SUPPRESS_WARNING_GCC_CLANG_POP
1759 if C4_LIKELY(num <= buf.
len)
1761 buf = buf.
first(num);
1765 buf = tree->_grow_arena(num);
1780#if (C4_CPP >= 17) || defined(__DOXYGEN__)
1787 if constexpr (std::is_arithmetic_v<T>)
1797 if constexpr (std::is_arithmetic_v<T>)
1806C4_ALWAYS_INLINE
auto scalar_flags_val(T
const&)
noexcept
1807 ->
typename std::enable_if<std::is_arithmetic<T>::value, type_bits>::type
1812C4_ALWAYS_INLINE
auto scalar_flags_key(T
const&)
noexcept
1813 ->
typename std::enable_if<std::is_arithmetic<T>::value, type_bits>::type
1820 ->
typename std::enable_if< ! std::is_arithmetic<T>::value,
type_bits>::type
1826 ->
typename std::enable_if< ! std::is_arithmetic<T>::value,
type_bits>::type
1876 NodeData const* C4_RESTRICT nd = tree->
_p(
id);
1881template<
class Wrapper>
1887 NodeData const* C4_RESTRICT nd = tree->
_p(
id);
1905template<
class Wrapper>
1921C4_SUPPRESS_WARNING_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...
id_type num_other_siblings(id_type node) const
does not count with this
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_val_style(id_type node, type_bits style)
bool has_sibling(id_type node, csubstr key) const
true if one of the node's siblings has the given key
csubstr resolve_tag_sub(substr output, csubstr tag, id_type node_id) const
Wrapper for Tree::resolve_tag(), returning a substring.
csubstr const & key_ref(id_type node) const
csubstr const & key(id_type node) const
bool is_key_plain(id_type node) const
id_type num_siblings(id_type node) const
O(num_siblings).
id_type first_child(id_type node) const
bool is_stream(id_type node) const
void save_key(id_type node, T const &key, NodeType more_flags)
NodeType type(id_type node) const
id_type append_sibling(id_type node)
void set_val_ref(id_type node, csubstr ref)
csubstr const & val_ref(id_type node) const
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 ...
size_t arena_slack() const
get the current slack of the tree's internal arena
bool has_key_tag(id_type node) const
void save(id_type node, T const &val)
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
id_type prepend_sibling(id_type node)
create and insert a node as the first node of parent
void set_val(id_type node, csubstr val) RYML_NOEXCEPT
ReadResult deserialize_key(id_type node, Wrapper const &w) const
(2) like (1), but for a wrapper type like those used in tag functions
bool is_map(id_type node) const
NodeData const * _p(id_type node) const
An if-less form of get() that demands a valid node index. This function is implementation only; use a...
void set_serialized(id_type node, T const &val) RYML_NOEXCEPT
void callbacks(Callbacks const &cb)
bool is_val_anchor(id_type node) const
void set_key_serialized(id_type node, T const &key) RYML_NOEXCEPT
ReadResult deserialize_child(id_type node, csubstr child_key, T *v, T const &fallback) const
(2) like (1), but assign from fallback if no such child exists.
id_type sibling(id_type node, id_type pos) const
void set_key_serialized(id_type node, T const &key, NodeType more_flags) RYML_NOEXCEPT
void load(id_type node, T *v, bool check_readable=true) const
(1) deserialize the node's contents (val or container) to the given variable, forwarding to the user-...
NodeScalar const & keysc(id_type node) const
c4::yml::TagDirectiveRange tag_directives() const
bool is_key_quoted(id_type node) const
csubstr const & val(id_type node) const
bool has_val_anchor(id_type node) const
id_type insert_child(id_type parent, id_type after)
create and insert a new child of parent.
TagDirectives m_tag_directives
bool is_root(id_type node) const
bool key_is_null(id_type node) const
true if the node key is empty, or its scalar verifies scalar_is_null().
NodeRef ref(id_type node)
Get a NodeRef of a node by id.
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
bool is_val_folded(id_type node) const
void set_key(id_type node, csubstr key, NodeType more_flags) RYML_NOEXCEPT
void set_serialized(id_type node, T const &val, NodeType more_flags) RYML_NOEXCEPT
id_type last_sibling(id_type node) const
static ReadResult to_result_(ReadResult notlegacy, id_type) noexcept
bool has_key(id_type node) const
bool has_other_siblings(id_type node) const
true if node is not a single child
csubstr const & val_tag(id_type node) const
bool in_arena(csubstr s) const
return true if the given substring is part of the tree's string arena
ReadResult deserialize_child(id_type node, id_type child_pos, Wrapper const &wrapper) const
(3) like (1), but for wrapper tag types such as c4::fmt::base64()
id_type parent(id_type node) const
bool is_key_unfiltered(id_type node) const
true if the key was a scalar requiring filtering and was left unfiltered during the parsing (see Pars...
void rem_key_anchor(id_type node)
size_t resolve_tag(substr output, csubstr tag, id_type node_id) const
resolve the given tag, appearing at node_id.
bool is_key_literal(id_type node) const
NodeType key_style(id_type node) const
bool is_block(id_type node) const
id_type prepend_child(id_type parent)
create and insert a node as the first child of parent
bool is_val(id_type node) const
bool is_container_styled(id_type node) const
bool empty() const
Query for zero size.
ReadResult find_sibling_r(id_type node, csubstr const &key, id_type *sibling_id) const
like Tree::find_sibling(), but return a ReadResult if with the status
void load_key(id_type node, T *k, bool check_readable=true) const
(1) deserialize the node's key (necessarily a scalar) to the given variable, forwarding to the user-o...
void set_seq(id_type node) RYML_NOEXCEPT
void set_stream(id_type node)
id_type sibling_pos(id_type node, id_type sib) 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
ReadResult find_child_r(id_type node, csubstr const &key, id_type *child_id) const
like Tree::find_child(), but return a ReadResult with the status
bool has_sibling(id_type node, id_type sib) const
true if node has a sibling with id sib
ReadResult deserialize(id_type node, T *v) const
(1) deserialize a node's contents to a variable
id_type next_sibling(id_type node) const
bool is_flow_mln(id_type node) const
bool is_key_squo(id_type node) const
bool parent_is_seq(id_type node) const
void save_key(id_type node, T const &key)
bool has_anchor(id_type node) const
id_type insert_sibling(id_type node, id_type after)
create and insert a new sibling of n. insert after "after"
bool has_val_tag(id_type node) const
NodeData const * get(id_type node) const
get a pointer to a node's NodeData. node can be NONE, in which case a nullptr is returned.
ReadResult sibling_r(id_type node, id_type pos, id_type *sibling_id) const
like Tree::sibling(), but return a ReadResult with the status
bool is_flow_ml1(id_type node) const
bool is_key_dquo(id_type node) const
void set_key_tag(id_type node, csubstr tag)
void set_container_style(id_type node, type_bits style)
void rem_anchor_ref(id_type node)
id_type last_child(id_type node) const
csubstr const & key_tag(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 ...
bool type_has_any(id_type node, type_bits bits) const
substr arena_rem()
get the free space at the end of the arena
void set_map(id_type node, NodeType more_flags) RYML_NOEXCEPT
csubstr to_arena(T const &a)
serialize the given variable to the tree's arena, growing it as needed to accomodate the serializatio...
void set_val_anchor(id_type node, csubstr anchor)
bool is_val_plain(id_type node) const
bool is_doc(id_type node) const
bool has_child(id_type node, csubstr key) const
true if node has a child with key key
void set_val(id_type node, csubstr val, NodeType more_flags) RYML_NOEXCEPT
ReadResult deserialize(id_type node, Wrapper const &w) const
(2) like (1), but for a wrapper type like those used in tag functions
ReadResult deserialize_child(id_type node, id_type child_pos, T *v, T const &fallback) const
(2) like (1), but assign from fallback if no such child exists
void set_seq(id_type node, NodeType more_flags) RYML_NOEXCEPT
id_type root_id_maybe() const
Get the id of the root node, or NONE if the tree is empty.
bool is_key_ref(id_type node) const
bool is_key_anchor(id_type node) const
void remove_children(id_type node)
remove all the node's children, but keep the node itself
bool type_has_all(id_type node, type_bits bits) const
bool has_val(id_type node) const
bool is_val_dquo(id_type node) const
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)
bool is_flow_ml(id_type node) const
NodeType val_style(id_type node) const
bool is_key_folded(id_type node) const
csubstr arena_rem() const
get the free space at the end of the arena
Tree(id_type node_capacity, size_t arena_capacity=RYML_DEFAULT_TREE_ARENA_CAPACITY)
bool is_anchor_or_ref(id_type node) const
bool is_anchor(id_type node) const
id_type find_sibling(id_type node, csubstr const &key) const
bool is_seq(id_type node) const
bool is_val_styled(id_type node) const
bool parent_is_map(id_type node) const
void set_map(id_type node) RYML_NOEXCEPT
bool has_key_anchor(id_type node) const
void remove(id_type node)
remove an entire branch at once: ie remove the children and the node itself
ReadResult deserialize_key(id_type node, T *v) const
(1) deserialize a node's key to a variable
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(),...
void save(id_type node, T const &val, NodeType more_flags)
bool type_has_none(id_type node, type_bits bits) const
bool is_quoted(id_type node) const
csubstr const & val_anchor(id_type node) const
bool change_type(id_type node, type_bits type)
NodeData * get(id_type node)
get a pointer to a node's NodeData. node can be NONE, in which case a nullptr is returned
substr arena()
get the current arena
void rem_val_ref(id_type node)
bool has_parent(id_type node) const
bool val_is_null(id_type node) const
true if the node val is empty, or its scalar verifies scalar_is_null().
id_type first_sibling(id_type node) const
void set_key_style(id_type node, type_bits style)
bool is_flow(id_type node) const
bool is_val_quoted(id_type node) const
bool empty(id_type node) const
true when key and val are empty, and has no children
csubstr const & key_anchor(id_type node) const
bool is_val_squo(id_type node) const
substr copy_to_arena(csubstr s)
copy the given string to the tree's arena, growing the arena by the required size.
ReadResult deserialize_child(id_type node, csubstr child_key, Wrapper const &wrapper) const
(3) like (1), but for wrapper tag types such as c4::fmt::base64()
void set_key(id_type node, csubstr key) RYML_NOEXCEPT
bool has_flow_space(id_type node) const
id_type num_children(id_type node) const
O(num_children).
csubstr arena() const
get the current arena
bool is_container(id_type node) const
void set_doc(id_type node)
bool is_flow_mlx(id_type node) const
ReadResult deserialize_child(id_type node, id_type child_pos, T *v) const
(1) find a child by position and deserialize its contents to the given variable (ie call ....
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
find child by position, or NONE if there are less than pos children posi
bool is_ref(id_type node) const
void set_val_tag(id_type node, csubstr tag)
bool is_key_styled(id_type node) const
void set_key_anchor(id_type node, csubstr anchor)
bool is_val_ref(id_type node) const
void set_key_ref(id_type node, csubstr ref)
void load(id_type node, Wrapper const &w, bool check_readable=true) const
(2) like (1), but for wrapper tag types such as c4::fmt::base64()
id_type _append_child__unprotected(id_type parent)
bool has_child(id_type node, id_type ch) const
true if node has a child with id ch
bool is_val_literal(id_type node) const
void rem_val_anchor(id_type node)
NodeScalar const & valsc(id_type node) const
bool is_val_unfiltered(id_type node) const
true if the val was a scalar requiring filtering and was left unfiltered during the parsing (see Pars...
ReadResult deserialize_child(id_type node, csubstr child_key, T *v) const
(1) find a child by name and deserialize its contents to the given variable (ie call ....
void load_key(id_type node, Wrapper const &w, bool check_readable=true) const
(2) like (1), but for wrapper tag types such as c4::fmt::base64()
void rem_key_ref(id_type node)
ReadResult child_r(id_type node, id_type pos, id_type *child_id) const
bool is_flow_sl(id_type node) const
id_type ancestor_doc(id_type node) const
get the document which is a parent document of node i, or the root if the tree is not a stream
bool has_children(id_type node) const
true if node has any children
static ReadResult to_result_(bool, id_type node) noexcept
bool has_anchor(id_type node, csubstr a) const
true when the node has an anchor named a
Common utilities and infrastructure used by ryml.
#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
#define RYML_DEFAULT_TREE_ARENA_CAPACITY_START
default starting capacity for the tree's arena when it is first allocated. should be larger than RYML...
#define RYML_NOEXCEPT
Conditionally expands to noexcept when RYML_USE_ASSERT is 0 and is empty otherwise.
Error utilities used by ryml.
Callbacks const & get_callbacks()
get the global callbacks
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
@ VALANCH
the val has an &anchor
@ NOTYPE
no node type or style is set
@ VALREF
a *reference: the val references an &anchor
@ 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
@ 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
@ VAL_PLAIN
mark val scalar as plain scalar (unquoted, even when multiline)
@ KEYREF
a *reference: the key references an &anchor
@ KEYANCH
the key has an &anchor
@ KEY_PLAIN
mark key scalar as plain scalar (unquoted, even when multiline)
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree (see Event Ha...
ryml::ReadResult read(ryml::Tree const *tree, ryml::id_type id, my_seq_type< T > *seq)
void write(ryml::Tree *tree, ryml::id_type id, my_seq_type< T > const &seq)
bool from_chars(ryml::csubstr buf, vec2< T > *v)
size_t scalar_serialize(substr buf, T const &a)
Serialize a scalar to the buffer, dispatching to to_chars() or to_chars_float() as appropriate.
bool scalar_is_null(csubstr s) noexcept
YAML-sense query of nullity.
bool scalar_deserialize(csubstr str, T *val)
Deserialize a scalar from its string representation, dispatching to one of from_chars(),...
ReadResult read_key(ConstNodeRef const &n, T *v)
void write_key(NodeRef *n, T const &v)
csubstr serialize_to_arena(Tree *tree, T const &scalar)
Serialize a scalar to a tree's arena, dispatching to either serialize_to_arena_scalar() or serialize_...
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.
type_bits scalar_flags_val(T const &) noexcept
Return extra style flags to use when setting a scalar as val.
type_bits scalar_flags_key(T const &) noexcept
Return extra style flags to use when setting a scalar as key.
csubstr to_csubstr(const char(&s)[N]) noexcept
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
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
basic_substring triml(const C c) const
trim left
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
bool overlaps(ro_substr const that) const noexcept
true if there is overlap of at least one element between that and *this
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[
C * str
a restricted pointer to the first character of the substring
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.
a node scalar is a csubstr, which may be tagged and anchored.
NodeScalar(const char(&t)[N], const char(&s)[N]) noexcept
initialize as a tagged scalar
bool empty() const noexcept
NodeScalar() noexcept
initialize as an empty scalar
NodeScalar(csubstr s) noexcept
NodeScalar(csubstr t, csubstr s) noexcept
NodeScalar(const char(&s)[N]) noexcept
initialize as an untagged scalar
~NodeScalar() noexcept=default
void set_ref_maybe_replacing_scalar(csubstr ref, bool has_scalar) RYML_NOEXCEPT
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
bool is_doc() const noexcept
const char * type_str() const noexcept
return a preset string based on the node type
A lightweight truthy type, used to enable reporting the offending node when a deserializing error hap...
Reusable object to resolve references/aliases in a Tree.
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
lookup_result(csubstr path_, id_type start)