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")
40 template<
class T>
inline auto read(Tree
const* C4_RESTRICT tree,
id_type id, T *v) ->
typename std::enable_if<!std::is_arithmetic<T>::value,
bool>::type;
41 template<
class T>
inline auto read(Tree
const* C4_RESTRICT tree,
id_type id, T *v) ->
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_floating_point<T>::value,
bool>::type;
42 template<
class T>
inline auto read(Tree
const* C4_RESTRICT tree,
id_type id, T *v) ->
typename std::enable_if<std::is_floating_point<T>::value,
bool>::type;
44 template<
class T>
inline auto readkey(Tree
const* C4_RESTRICT tree,
id_type id, T *v) ->
typename std::enable_if<!std::is_arithmetic<T>::value,
bool>::type;
45 template<
class T>
inline auto readkey(Tree
const* C4_RESTRICT tree,
id_type id, T *v) ->
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_floating_point<T>::value,
bool>::type;
46 template<
class T>
inline auto readkey(Tree
const* C4_RESTRICT tree,
id_type id, T *v) ->
typename std::enable_if<std::is_floating_point<T>::value,
bool>::type;
76 NodeScalar(
const char (&s)[N]) noexcept : tag(), scalar(s), anchor() {}
77 NodeScalar(csubstr s ) noexcept : tag(), scalar(s), anchor() {}
80 template<
size_t N,
size_t M>
81 NodeScalar(
const char (&t)[N],
const char (&s)[N]) noexcept : tag(t), scalar(s), anchor() {}
82 NodeScalar(csubstr t , csubstr s ) noexcept : tag(t), scalar(s), anchor() {}
94 bool empty() const noexcept {
return tag.
empty() && scalar.empty() && anchor.empty(); }
96 void clear() noexcept { tag.clear(); scalar.clear(); anchor.clear(); }
100 csubstr trimmed = ref.begins_with(
'*') ? ref.sub(1) : ref;
102 if((!has_scalar) || !scalar.ends_with(trimmed))
106 C4_MUST_BE_TRIVIAL_COPY(NodeScalar);
149 type = (type|more_flags);
150 if( !
key.tag.empty())
152 if( ! val.
tag.empty())
154 if( !
key.anchor.empty())
163 RYML_ASSERT(
key.scalar.empty() == ((type &
KEY) == 0));
165 RYML_ASSERT(
key.tag.empty() == ((type &
KEYTAG) == 0));
167 RYML_ASSERT(((type &
VAL) != 0) || val.
scalar.empty());
169 RYML_ASSERT(val.
tag.empty() == ((type &
VALTAG) == 0));
218 Tree& operator= (
Tree && that) noexcept;
227 void reserve(
id_type node_capacity);
235 bool empty()
const {
return m_size == 0; }
239 id_type slack()
const { RYML_ASSERT(m_cap >= m_size);
return m_cap - m_size; }
257 _RYML_CB_ASSERT(m_callbacks, n >= m_buf && n < m_buf + m_cap);
258 return static_cast<id_type>(n - m_buf);
267 _RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap);
276 _RYML_CB_ASSERT(m_callbacks, node >= 0 && node < m_cap);
282 NodeData *
_p(
id_type node) { _RYML_CB_ASSERT(m_callbacks, node !=
NONE && node >= 0 && node < m_cap);
return m_buf + node; }
285 NodeData const *
_p(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, node !=
NONE && node >= 0 && node < m_cap);
return m_buf + node; }
288 id_type root_id() {
if(m_cap == 0) { reserve(16); } _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0);
return 0; }
290 id_type root_id()
const { _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0);
return 0; }
338 const char*
type_str(
id_type node)
const {
return NodeType::type_str(_p(node)->m_type); }
340 csubstr
const&
key (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_key(node));
return _p(node)->m_key.scalar; }
341 csubstr
const&
key_tag (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_key_tag(node));
return _p(node)->m_key.tag; }
342 csubstr
const&
key_ref (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, is_key_ref(node));
return _p(node)->m_key.anchor; }
343 csubstr
const&
key_anchor(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_key_anchor(node));
return _p(node)->m_key.anchor; }
346 csubstr
const&
val (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_val(node));
return _p(node)->m_val.scalar; }
347 csubstr
const&
val_tag (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_val_tag(node));
return _p(node)->m_val.tag; }
348 csubstr
const&
val_ref (
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, is_val_ref(node));
return _p(node)->m_val.anchor; }
349 csubstr
const&
val_anchor(
id_type node)
const { _RYML_CB_ASSERT(m_callbacks, has_val_anchor(node));
return _p(node)->m_val.anchor; }
363 C4_ALWAYS_INLINE
bool is_stream(
id_type node)
const {
return _p(node)->m_type.is_stream(); }
364 C4_ALWAYS_INLINE
bool is_doc(
id_type node)
const {
return _p(node)->m_type.is_doc(); }
366 C4_ALWAYS_INLINE
bool is_map(
id_type node)
const {
return _p(node)->m_type.is_map(); }
367 C4_ALWAYS_INLINE
bool is_seq(
id_type node)
const {
return _p(node)->m_type.is_seq(); }
368 C4_ALWAYS_INLINE
bool has_key(
id_type node)
const {
return _p(node)->m_type.has_key(); }
369 C4_ALWAYS_INLINE
bool has_val(
id_type node)
const {
return _p(node)->m_type.has_val(); }
370 C4_ALWAYS_INLINE
bool is_val(
id_type node)
const {
return _p(node)->m_type.is_val(); }
371 C4_ALWAYS_INLINE
bool is_keyval(
id_type node)
const {
return _p(node)->m_type.is_keyval(); }
379 C4_ALWAYS_INLINE
bool is_ref(
id_type node)
const {
return _p(node)->m_type.is_ref(); }
381 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); }
382 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); }
385 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; }
390 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() && (n->m_type.key_is_null() ||
scalar_is_null(n->m_key.scalar)); }
394 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() && (n->m_type.val_is_null() ||
scalar_is_null(n->m_val.scalar)); }
403 RYML_DEPRECATED(
"use has_key_anchor()") bool is_key_anchor(
id_type node)
const {
return _p(node)->m_type.has_key_anchor(); }
404 RYML_DEPRECATED(
"use has_val_anchor()") bool is_val_anchor(
id_type node)
const {
return _p(node)->m_type.has_val_anchor(); }
405 RYML_DEPRECATED(
"use has_anchor()") bool is_anchor(
id_type node)
const {
return _p(node)->m_type.has_anchor(); }
406 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(); }
415 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; }
423 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()); }
448 RYML_DEPRECATED(
"use has_other_siblings()") static
bool has_siblings(
id_type ) {
return true; }
494 C4_ALWAYS_INLINE
bool is_block(
id_type node)
const {
return _p(node)->m_type.is_block(); }
497 C4_ALWAYS_INLINE
bool is_flow(
id_type node)
const {
return _p(node)->m_type.is_flow(); }
513 C4_ALWAYS_INLINE
bool is_quoted(
id_type node)
const {
return _p(node)->m_type.is_quoted(); }
535 void set_key(
id_type node, csubstr
key) { _RYML_CB_ASSERT(m_callbacks, has_key(node)); _p(node)->m_key.scalar =
key; }
536 void set_val(
id_type node, csubstr val) { _RYML_CB_ASSERT(m_callbacks, has_val(node)); _p(node)->m_val.scalar = val; }
538 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); }
539 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); }
541 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); }
542 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); }
543 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); }
544 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); }
581 void resolve(
bool clear_anchors=
true);
589 void normalize_tags();
590 void normalize_tags_long();
592 id_type num_tag_directives()
const;
593 bool add_tag_directive(csubstr directive);
595 void clear_tag_directives();
599 size_t resolve_tag(substr output, csubstr tag,
id_type node_id)
const;
602 size_t needed = resolve_tag(output, tag, node_id);
603 return needed <= output.len ? output.first(needed) : output;
625 _RYML_CB_ASSERT(m_callbacks, parent !=
NONE);
626 _RYML_CB_ASSERT(m_callbacks, is_container(parent) || is_root(parent));
627 _RYML_CB_ASSERT(m_callbacks, after ==
NONE || (_p(after)->m_parent == parent));
629 _set_hierarchy(child, parent, after);
639 _set_hierarchy(child, parent, _p(parent)->m_last_child);
645 #if defined(__clang__)
646 # pragma clang diagnostic push
647 # pragma clang diagnostic ignored "-Wnull-dereference"
648 #elif defined(__GNUC__)
649 # pragma GCC diagnostic push
651 # pragma GCC diagnostic ignored "-Wnull-dereference"
658 return insert_child(_p(node)->m_parent, after);
669 remove_children(node);
674 void remove_children(
id_type node);
689 return change_type(node, (
NodeType)type);
692 #if defined(__clang__)
693 # pragma clang diagnostic pop
694 #elif defined(__GNUC__)
695 # pragma GCC diagnostic pop
731 void set_root_as_stream();
775 RYML_DEPRECATED(
"use arena_size() instead") size_t arena_pos()
const {
return m_arena_pos; }
781 size_t arena_slack()
const { _RYML_CB_ASSERT(m_callbacks, m_arena.len >= m_arena_pos);
return m_arena.len - m_arena_pos; }
784 csubstr
arena()
const {
return m_arena.first(m_arena_pos); }
786 substr
arena() {
return m_arena.first(m_arena_pos); }
791 return m_arena.is_super(s);
806 ->
typename std::enable_if<std::is_floating_point<T>::value, csubstr>::type
808 substr rem(m_arena.sub(m_arena_pos));
812 rem = _grow_arena(num);
814 _RYML_CB_ASSERT(m_callbacks, num <= rem.len);
816 rem = _request_span(num);
832 ->
typename std::enable_if<!std::is_floating_point<T>::value, csubstr>::type
834 substr rem(m_arena.sub(m_arena_pos));
838 rem = _grow_arena(num);
840 _RYML_CB_ASSERT(m_callbacks, num <= rem.len);
842 rem = _request_span(num);
860 substr rem(m_arena.sub(m_arena_pos));
864 rem = _grow_arena(num);
866 _RYML_CB_ASSERT(m_callbacks, num <= rem.len);
868 return _request_span(num);
876 else if(m_arena.str ==
nullptr)
884 return _request_span(0);
891 C4_ALWAYS_INLINE
static csubstr
to_arena(std::nullptr_t)
910 substr cp = alloc_arena(s.len);
911 _RYML_CB_ASSERT(m_callbacks, cp.len == s.len);
912 _RYML_CB_ASSERT(m_callbacks, !s.overlaps(cp));
913 #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10)
914 C4_SUPPRESS_WARNING_GCC_PUSH
915 C4_SUPPRESS_WARNING_GCC(
"-Wstringop-overflow=")
916 C4_SUPPRESS_WARNING_GCC(
"-Wrestrict")
919 memcpy(cp.str, s.str, s.len);
920 #if (!defined(__clang__)) && (defined(__GNUC__) && __GNUC__ >= 10)
921 C4_SUPPRESS_WARNING_GCC_POP
938 if(sz > arena_slack())
939 _grow_arena(sz - arena_slack());
940 substr s = _request_span(sz);
950 if(arena_cap > m_arena.len)
953 buf.str = (
char*) m_callbacks.m_allocate(arena_cap, m_arena.str, m_callbacks.m_user_data);
957 _RYML_CB_ASSERT(m_callbacks, m_arena.len >= 0);
959 m_callbacks.m_free(m_arena.str, m_arena.len, m_callbacks.m_user_data);
969 substr _grow_arena(
size_t more)
971 size_t cap = m_arena.len + more;
972 cap = cap < 2 * m_arena.len ? 2 * m_arena.len : cap;
973 cap = cap < 64 ? 64 : cap;
975 return m_arena.sub(m_arena_pos);
978 substr _request_span(
size_t sz)
980 _RYML_CB_ASSERT(m_callbacks, m_arena_pos + sz <= m_arena.len);
982 s = m_arena.sub(m_arena_pos, sz);
987 substr _relocated(csubstr s, substr next_arena)
const
989 _RYML_CB_ASSERT(m_callbacks, m_arena.is_super(s));
990 _RYML_CB_ASSERT(m_callbacks, m_arena.sub(0, m_arena_pos).is_super(s));
991 auto pos = (s.str - m_arena.str);
992 substr r(next_arena.str + pos, s.len);
993 _RYML_CB_ASSERT(m_callbacks, r.str - next_arena.str == pos);
994 _RYML_CB_ASSERT(m_callbacks, next_arena.sub(0, m_arena_pos).is_super(r));
1010 operator bool()
const {
return target !=
NONE; }
1016 csubstr resolved()
const;
1018 csubstr unresolved()
const;
1022 lookup_result lookup_path(csubstr path,
id_type start=
NONE)
const;
1028 id_type lookup_path_or_modify(csubstr default_value, csubstr path,
id_type start=
NONE);
1040 struct _lookup_path_token
1044 _lookup_path_token() : value(), type() {}
1045 _lookup_path_token(csubstr v, NodeType t) : value(v), type(t) {}
1046 operator bool()
const {
return type !=
NOTYPE; }
1047 bool is_index()
const {
return value.begins_with(
'[') && value.ends_with(
']'); }
1052 void _lookup_path (lookup_result *r)
const;
1053 void _lookup_path_modify(lookup_result *r);
1055 id_type _next_node (lookup_result *r, _lookup_path_token *parent)
const;
1056 id_type _next_node_modify(lookup_result *r, _lookup_path_token *parent);
1058 static void _advance(lookup_result *r,
size_t more);
1060 _lookup_path_token _next_token(lookup_result *r, _lookup_path_token
const& parent)
const;
1066 void _copy(Tree
const& that);
1067 void _move(Tree & that) noexcept;
1069 void _relocate(substr next_arena);
1075 #if ! RYML_USE_ASSERT
1080 NodeData *n = _p(node);
1085 RYML_ASSERT_MSG((f &
SEQ) == 0,
"cannot mark simultaneously as map and seq");
1086 RYML_ASSERT_MSG((f &
VAL) == 0,
"cannot mark simultaneously as map and val");
1087 RYML_ASSERT_MSG((o &
SEQ) == 0,
"cannot turn a seq into a map; clear first");
1088 RYML_ASSERT_MSG((o &
VAL) == 0,
"cannot turn a val into a map; clear first");
1092 RYML_ASSERT_MSG((f &
MAP) == 0,
"cannot mark simultaneously as seq and map");
1093 RYML_ASSERT_MSG((f &
VAL) == 0,
"cannot mark simultaneously as seq and val");
1094 RYML_ASSERT_MSG((o &
MAP) == 0,
"cannot turn a map into a seq; clear first");
1095 RYML_ASSERT_MSG((o &
VAL) == 0,
"cannot turn a val into a seq; clear first");
1099 _RYML_CB_ASSERT(m_callbacks, !is_root(node));
1100 auto pid = parent(node); C4_UNUSED(pid);
1101 _RYML_CB_ASSERT(m_callbacks, is_map(pid));
1103 if((f &
VAL) && !is_root(node))
1105 auto pid = parent(node); C4_UNUSED(pid);
1106 _RYML_CB_ASSERT(m_callbacks, is_map(pid) || is_seq(pid));
1111 void _set_flags(
id_type node,
NodeType_e f) { _check_next_flags(node, f); _p(node)->m_type = f; }
1112 void _set_flags(
id_type node,
type_bits f) { _check_next_flags(node, f); _p(node)->m_type = f; }
1115 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; }
1118 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; }
1122 _p(node)->m_key.scalar =
key;
1123 _add_flags(node,
KEY|more_flags);
1127 _p(node)->m_key =
key;
1128 _add_flags(node,
KEY|more_flags);
1133 _RYML_CB_ASSERT(m_callbacks, num_children(node) == 0);
1134 _RYML_CB_ASSERT(m_callbacks, !is_seq(node) && !is_map(node));
1135 _p(node)->m_val.scalar = val;
1136 _add_flags(node,
VAL|more_flags);
1140 _RYML_CB_ASSERT(m_callbacks, num_children(node) == 0);
1141 _RYML_CB_ASSERT(m_callbacks, ! is_container(node));
1142 _p(node)->m_val = val;
1143 _add_flags(node,
VAL|more_flags);
1146 void _set(
id_type node, NodeInit
const& i)
1148 _RYML_CB_ASSERT(m_callbacks, i._check());
1149 NodeData *n = _p(node);
1150 _RYML_CB_ASSERT(m_callbacks, n->m_key.scalar.empty() || i.key.scalar.empty() || i.key.scalar == n->m_key.scalar);
1151 _add_flags(node, i.type);
1152 if(n->m_key.scalar.empty())
1154 if( ! i.key.scalar.empty())
1156 _set_key(node, i.key.scalar);
1159 n->m_key.tag = i.key.tag;
1163 void _set_parent_as_container_if_needed(
id_type in)
1165 NodeData
const* n = _p(in);
1169 if( ! (is_seq(ip) || is_map(ip)))
1171 if((in == first_child(ip)) && (in == last_child(ip)))
1173 if( ! n->m_key.empty() || has_key(in))
1175 _add_flags(ip,
MAP);
1179 _add_flags(ip,
SEQ);
1188 _RYML_CB_ASSERT(m_callbacks, is_seq(node));
1189 for(
id_type i = first_child(node); i !=
NONE; i = next_sibling(i))
1191 NodeData *C4_RESTRICT ch = _p(i);
1192 if(ch->m_type.is_keyval())
1194 ch->m_type.add(
KEY);
1195 ch->m_key = ch->m_val;
1197 auto *C4_RESTRICT n = _p(node);
1211 _copy_props(dst_,
this, src_);
1216 _copy_props_wo_key(dst_,
this, src_);
1219 void _copy_props(
id_type dst_, Tree
const* that_tree,
id_type src_)
1221 auto & C4_RESTRICT dst = *_p(dst_);
1222 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1223 dst.m_type = src.m_type;
1224 dst.m_key = src.m_key;
1225 dst.m_val = src.m_val;
1230 auto & C4_RESTRICT dst = *_p(dst_);
1231 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1232 dst.m_type = (src.m_type & src_mask) | (dst.m_type & ~src_mask);
1233 dst.m_key = src.m_key;
1234 dst.m_val = src.m_val;
1237 void _copy_props_wo_key(
id_type dst_, Tree
const* that_tree,
id_type src_)
1239 auto & C4_RESTRICT dst = *_p(dst_);
1240 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1242 dst.m_val = src.m_val;
1247 auto & C4_RESTRICT dst = *_p(dst_);
1248 auto const& C4_RESTRICT src = *that_tree->_p(src_);
1249 dst.m_type = (src.m_type & ((~
_KEYMASK)|src_mask)) | (dst.m_type & (
_KEYMASK|~src_mask));
1250 dst.m_val = src.m_val;
1253 void _clear_type(
id_type node)
1255 _p(node)->m_type =
NOTYPE;
1260 auto *C4_RESTRICT n = _p(node);
1265 n->m_first_child =
NONE;
1266 n->m_last_child =
NONE;
1271 _p(node)->m_key.clear();
1272 _rem_flags(node,
KEY);
1277 _p(node)->m_val.clear();
1278 _rem_flags(node,
VAL);
1292 void _free_list_add(
id_type node);
1293 void _free_list_rem(
id_type node);
1296 void _rem_hierarchy(
id_type node);
1338 ->
typename std::enable_if<!std::is_arithmetic<T>::value,
bool>::type
1340 return C4_LIKELY(!(tree->type(
id) &
VALNIL)) ?
from_chars(tree->val(
id), v) :
false;
1349 ->
typename std::enable_if<!std::is_arithmetic<T>::value,
bool>::type
1351 return C4_LIKELY(!(tree->type(
id) &
KEYNIL)) ?
from_chars(tree->key(
id), v) :
false;
1363 inline auto read(Tree
const* C4_RESTRICT tree,
id_type id, T *v)
1364 ->
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_floating_point<T>::value,
bool>::type
1366 using U =
typename std::remove_cv<T>::type;
1367 enum { ischar = std::is_same<char, U>::value || std::is_same<signed char, U>::value || std::is_same<unsigned char, U>::value };
1368 csubstr val = tree->val(
id);
1369 NodeType ty = tree->type(
id);
1370 if(C4_UNLIKELY((ty &
VALNIL) || val.empty()))
1374 char first = val[0];
1375 if(ty.is_val_quoted() && (first !=
'0' && !ischar))
1377 else if(first ==
'+')
1388 inline auto readkey(Tree
const* C4_RESTRICT tree,
id_type id, T *v)
1389 ->
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_floating_point<T>::value,
bool>::type
1391 using U =
typename std::remove_cv<T>::type;
1392 enum { ischar = std::is_same<char, U>::value || std::is_same<signed char, U>::value || std::is_same<unsigned char, U>::value };
1393 csubstr
key = tree->key(
id);
1394 NodeType ty = tree->type(
id);
1399 char first =
key[0];
1400 if(ty.is_key_quoted() && (first !=
'0' && !ischar))
1402 else if(first ==
'+')
1414 static_assert(std::is_floating_point<T>::value,
"must be floating point");
1415 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(
"-Wfloat-equal");
1416 if(C4_UNLIKELY(std::isnan(val)))
1417 return to_chars(buf, csubstr(
".nan"));
1418 else if(C4_UNLIKELY(val == std::numeric_limits<T>::infinity()))
1419 return to_chars(buf, csubstr(
".inf"));
1420 else if(C4_UNLIKELY(val == -std::numeric_limits<T>::infinity()))
1421 return to_chars(buf, csubstr(
"-.inf"));
1423 C4_SUPPRESS_WARNING_GCC_CLANG_POP
1432 static_assert(std::is_floating_point<T>::value,
"must be floating point");
1433 if(buf.begins_with(
'+'))
1441 else if(C4_UNLIKELY(buf ==
".nan" || buf ==
".NaN" || buf ==
".NAN"))
1443 *val = std::numeric_limits<T>::quiet_NaN();
1446 else if(C4_UNLIKELY(buf ==
".inf" || buf ==
".Inf" || buf ==
".INF"))
1448 *val = std::numeric_limits<T>::infinity();
1451 else if(C4_UNLIKELY(buf ==
"-.inf" || buf ==
"-.Inf" || buf ==
"-.INF"))
1453 *val = -std::numeric_limits<T>::infinity();
1485 typename std::enable_if<std::is_floating_point<T>::value,
bool>::type
1488 csubstr val = tree->val(
id);
1515 typename std::enable_if<std::is_floating_point<T>::value,
bool>::type
1518 csubstr
key = tree->key(
id);
1531 C4_SUPPRESS_WARNING_MSVC_POP
1532 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
auto to_arena(T const &a) -> typename std::enable_if< std::is_floating_point< T >::value, csubstr >::type
serialize the given floating-point variable to the tree's arena, growing it as needed to accomodate t...
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
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 is empty, or 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
static csubstr to_arena(std::nullptr_t)
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)
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
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 val is empty, or 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
auto to_arena(T const &a) -> typename std::enable_if<!std::is_floating_point< T >::value, csubstr >::type
serialize the given non-floating-point variable to the tree's arena, growing it as needed to accomoda...
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
@ VALNIL
the val is null (eg {a : } results in a null val)
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
@ 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
@ KEYNIL
the key is null (eg { : b} results in a null key)
bool from_chars(ryml::csubstr buf, vec2< T > *v)
size_t to_chars(ryml::substr buf, vec2< T > v)
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.
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...
std::enable_if< std::is_floating_point< T >::value, bool >::type read(Tree const *tree, id_type id, T *v)
convert the val of a scalar node to a floating point type, by forwarding its val to from_chars_float<...
std::enable_if< std::is_floating_point< T >::value, bool >::type readkey(Tree const *tree, id_type id, T *v)
convert the key of a scalar node to a floating point type, by forwarding its key to from_chars_float<...
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 a Tree.
lookup_result(csubstr path_, id_type start)