1 #ifndef _C4_YML_TREE_HPP_
2 #define _C4_YML_TREE_HPP_
6 #include "c4/error.hpp"
7 #include "c4/types.hpp"
8 #ifndef _C4_YML_FWD_HPP_
11 #ifndef _C4_YML_COMMON_HPP_
14 #ifndef C4_YML_NODE_TYPE_HPP_
17 #ifndef _C4_YML_TAG_HPP_
20 #ifndef _C4_CHARCONV_HPP_
28 C4_SUPPRESS_WARNING_MSVC_PUSH
29 C4_SUPPRESS_WARNING_MSVC(4251)
30 C4_SUPPRESS_WARNING_MSVC(4296)
31 C4_SUPPRESS_WARNING_GCC_CLANG_PUSH
32 C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
33 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
34 C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
44 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wfloat-equal");
45 static_assert(std::is_floating_point<T>::value,
"must be floating point");
46 if(C4_UNLIKELY(std::isnan(val)))
47 return to_chars(buf, csubstr(
".nan"));
48 else if(C4_UNLIKELY(val == std::numeric_limits<T>::infinity()))
49 return to_chars(buf, csubstr(
".inf"));
50 else if(C4_UNLIKELY(val == -std::numeric_limits<T>::infinity()))
51 return to_chars(buf, csubstr(
"-.inf"));
53 C4_SUPPRESS_WARNING_GCC_CLANG_POP
62 static_assert(std::is_floating_point<T>::value,
"must be floating point");
67 else if(C4_UNLIKELY(buf.begins_with(
'+')))
71 else if(C4_UNLIKELY(buf ==
".nan" || buf ==
".NaN" || buf ==
".NAN"))
73 *val = std::numeric_limits<T>::quiet_NaN();
76 else if(C4_UNLIKELY(buf ==
".inf" || buf ==
".Inf" || buf ==
".INF"))
78 *val = std::numeric_limits<T>::infinity();
81 else if(C4_UNLIKELY(buf ==
"-.inf" || buf ==
"-.Inf" || buf ==
"-.INF"))
83 *val = -std::numeric_limits<T>::infinity();
117 inline NodeScalar(
const char (&s)[N]) noexcept : tag(), scalar(s), anchor() {}
118 inline NodeScalar(csubstr s ) noexcept : tag(), scalar(s), anchor() {}
121 template<
size_t N,
size_t M>
122 inline NodeScalar(
const char (&t)[N],
const char (&s)[N]) noexcept : tag(t), scalar(s), anchor() {}
123 inline NodeScalar(csubstr t , csubstr s ) noexcept : tag(t), scalar(s), anchor() {}
135 bool empty() const noexcept {
return tag.
empty() && scalar.empty() && anchor.empty(); }
137 void clear() noexcept { tag.clear(); scalar.clear(); anchor.clear(); }
141 csubstr trimmed = ref.begins_with(
'*') ? ref.sub(1) : ref;
143 if((!has_scalar) || !scalar.ends_with(trimmed))
147 C4_MUST_BE_TRIVIAL_COPY(NodeScalar);
190 type = (type|more_flags);
191 if( !
key.tag.empty())
193 if( ! val.
tag.empty())
195 if( !
key.anchor.empty())
204 RYML_ASSERT(
key.scalar.empty() == ((type &
KEY) == 0));
206 RYML_ASSERT(
key.tag.empty() == ((type &
KEYTAG) == 0));
208 RYML_ASSERT(((type &
VAL) != 0) || val.
scalar.empty());
210 RYML_ASSERT(val.
tag.empty() == ((type &
VALTAG) == 0));
268 void reserve(
id_type node_capacity);
276 inline bool empty()
const {
return m_size == 0; }
280 inline id_type slack()
const { RYML_ASSERT(m_cap >= m_size);
return m_cap - m_size; }
298 _RYML_CB_ASSERT(m_callbacks, n >= m_buf && n < m_buf + m_cap);
299 return static_cast<id_type>(n - m_buf);
308 _RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap);
317 _RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap);
323 inline NodeData *
_p(
id_type node) { _RYML_CB_ASSERT(m_callbacks, node !=
NONE && node >= 0 && node < m_cap);
return m_buf + node; }
326 inline NodeData const *
_p(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, node !=
NONE && node >= 0 && node < m_cap);
return m_buf + node; }
329 id_type root_id() {
if(m_cap == 0) { reserve(16); } _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0);
return 0; }
331 id_type root_id()
const { _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0);
return 0; }
379 const char*
type_str(
id_type node)
const {
return NodeType::type_str(_p(node)->m_type); }
381 csubstr
const&
key (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_key(node));
return _p(node)->m_key.scalar; }
382 csubstr
const&
key_tag (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_key_tag(node));
return _p(node)->m_key.tag; }
383 csubstr
const&
key_ref (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, is_key_ref(node));
return _p(node)->m_key.anchor; }
384 csubstr
const&
key_anchor(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_key_anchor(node));
return _p(node)->m_key.anchor; }
387 csubstr
const&
val (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_val(node));
return _p(node)->m_val.scalar; }
388 csubstr
const&
val_tag (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_val_tag(node));
return _p(node)->m_val.tag; }
389 csubstr
const&
val_ref (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, is_val_ref(node));
return _p(node)->m_val.anchor; }
390 csubstr
const&
val_anchor(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_val_anchor(node));
return _p(node)->m_val.anchor; }
404 C4_ALWAYS_INLINE
bool is_stream(
id_type node)
const {
return _p(node)->m_type.is_stream(); }
405 C4_ALWAYS_INLINE
bool is_doc(
id_type node)
const {
return _p(node)->m_type.is_doc(); }
407 C4_ALWAYS_INLINE
bool is_map(
id_type node)
const {
return _p(node)->m_type.is_map(); }
408 C4_ALWAYS_INLINE
bool is_seq(
id_type node)
const {
return _p(node)->m_type.is_seq(); }
409 C4_ALWAYS_INLINE
bool has_key(
id_type node)
const {
return _p(node)->m_type.has_key(); }
410 C4_ALWAYS_INLINE
bool has_val(
id_type node)
const {
return _p(node)->m_type.has_val(); }
411 C4_ALWAYS_INLINE
bool is_val(
id_type node)
const {
return _p(node)->m_type.is_val(); }
412 C4_ALWAYS_INLINE
bool is_keyval(
id_type node)
const {
return _p(node)->m_type.is_keyval(); }
420 C4_ALWAYS_INLINE
bool is_ref(
id_type node)
const {
return _p(node)->m_type.is_ref(); }
422 C4_ALWAYS_INLINE
bool parent_is_seq(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_parent(node));
return is_seq(_p(node)->m_parent); }
423 C4_ALWAYS_INLINE
bool parent_is_map(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_parent(node));
return is_map(_p(node)->m_parent); }
426 C4_ALWAYS_INLINE
bool has_anchor(
id_type node, csubstr a)
const {
return _p(node)->m_key.anchor == a || _p(node)->m_val.anchor == a; }
431 C4_ALWAYS_INLINE
bool key_is_null(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_key(node));
NodeData const* C4_RESTRICT n = _p(node);
return !n->m_type.is_key_quoted() &&
scalar_is_null(n->m_key.scalar); }
435 C4_ALWAYS_INLINE
bool val_is_null(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_val(node));
NodeData const* C4_RESTRICT n = _p(node);
return !n->m_type.is_val_quoted() &&
scalar_is_null(n->m_val.scalar); }
444 RYML_DEPRECATED(
"use has_key_anchor()") bool is_key_anchor(
id_type node)
const {
return _p(node)->m_type.has_key_anchor(); }
445 RYML_DEPRECATED(
"use has_val_anchor()") bool is_val_anchor(
id_type node)
const {
return _p(node)->m_type.has_val_anchor(); }
446 RYML_DEPRECATED(
"use has_anchor()") bool is_anchor(
id_type node)
const {
return _p(node)->m_type.has_anchor(); }
447 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(); }
456 bool is_root(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, _p(node)->m_parent !=
NONE || node == 0);
return _p(node)->m_parent ==
NONE; }
461 bool empty(
id_type node)
const {
return ! has_children(node) && _p(node)->m_key.empty() && (( ! (_p(node)->m_type &
VAL)) || _p(node)->m_val.empty()); }
486 RYML_DEPRECATED(
"use has_other_siblings()") bool has_siblings(
id_type )
const {
return true; }
532 C4_ALWAYS_INLINE
bool is_block(
id_type node)
const {
return _p(node)->m_type.is_block(); }
535 C4_ALWAYS_INLINE
bool is_flow(
id_type node)
const {
return _p(node)->m_type.is_flow(); }
551 C4_ALWAYS_INLINE
bool is_quoted(
id_type node)
const {
return _p(node)->m_type.is_quoted(); }
573 void set_key(
id_type node, csubstr
key) { _RYML_CB_ASSERT(m_callbacks, has_key(node)); _p(node)->m_key.scalar =
key; }
574 void set_val(
id_type node, csubstr val) { _RYML_CB_ASSERT(m_callbacks, has_val(node)); _p(node)->m_val.scalar = val; }
576 void set_key_tag(
id_type node, csubstr tag) { _RYML_CB_ASSERT(m_callbacks, has_key(node)); _p(node)->m_key.tag = tag; _add_flags(node,
KEYTAG); }
577 void set_val_tag(
id_type node, csubstr tag) { _RYML_CB_ASSERT(m_callbacks, has_val(node) || is_container(node)); _p(node)->m_val.tag = tag; _add_flags(node,
VALTAG); }
579 void set_key_anchor(
id_type node, csubstr anchor) { _RYML_CB_ASSERT(m_callbacks, ! is_key_ref(node)); _p(node)->m_key.anchor = anchor.triml(
'&'); _add_flags(node,
KEYANCH); }
580 void set_val_anchor(
id_type node, csubstr anchor) { _RYML_CB_ASSERT(m_callbacks, ! is_val_ref(node)); _p(node)->m_val.anchor = anchor.triml(
'&'); _add_flags(node,
VALANCH); }
581 void set_key_ref (
id_type node, csubstr ref ) { _RYML_CB_ASSERT(m_callbacks, ! has_key_anchor(node));
NodeData* C4_RESTRICT n = _p(node); n->m_key.set_ref_maybe_replacing_scalar(ref, n->m_type.has_key()); _add_flags(node,
KEY|
KEYREF); }
582 void set_val_ref (
id_type node, csubstr ref ) { _RYML_CB_ASSERT(m_callbacks, ! has_val_anchor(node));
NodeData* C4_RESTRICT n = _p(node); n->m_val.set_ref_maybe_replacing_scalar(ref, n->m_type.has_val()); _add_flags(node,
VAL|
VALREF); }
637 void normalize_tags();
638 void normalize_tags_long();
640 id_type num_tag_directives()
const;
641 bool add_tag_directive(csubstr directive);
643 void clear_tag_directives();
647 size_t resolve_tag(substr output, csubstr tag,
id_type node_id)
const;
650 size_t needed = resolve_tag(output, tag, node_id);
651 return needed <= output.len ? output.first(needed) : output;
673 _RYML_CB_ASSERT(m_callbacks, parent !=
NONE);
674 _RYML_CB_ASSERT(m_callbacks, is_container(parent) || is_root(parent));
675 _RYML_CB_ASSERT(m_callbacks, after ==
NONE || (_p(after)->m_parent == parent));
677 _set_hierarchy(child, parent, after);
687 _set_hierarchy(child, parent, _p(parent)->m_last_child);
693 #if defined(__clang__)
694 # pragma clang diagnostic push
695 # pragma clang diagnostic ignored "-Wnull-dereference"
696 #elif defined(__GNUC__)
697 # pragma GCC diagnostic push
699 # pragma GCC diagnostic ignored "-Wnull-dereference"
706 return insert_child(_p(node)->m_parent, after);
717 remove_children(node);
722 void remove_children(
id_type node);
737 return change_type(node, (
NodeType)type);
740 #if defined(__clang__)
741 # pragma clang diagnostic pop
742 #elif defined(__GNUC__)
743 # pragma GCC diagnostic pop
779 void set_root_as_stream();
823 RYML_DEPRECATED(
"use arena_size() instead") size_t arena_pos()
const {
return m_arena_pos; }
829 inline size_t arena_slack()
const { _RYML_CB_ASSERT(m_callbacks, m_arena.len >= m_arena_pos);
return m_arena.len - m_arena_pos; }
832 csubstr
arena()
const {
return m_arena.first(m_arena_pos); }
834 substr
arena() {
return m_arena.first(m_arena_pos); }
839 return m_arena.is_super(s);
853 typename std::enable_if<std::is_floating_point<T>::value, csubstr>::type
856 substr rem(m_arena.sub(m_arena_pos));
860 rem = _grow_arena(num);
862 _RYML_CB_ASSERT(m_callbacks, num <= rem.len);
864 rem = _request_span(num);
879 typename std::enable_if<!std::is_floating_point<T>::value, csubstr>::type
882 substr rem(m_arena.sub(m_arena_pos));
886 rem = _grow_arena(num);
888 _RYML_CB_ASSERT(m_callbacks, num <= rem.len);
890 rem = _request_span(num);
908 substr rem(m_arena.sub(m_arena_pos));
912 rem = _grow_arena(num);
914 _RYML_CB_ASSERT(m_callbacks, num <= rem.len);
916 return _request_span(num);
924 else if(m_arena.str ==
nullptr)
932 return _request_span(0);
956 substr cp = alloc_arena(s.len);
957 _RYML_CB_ASSERT(m_callbacks, cp.len == s.len);
958 _RYML_CB_ASSERT(m_callbacks, !s.overlaps(cp));
959 #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10)
960 C4_SUPPRESS_WARNING_GCC_PUSH
961 C4_SUPPRESS_WARNING_GCC(
"-Wstringop-overflow=")
962 C4_SUPPRESS_WARNING_GCC(
"-Wrestrict")
965 memcpy(cp.str, s.str, s.len);
966 #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10)
967 C4_SUPPRESS_WARNING_GCC_POP
984 if(sz > arena_slack())
985 _grow_arena(sz - arena_slack());
986 substr s = _request_span(sz);
996 if(arena_cap > m_arena.len)
999 buf.str = (
char*) m_callbacks.m_allocate(arena_cap, m_arena.str, m_callbacks.m_user_data);
1000 buf.len = arena_cap;
1003 _RYML_CB_ASSERT(m_callbacks, m_arena.len >= 0);
1005 m_callbacks.m_free(m_arena.str, m_arena.len, m_callbacks.m_user_data);
1015 substr _grow_arena(
size_t more)
1017 size_t cap = m_arena.len + more;
1018 cap = cap < 2 * m_arena.len ? 2 * m_arena.len : cap;
1019 cap = cap < 64 ? 64 : cap;
1021 return m_arena.sub(m_arena_pos);
1024 substr _request_span(
size_t sz)
1026 _RYML_CB_ASSERT(m_callbacks, m_arena_pos + sz <= m_arena.len);
1028 s = m_arena.sub(m_arena_pos, sz);
1033 substr _relocated(csubstr s, substr next_arena)
const
1035 _RYML_CB_ASSERT(m_callbacks, m_arena.is_super(s));
1036 _RYML_CB_ASSERT(m_callbacks, m_arena.sub(0, m_arena_pos).is_super(s));
1037 auto pos = (s.str - m_arena.str);
1038 substr r(next_arena.str + pos, s.len);
1039 _RYML_CB_ASSERT(m_callbacks, r.str - next_arena.str == pos);
1040 _RYML_CB_ASSERT(m_callbacks, next_arena.sub(0, m_arena_pos).is_super(r));
1056 inline operator bool()
const {
return target !=
NONE; }
1062 csubstr resolved()
const;
1064 csubstr unresolved()
const;
1068 lookup_result lookup_path(csubstr path,
id_type start=
NONE)
const;
1074 id_type lookup_path_or_modify(csubstr default_value, csubstr path,
id_type start=
NONE);
1086 struct _lookup_path_token
1090 _lookup_path_token() : value(), type() {}
1091 _lookup_path_token(csubstr v, NodeType t) : value(v), type(t) {}
1092 inline operator bool()
const {
return type !=
NOTYPE; }
1093 bool is_index()
const {
return value.begins_with(
'[') && value.ends_with(
']'); }
1098 void _lookup_path (lookup_result *r)
const;
1099 void _lookup_path_modify(lookup_result *r);
1101 id_type _next_node (lookup_result *r, _lookup_path_token *parent)
const;
1102 id_type _next_node_modify(lookup_result *r, _lookup_path_token *parent);
1104 void _advance(lookup_result *r,
size_t more)
const;
1106 _lookup_path_token _next_token(lookup_result *r, _lookup_path_token
const& parent)
const;
1112 void _copy(Tree
const& that);
1113 void _move(Tree & that) noexcept;
1115 void _relocate(substr next_arena);
1121 #if ! RYML_USE_ASSERT
1131 RYML_ASSERT_MSG((f &
SEQ) == 0,
"cannot mark simultaneously as map and seq");
1132 RYML_ASSERT_MSG((f &
VAL) == 0,
"cannot mark simultaneously as map and val");
1133 RYML_ASSERT_MSG((o &
SEQ) == 0,
"cannot turn a seq into a map; clear first");
1134 RYML_ASSERT_MSG((o &
VAL) == 0,
"cannot turn a val into a map; clear first");
1138 RYML_ASSERT_MSG((f &
MAP) == 0,
"cannot mark simultaneously as seq and map");
1139 RYML_ASSERT_MSG((f &
VAL) == 0,
"cannot mark simultaneously as seq and val");
1140 RYML_ASSERT_MSG((o &
MAP) == 0,
"cannot turn a map into a seq; clear first");
1141 RYML_ASSERT_MSG((o &
VAL) == 0,
"cannot turn a val into a seq; clear first");
1145 _RYML_CB_ASSERT(m_callbacks, !is_root(node));
1146 auto pid = parent(node); C4_UNUSED(pid);
1147 _RYML_CB_ASSERT(m_callbacks, is_map(pid));
1149 if((f &
VAL) && !is_root(node))
1151 auto pid = parent(node); C4_UNUSED(pid);
1152 _RYML_CB_ASSERT(m_callbacks, is_map(pid) || is_seq(pid));
1157 inline void _set_flags(
id_type node,
NodeType_e f) { _check_next_flags(node, f); _p(node)->m_type = f; }
1158 inline void _set_flags(
id_type node,
type_bits f) { _check_next_flags(node, f); _p(node)->m_type = f; }
1161 inline void _add_flags(
id_type node,
type_bits f) { NodeData *d = _p(node); f |= d->m_type; _check_next_flags(node, f); d->m_type = f; }
1164 inline void _rem_flags(
id_type node,
type_bits f) { NodeData *d = _p(node); f = d->m_type & ~f; _check_next_flags(node, f); d->m_type = f; }
1168 _p(node)->m_key.scalar =
key;
1169 _add_flags(node,
KEY|more_flags);
1173 _p(node)->m_key =
key;
1174 _add_flags(node,
KEY|more_flags);
1179 _RYML_CB_ASSERT(m_callbacks, num_children(node) == 0);
1180 _RYML_CB_ASSERT(m_callbacks, !is_seq(node) && !is_map(node));
1181 _p(node)->m_val.scalar = val;
1182 _add_flags(node,
VAL|more_flags);
1186 _RYML_CB_ASSERT(m_callbacks, num_children(node) == 0);
1187 _RYML_CB_ASSERT(m_callbacks, ! is_container(node));
1188 _p(node)->m_val = val;
1189 _add_flags(node,
VAL|more_flags);
1192 void _set(
id_type node, NodeInit
const& i)
1194 _RYML_CB_ASSERT(m_callbacks, i._check());
1195 NodeData *n = _p(node);
1196 _RYML_CB_ASSERT(m_callbacks, n->m_key.scalar.empty() || i.key.scalar.empty() || i.key.scalar == n->m_key.scalar);
1197 _add_flags(node, i.type);
1198 if(n->m_key.scalar.empty())
1200 if( ! i.key.scalar.empty())
1202 _set_key(node, i.key.scalar);
1205 n->m_key.tag = i.key.tag;
1209 void _set_parent_as_container_if_needed(
id_type in)
1211 NodeData
const* n = _p(in);
1215 if( ! (is_seq(ip) || is_map(ip)))
1217 if((in == first_child(ip)) && (in == last_child(ip)))
1219 if( ! n->m_key.empty() || has_key(in))
1221 _add_flags(ip,
MAP);
1225 _add_flags(ip,
SEQ);
1234 _RYML_CB_ASSERT(m_callbacks, is_seq(node));
1235 for(
id_type i = first_child(node); i !=
NONE; i = next_sibling(i))
1237 NodeData *C4_RESTRICT ch = _p(i);
1238 if(ch->m_type.is_keyval())
1240 ch->m_type.add(
KEY);
1241 ch->m_key = ch->m_val;
1243 auto *C4_RESTRICT n = _p(node);
1257 _copy_props(dst_,
this, src_);
1262 _copy_props_wo_key(dst_,
this, src_);
1265 void _copy_props(
id_type dst_, Tree
const* that_tree,
id_type src_)
1267 auto & C4_RESTRICT dst = *_p(dst_);
1268 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1269 dst.m_type = src.m_type;
1270 dst.m_key = src.m_key;
1271 dst.m_val = src.m_val;
1276 auto & C4_RESTRICT dst = *_p(dst_);
1277 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1278 dst.m_type = (src.m_type & src_mask) | (dst.m_type & ~src_mask);
1279 dst.m_key = src.m_key;
1280 dst.m_val = src.m_val;
1283 void _copy_props_wo_key(
id_type dst_, Tree
const* that_tree,
id_type src_)
1285 auto & C4_RESTRICT dst = *_p(dst_);
1286 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1288 dst.m_val = src.m_val;
1293 auto & C4_RESTRICT dst = *_p(dst_);
1294 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1295 dst.m_type = (src.m_type & ((~
_KEYMASK)|src_mask)) | (dst.m_type & (
_KEYMASK|~src_mask));
1296 dst.m_val = src.m_val;
1299 inline void _clear_type(
id_type node)
1301 _p(node)->m_type =
NOTYPE;
1304 inline void _clear(
id_type node)
1306 auto *C4_RESTRICT n = _p(node);
1311 n->m_first_child =
NONE;
1312 n->m_last_child =
NONE;
1315 inline void _clear_key(
id_type node)
1317 _p(node)->m_key.clear();
1318 _rem_flags(node,
KEY);
1321 inline void _clear_val(
id_type node)
1323 _p(node)->m_val.clear();
1324 _rem_flags(node,
VAL);
1338 void _free_list_add(
id_type node);
1339 void _free_list_rem(
id_type node);
1342 void _rem_hierarchy(
id_type node);
1371 C4_SUPPRESS_WARNING_MSVC_POP
1372 C4_SUPPRESS_WARNING_GCC_CLANG_POP
Lightweight generic type-safe wrappers for converting individual values to/from strings.
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...
csubstr to_arena(csubstr a)
serialize the given csubstr to the tree's arena, growing the arena as needed to accomodate the serial...
id_type num_other_siblings(id_type node) const
does not count with this
void reserve_arena(size_t arena_cap)
ensure the tree's internal string arena is at least the given capacity
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
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
NodeType type(id_type node) const
id_type append_sibling(id_type node)
void set_val_ref(id_type node, csubstr ref)
id_type root_id() const
Get the id of the root node.
size_t arena_slack() const
get the current slack of the tree's internal arena
bool has_key_tag(id_type node) const
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
id_type prepend_sibling(id_type node)
create and insert a node as the first node of parent
std::enable_if<!std::is_floating_point< T >::value, csubstr >::type to_arena(T const &a)
serialize the given non-floating-point variable to the tree's arena, growing it as needed to accomoda...
bool is_map(id_type node) const
csubstr const & key_ref(id_type node) const
void callbacks(Callbacks const &cb)
id_type sibling(id_type node, id_type pos) const
c4::yml::TagDirectiveRange tag_directives() const
bool is_key_quoted(id_type node) const
bool has_val_anchor(id_type node) const
bool is_root(id_type node) const
bool key_is_null(id_type node) const
true if the node key does not have any KEYQUO flags, and its scalar verifies scalar_is_null().
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
id_type last_sibling(id_type node) const
bool has_key(id_type node) const
bool has_other_siblings(id_type node) const
true if node is not a single child
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
void set_key_style(id_type node, NodeType_e style)
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)
Callbacks const & callbacks() const
TagDirective const * end_tag_directives() const
bool is_key_literal(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
NodeScalar const & valsc(id_type node) const
bool type_has_any(id_type node, NodeType_e bits) const
bool is_container_styled(id_type node) const
csubstr to_arena(const char *s)
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...
id_type sibling_pos(id_type node, id_type sib) const
id_type append_child(id_type parent)
create and insert a node as the last child of parent
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
bool is_key_squo(id_type node) const
bool parent_is_seq(id_type node) const
csubstr const & key(id_type node) const
csubstr const & val_ref(id_type node) const
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
bool is_key_dquo(id_type node) const
void set_key_tag(id_type node, csubstr tag)
TagDirective const * begin_tag_directives() const
void rem_anchor_ref(id_type node)
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
NodeData const * get(id_type node) const
get a pointer to a node's NodeData. i can be NONE, in which case a nullptr is returned.
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_container_style(id_type node, NodeType_e style)
csubstr to_arena(std::nullptr_t)
bool is_key_ref(id_type node) const
void set_key(id_type node, csubstr key)
bool has_val(id_type node) const
bool is_val_dquo(id_type node) const
NodeScalar const & keysc(id_type node) const
size_t arena_capacity() const
get the current capacity of the tree's internal arena
csubstr const & key_anchor(id_type node) const
id_type doc(id_type i) const
gets the i document node index.
bool is_flow_ml(id_type node) const
bool is_key_folded(id_type node) const
csubstr const & val_tag(id_type node) const
bool type_has_all(id_type node, NodeType_e bits) const
void set_val(id_type node, csubstr val)
csubstr const & val(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
std::enable_if< std::is_floating_point< T >::value, csubstr >::type to_arena(T const &a)
serialize the given floating-point variable to the tree's arena, growing it as needed to accomodate t...
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
bool is_quoted(id_type node) const
bool change_type(id_type node, type_bits type)
Tree(id_type node_capacity, size_t arena_capacity=0)
csubstr const & key_tag(id_type node) const
void set_val_style(id_type node, NodeType_e style)
substr arena()
get the current arena
id_type root_id()
Get the id of the root node.
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 key does not have any VALQUO flags, and its scalar verifies scalar_is_null().
id_type first_sibling(id_type node) const
bool is_flow(id_type node) const
bool is_val_quoted(id_type node) const
TagDirective const * tag_directive_const_iterator
bool type_has_none(id_type node, NodeType_e bits) const
bool empty(id_type node) const
true when key and val are empty, and has no children
bool is_val_squo(id_type node) const
substr copy_to_arena(csubstr s)
copy the given substr to the tree's arena, growing it by the required size
csubstr arena() const
get the current arena
bool is_container(id_type node) const
size_t arena_size() const
get the current size of the tree's internal arena
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)
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)
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...
void rem_key_ref(id_type node)
csubstr const & val_anchor(id_type node) const
NodeData * _p(id_type node)
An if-less form of get() that demands a valid node index. This function is implementation only; use a...
bool is_flow_sl(id_type node) const
bool has_children(id_type node) const
true if node has any children key
bool has_anchor(id_type node, csubstr a) const
true when the node has an anchor named a
const char * type_str(id_type node) const
Common utilities and infrastructure used by ryml.
#define RYML_NOEXCEPT
Conditionally expands to noexcept when RYML_USE_ASSERT is 0 and is empty otherwise.
Callbacks const & get_callbacks()
get the global callbacks
bool scalar_is_null(csubstr s) noexcept
YAML-sense query of nullity.
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
NodeType_e
a bit mask for marking node types and styles
@ 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
@ KEY
is member of a map, must have non-empty key
@ 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
@ KEYREF
a *reference: the key references an &anchor
@ KEYANCH
the key has an &anchor
bool from_chars(ryml::csubstr buf, vec2< T > *v)
size_t to_chars(ryml::substr buf, vec2< T > v)
csubstr to_csubstr(substr s) noexcept
neutral version for use in generic code
#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...
size_t to_chars_float(substr buf, T val)
encode a floating point value to a string.
bool from_chars_float(csubstr buf, T *val)
decode a floating point from string.
a c-style callbacks class.
contains the data for each YAML node.
convenience class to initialize nodes
NodeInit(NodeScalar const &k, NodeScalar const &v)
initialize as a mapping member
NodeInit(NodeType_e t, NodeScalar const &k, NodeScalar const &v)
initialize as a mapping member with explicit type
void _add_flags(type_bits more_flags=0)
NodeInit(NodeScalar const &v, NodeType_e t)
initialize as a sequence member with explicit type
NodeInit(NodeScalar const &v)
initialize as a sequence member
NodeInit(NodeType_e t)
initialize as a typed node
NodeInit(NodeType_e t, NodeScalar const &k)
initialize as a mapping member with explicit type (eg for SEQ or MAP)
NodeInit()
initialize as an empty 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 NodeType_e element with some syntactic sugar and predicates
Reusable object to resolve references/aliases in the tree.
lookup_result(csubstr path_, id_type start)