rapidyaml 0.15.2
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
node.hpp
Go to the documentation of this file.
1#ifndef C4_YML_NODE_HPP_
2#define C4_YML_NODE_HPP_
3
4/** @file node.hpp Node classes */
5
6#ifndef C4_YML_TREE_HPP_
7#include "c4/yml/tree.hpp"
8#endif
9
10C4_SUPPRESS_WARNING_PUSH
11C4_SUPPRESS_WARNING_GCC_CLANG("-Wtype-limits")
12C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
13C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
14C4_SUPPRESS_WARNING_CLANG("-Wnull-dereference")
15#if defined(__GNUC__) && __GNUC__ >= 6
16C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
17#endif
18C4_SUPPRESS_WARNING_MSVC(4251/*needs to have dll-interface to be used by clients of struct*/)
19C4_SUPPRESS_WARNING_MSVC(4296/*expression is always 'boolean_value'*/)
20C4_SUPPRESS_WARNING_MSVC(4996/*deprecated*/)
21// NOLINTBEGIN(modernize-avoid-c-style-cast)
22
23
24namespace c4 {
25namespace yml {
26
27/** @cond dev */
28#ifndef __DOXYGEN__
29// forward decls
30class NodeRef;
31class ConstNodeRef;
32template<class T> ReadResult read(ConstNodeRef const& C4_RESTRICT n, T *v);
33template<class T> ReadResult read_key(ConstNodeRef const& C4_RESTRICT n, T *v);
34template<class T> void write(NodeRef *n, T const& v);
35template<class T> void write(NodeRef &n, T const& v);
36template<class T> void write_key(NodeRef *n, T const& v);
37template<class T> void write_key(NodeRef &n, T const& v);
38#endif
39
40namespace detail {
41
42template<class NodeRefType>
43struct child_iterator
44{
45 using value_type = NodeRefType;
46 using tree_type = typename NodeRefType::tree_type;
47 tree_type * C4_RESTRICT m_tree;
48 id_type m_child_id;
49 child_iterator(tree_type * t, id_type id) noexcept : m_tree(t), m_child_id(id) {}
50 child_iterator& operator++ () RYML_NOEXCEPT { RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_child_id != NONE, m_tree, NONE); m_child_id = m_tree->next_sibling(m_child_id); return *this; }
51 NodeRefType operator* () const RYML_NOEXCEPT { return NodeRefType(m_tree, m_child_id); }
52 bool operator!= (child_iterator that) const RYML_NOEXCEPT { RYML_ASSERT_VISIT_(m_tree == that.m_tree, m_tree, NONE); return m_child_id != that.m_child_id; }
53};
54
55template<class NodeRefType>
56struct children_view
57{
58 using iterator = child_iterator<NodeRefType>;
59 using tree_type = typename NodeRefType::tree_type;
60 tree_type *tree;
61 id_type b, e;
62 children_view(tree_type *t, id_type b_, id_type e_) noexcept : tree(t), b(b_), e(e_) {}
63 C4_ALWAYS_INLINE iterator begin() const noexcept { return {tree, b}; }
64 C4_ALWAYS_INLINE iterator end () const noexcept { return {tree, e}; }
65};
66
67template<class ViewType, class TreeType>
68static ViewType make_children_view(TreeType *C4_RESTRICT tree, id_type id) RYML_NOEXCEPT
69{
70 return ViewType(tree, tree->get(id)->m_first_child, NONE);
71}
72
73template<class ViewType, class TreeType>
74static ViewType make_siblings_view(TreeType *C4_RESTRICT tree, id_type id) RYML_NOEXCEPT
75{
76 NodeData const *nd = tree->get(id);
77 id_type first = (nd->m_parent != NONE) ? tree->get(nd->m_parent)->m_first_child : NONE;
78 return ViewType(tree, first, NONE);
79}
80
81
82// LCOV_EXCL_START
83template<class NodeRefType, class Visitor>
84RYML_DEPRECATED("") bool _visit(NodeRefType &node, Visitor fn, id_type indentation_level, bool skip_root=false)
85{
86 id_type increment = 0;
87 if( ! (node.is_root() && skip_root))
88 {
89 if(fn(node, indentation_level))
90 return true;
91 ++increment;
92 }
93 if(node.has_children())
94 {
95 for(auto ch : node.children())
96 {
97 if(_visit(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
98 {
99 return true;
100 }
101 }
102 }
103 return false;
104}
105
106template<class NodeRefType, class Visitor>
107RYML_DEPRECATED("") bool _visit_stacked(NodeRefType &node, Visitor fn, id_type indentation_level, bool skip_root=false)
108{
109 id_type increment = 0;
110 if( ! (node.is_root() && skip_root))
111 {
112 if(fn(node, indentation_level))
113 {
114 return true;
115 }
116 ++increment;
117 }
118 if(node.has_children())
119 {
120 fn.push(node, indentation_level);
121 for(auto ch : node.children())
122 {
123 if(_visit_stacked(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
124 {
125 fn.pop(node, indentation_level);
126 return true;
127 }
128 }
129 fn.pop(node, indentation_level);
130 }
131 return false;
132}
133// LCOV_EXCL_STOP
134
135} // detail
136/** @endcond */
137
138
139//-----------------------------------------------------------------------------
140//-----------------------------------------------------------------------------
141//-----------------------------------------------------------------------------
142
143/** @addtogroup doc_node_classes
144 *
145 * @{
146 */
147
148
149namespace detail {
150/** a CRTP base providing read-only methods for @ref ConstNodeRef and @ref NodeRef */
151template<class Impl, class ConstImpl>
152struct RoNodeMethods // NOLINT
153{
154 /** @cond dev */
155 // CRTP helper macros, undefined at the end
156 #define mtree_ ((Impl const* C4_RESTRICT)this)->m_tree
157 #define tree_ ((ConstImpl const* C4_RESTRICT)this)->m_tree
158 #define id_ ((ConstImpl const* C4_RESTRICT)this)->m_id
159 #define this_ ((Impl const* C4_RESTRICT)this)
160 #define this_assert_readable_() ((Impl const* C4_RESTRICT)this)->assert_readable_()
161 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wcast-align") // the leading members are aligned
162 /** @endcond */
163
164public:
165
166 /** @name node property getters */
167 /** @{ */
168
169 // vertically aligned to highlight differences.
170 // documentation to the right -->
171
172 C4_ALWAYS_INLINE NodeType type() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->type(id_); } /**< Forward to @ref Tree::type(). Node must be readable. */
173
174 C4_ALWAYS_INLINE csubstr key() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->key(id_); } /**< Forward to @ref Tree::key(). Node must be readable. */
175 C4_ALWAYS_INLINE csubstr key_tag() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->key_tag(id_); } /**< Forward to @ref Tree::key_tag(). Node must be readable. */
176 C4_ALWAYS_INLINE csubstr key_ref() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->key_ref(id_); } /**< Forward to @ref Tree::key_ref(). Node must be readable. */
177 C4_ALWAYS_INLINE csubstr key_anchor() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->key_anchor(id_); } /**< Forward to @ref Tree::key_anchor(). Node must be readable. */
178
179 C4_ALWAYS_INLINE csubstr val() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->val(id_); } /**< Forward to @ref Tree::val(). Node must be readable. */
180 C4_ALWAYS_INLINE csubstr val_tag() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->val_tag(id_); } /**< Forward to @ref Tree::val_tag(). Node must be readable. */
181 C4_ALWAYS_INLINE csubstr val_ref() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->val_ref(id_); } /**< Forward to @ref Tree::val_ref(). Node must be readable. */
182 C4_ALWAYS_INLINE csubstr val_anchor() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->val_anchor(id_); } /**< Forward to @ref Tree::val_anchor(). Node must be readable. */
183
184 C4_ALWAYS_INLINE NodeScalar const& keysc() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->keysc(id_); } /**< Forward to @ref Tree::keysc(). Node must be readable. */
185 C4_ALWAYS_INLINE NodeScalar const& valsc() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->valsc(id_); } /**< Forward to @ref Tree::valsc(). Node must be readable. */
186
187 C4_ALWAYS_INLINE bool key_is_null() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->key_is_null(id_); } /**< Forward to @ref Tree::key_is_null(). Node must be readable. */
188 C4_ALWAYS_INLINE bool val_is_null() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->val_is_null(id_); } /**< Forward to @ref Tree::val_is_null(). Node must be readable. */
189
190 C4_ALWAYS_INLINE bool is_key_unfiltered() const noexcept { this_assert_readable_(); return tree_->is_key_unfiltered(id_); } /**< Forward to @ref Tree::is_key_unfiltered(). Node must be readable. */
191 C4_ALWAYS_INLINE bool is_val_unfiltered() const noexcept { this_assert_readable_(); return tree_->is_val_unfiltered(id_); } /**< Forward to @ref Tree::is_val_unfiltered(). Node must be readable. */
192
193 /** @} */
194
195public:
196
197 /** @name node type predicates */
198 /** @{ */
199
200 // vertically aligned to highlight differences.
201 // documentation to the right -->
202
203 C4_ALWAYS_INLINE bool empty() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->empty(id_); } /**< Forward to @ref Tree::empty(). Node must be readable. */
204 C4_ALWAYS_INLINE bool is_stream() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_stream(id_); } /**< Forward to @ref Tree::is_stream(). Node must be readable. */
205 C4_ALWAYS_INLINE bool is_doc() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_doc(id_); } /**< Forward to @ref Tree::is_doc(). Node must be readable. */
206 C4_ALWAYS_INLINE bool is_container() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_container(id_); } /**< Forward to @ref Tree::is_container(). Node must be readable. */
207 C4_ALWAYS_INLINE bool is_map() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_map(id_); } /**< Forward to @ref Tree::is_map(). Node must be readable. */
208 C4_ALWAYS_INLINE bool is_seq() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_seq(id_); } /**< Forward to @ref Tree::is_seq(). Node must be readable. */
209 C4_ALWAYS_INLINE bool has_val() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_val(id_); } /**< Forward to @ref Tree::has_val(). Node must be readable. */
210 C4_ALWAYS_INLINE bool has_key() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_key(id_); } /**< Forward to @ref Tree::has_key(). Node must be readable. */
211 C4_ALWAYS_INLINE bool is_val() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val(id_); } /**< Forward to @ref Tree::is_val(). Node must be readable. */
212 C4_ALWAYS_INLINE bool is_keyval() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_keyval(id_); } /**< Forward to @ref Tree::is_keyval(). Node must be readable. */
213 C4_ALWAYS_INLINE bool has_key_tag() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_key_tag(id_); } /**< Forward to @ref Tree::has_key_tag(). Node must be readable. */
214 C4_ALWAYS_INLINE bool has_val_tag() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_val_tag(id_); } /**< Forward to @ref Tree::has_val_tag(). Node must be readable. */
215 C4_ALWAYS_INLINE bool has_key_anchor() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_key_anchor(id_); } /**< Forward to @ref Tree::has_key_anchor(). Node must be readable. */
216 C4_ALWAYS_INLINE bool has_val_anchor() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_val_anchor(id_); } /**< Forward to @ref Tree::has_val_anchor(). Node must be readable. */
217 C4_ALWAYS_INLINE bool has_anchor() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_anchor(id_); } /**< Forward to @ref Tree::has_anchor(). Node must be readable. */
218 C4_ALWAYS_INLINE bool is_key_ref() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_ref(id_); } /**< Forward to @ref Tree::is_key_ref(). Node must be readable. */
219 C4_ALWAYS_INLINE bool is_val_ref() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_ref(id_); } /**< Forward to @ref Tree::is_val_ref(). Node must be readable. */
220 C4_ALWAYS_INLINE bool is_ref() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_ref(id_); } /**< Forward to @ref Tree::is_ref(). Node must be readable. */
221 C4_ALWAYS_INLINE bool parent_is_seq() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->parent_is_seq(id_); } /**< Forward to @ref Tree::parent_is_seq(). Node must be readable. */
222 C4_ALWAYS_INLINE bool parent_is_map() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->parent_is_map(id_); } /**< Forward to @ref Tree::parent_is_map(). Node must be readable. */
223
224 /** @} */
225
226public:
227
228 /** @name style predicates */
229 /** @{ */
230
231 // vertically aligned to highlight differences.
232 // documentation to the right -->
233
234 C4_ALWAYS_INLINE bool type_has_any(type_bits bits) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->type_has_any(id_, bits); } /**< Forward to @ref Tree::type_has_any(). Node must be readable. */
235 C4_ALWAYS_INLINE bool type_has_all(type_bits bits) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->type_has_all(id_, bits); } /**< Forward to @ref Tree::type_has_all(). Node must be readable. */
236 C4_ALWAYS_INLINE bool type_has_none(type_bits bits) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->type_has_none(id_, bits); } /**< Forward to @ref Tree::type_has_none(). Node must be readable. */
237
238 C4_ALWAYS_INLINE NodeType key_style() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->key_style(id_); } /**< Forward to @ref Tree::key_style(). Node must be readable. */
239 C4_ALWAYS_INLINE NodeType val_style() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->val_style(id_); } /**< Forward to @ref Tree::val_style(). Node must be readable. */
240
241 C4_ALWAYS_INLINE bool is_container_styled() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_container_styled(id_); } /**< Forward to @ref Tree::is_container_styled(). Node must be readable. */
242 C4_ALWAYS_INLINE bool is_block() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_block(id_); } /**< Forward to @ref Tree::is_block(). Node must be readable. */
243 C4_ALWAYS_INLINE bool is_flow() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_flow(id_); } /**< Forward to @ref Tree::is_flow(). Node must be readable. */
244 C4_ALWAYS_INLINE bool is_flow_sl() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_flow_sl(id_); } /**< Forward to @ref Tree::is_flow_sl(). Node must be readable. */
245 RYML_DEPRECATED("use one of .is_flow_ml{1,x,n}()")
246 C4_ALWAYS_INLINE bool is_flow_ml() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_flow_ml1(id_); } /**< Forward to @ref Tree::is_flow_ml1(). Node must be readable. */
247 C4_ALWAYS_INLINE bool is_flow_ml1() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_flow_ml1(id_); } /**< Forward to @ref Tree::is_flow_ml1(). Node must be readable. */
248 C4_ALWAYS_INLINE bool is_flow_mln() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_flow_mln(id_); } /**< Forward to @ref Tree::is_flow_mln(). Node must be readable. */
249 C4_ALWAYS_INLINE bool is_flow_mlx() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_flow_mlx(id_); } /**< Forward to @ref Tree::is_flow_mlx(). Node must be readable. */
250 C4_ALWAYS_INLINE bool has_flow_space() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_flow_space(id_); } /**< Forward to @ref Tree::has_flow_space(). Node must be readable. */
251
252 C4_ALWAYS_INLINE bool is_key_styled() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_styled(id_); } /**< Forward to @ref Tree::is_key_styled(). Node must be readable. */
253 C4_ALWAYS_INLINE bool is_val_styled() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_styled(id_); } /**< Forward to @ref Tree::is_val_styled(). Node must be readable. */
254 C4_ALWAYS_INLINE bool is_key_literal() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_literal(id_); } /**< Forward to @ref Tree::is_key_literal(). Node must be readable. */
255 C4_ALWAYS_INLINE bool is_val_literal() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_literal(id_); } /**< Forward to @ref Tree::is_val_literal(). Node must be readable. */
256 C4_ALWAYS_INLINE bool is_key_folded() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_folded(id_); } /**< Forward to @ref Tree::is_key_folded(). Node must be readable. */
257 C4_ALWAYS_INLINE bool is_val_folded() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_folded(id_); } /**< Forward to @ref Tree::is_val_folded(). Node must be readable. */
258 C4_ALWAYS_INLINE bool is_key_squo() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_squo(id_); } /**< Forward to @ref Tree::is_key_squo(). Node must be readable. */
259 C4_ALWAYS_INLINE bool is_val_squo() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_squo(id_); } /**< Forward to @ref Tree::is_val_squo(). Node must be readable. */
260 C4_ALWAYS_INLINE bool is_key_dquo() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_dquo(id_); } /**< Forward to @ref Tree::is_key_dquo(). Node must be readable. */
261 C4_ALWAYS_INLINE bool is_val_dquo() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_dquo(id_); } /**< Forward to @ref Tree::is_val_dquo(). Node must be readable. */
262 C4_ALWAYS_INLINE bool is_key_plain() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_plain(id_); } /**< Forward to @ref Tree::is_key_plain(). Node must be readable. */
263 C4_ALWAYS_INLINE bool is_val_plain() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_plain(id_); } /**< Forward to @ref Tree::is_val_plain(). Node must be readable. */
264 C4_ALWAYS_INLINE bool is_key_quoted() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_key_quoted(id_); } /**< Forward to @ref Tree::is_key_quoted(). Node must be readable. */
265 C4_ALWAYS_INLINE bool is_val_quoted() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_val_quoted(id_); } /**< Forward to @ref Tree::is_val_quoted(). Node must be readable. */
266 C4_ALWAYS_INLINE bool is_quoted() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_quoted(id_); } /**< Forward to @ref Tree::is_quoted(). Node must be readable. */
267
268 /** @} */
269
270public:
271
272 /** @name hierarchy predicates */
273 /** @{ */
274
275 // vertically aligned to highlight differences.
276 // documentation to the right -->
277
278 C4_ALWAYS_INLINE bool is_root() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_root(id_); } /**< Forward to @ref Tree::is_root(). Node must be readable. */
279 C4_ALWAYS_INLINE bool has_parent() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_parent(id_); } /**< Forward to @ref Tree::has_parent() Node must be readable. */
280 C4_ALWAYS_INLINE bool is_ancestor(ConstImpl const& ancestor) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->is_ancestor(id_, ancestor.m_id); } /**< Forward to @ref Tree::is_ancestor() Node must be readable. */
281
282 C4_ALWAYS_INLINE bool has_child(ConstImpl const& n) const RYML_NOEXCEPT { this_assert_readable_(); return n.readable() ? tree_->has_child(id_, n.m_id) : false; } /**< Forward to @ref Tree::has_child(). Node must be readable. */
283 C4_ALWAYS_INLINE bool has_child(id_type node) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_child(id_, node); } /**< Forward to @ref Tree::has_child(). Node must be readable. */
284 C4_ALWAYS_INLINE bool has_child(csubstr name) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_child(id_, name); } /**< Forward to @ref Tree::has_child(). Node must be readable. */
285 C4_ALWAYS_INLINE bool has_children() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_children(id_); } /**< Forward to @ref Tree::has_children(). Node must be readable. */
286
287 C4_ALWAYS_INLINE bool has_sibling(ConstImpl const& n) const RYML_NOEXCEPT { this_assert_readable_(); return n.readable() ? tree_->has_sibling(id_, n.m_id) : false; } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */
288 C4_ALWAYS_INLINE bool has_sibling(id_type node) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_sibling(id_, node); } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */
289 C4_ALWAYS_INLINE bool has_sibling(csubstr name) const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_sibling(id_, name); } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */
290 C4_ALWAYS_INLINE bool has_other_siblings() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_other_siblings(id_); } /**< Forward to @ref Tree::has_other_siblings(). Node must be readable. */
291
292 /** @} */
293
294public:
295
296 /** @name hierarchy getters */
297 /** @{ */
298
299 // vertically aligned to highlight differences.
300 // documentation to the right -->
301
302 C4_ALWAYS_INLINE id_type num_children() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->num_children(id_); } /**< O(num_children). Forward to @ref Tree::num_children(). */
303 C4_ALWAYS_INLINE id_type num_siblings() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->num_siblings(id_); } /**< O(num_children). Forward to @ref Tree::num_siblings(). */
304 C4_ALWAYS_INLINE id_type num_other_siblings() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->num_other_siblings(id_); } /**< O(num_siblings). Forward to @ref Tree::num_other_siblings(). */
305 C4_ALWAYS_INLINE id_type child_pos(ConstImpl const& n) const RYML_NOEXCEPT { this_assert_readable_(); RYML_ASSERT_VISIT_CB_(tree_->m_callbacks, n.readable(), n.tree(), n.id()); return tree_->child_pos(id_, n.m_id); } /**< O(num_children). Forward to @ref Tree::child_pos(). */
306 C4_ALWAYS_INLINE id_type sibling_pos(ConstImpl const& n) const RYML_NOEXCEPT { this_assert_readable_(); RYML_ASSERT_VISIT_CB_(tree_->callbacks(), n.readable(), n.tree(), n.id()); return tree_->child_pos(tree_->parent(id_), n.m_id); } /**< O(num_siblings). Forward to @ref Tree::sibling_pos(). */
307
308 C4_ALWAYS_INLINE id_type depth_asc() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->depth_asc(id_); } /** O(log(num_nodes)). Forward to Tree::depth_asc(). Node must be readable. */
309 C4_ALWAYS_INLINE id_type depth_desc() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->depth_desc(id_); } /** O(num_nodes). Forward to Tree::depth_desc(). Node must be readable. */
310
311 /** @} */
312
313public:
314
315 /** @name locations */
316 /** @{ */
317
318 Location location(Parser const& parser) const
319 {
320 this_assert_readable_();
321 return tree_->location(parser, id_);
322 }
323
324 /** @} */
325
326public:
327
328 /** @name deserialization: fully checked for lazy code
329 *
330 * These methods raise an error if the deserialization failed or
331 * optionally if the node is not readable.
332 *
333 */
334 /** @{ */
335
336 /** (1) deserialize the node's contents (val or container) to the
337 * given variable, forwarding to the user-overrideable @ref read()
338 * function, which can be for ConstNodeRef (see @ref
339 * doc_serialization_node_read) or for tree+id (see @ref
340 * doc_serialization_tree_read). This method differs from @ref
341 * ConstNodeRef::deserialize() in that here the error callback is
342 * called if the deserialization failed, or (optionally) the node
343 * is not readable. */
344 template<class T>
345 void load(T *v, bool check_readable=true) const
346 {
347 if(check_readable)
348 check_val_();
349 else
350 assert_val_(); // assert otherwise
351 // we can call read() directly because we checked everything
352 // (or the caller told us so)
353 // use the adapter ctor to accomodate legacy read() implementations
354 const ReadResult result(read((ConstImpl const&)*this, v), id_);
355 if C4_UNLIKELY(!result)
356 err_visit_(tree_, result.node, "could not deserialize node");
357 }
358 /** (2) like (1), but for wrapper tag types such as @ref
359 * c4::fmt::base64() */
360 template<class Wrapper>
361 void load(Wrapper const& wrapper, bool check_readable=true) const
362 {
363 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
364 if(check_readable)
365 check_val_();
366 else
367 assert_val_(); // assert otherwise
368 // we can call read() directly because we checked everything
369 // (or the caller told us so)
370 // use the adapter ctor to accomodate legacy read() implementations
371 const ReadResult result(read((ConstImpl const&)*this, wrapper), id_);
372 if C4_UNLIKELY(!result)
373 err_visit_(tree_, result.node, "could not deserialize node");
374 }
375
376 /** (1) deserialize the node's key (necessarily a scalar) to the
377 * given variable, forwarding to the user-overrideable @ref read_key()
378 * function, which can be for ConstNodeRef (see @ref
379 * doc_serialization_node_read) or for tree+id (see @ref
380 * doc_serialization_tree_read). This method differs from @ref
381 * ConstNodeRef::deserialize_key() in that here the error callback is
382 * called if the deserialization failed, or (optionally) the node
383 * is not readable. */
384 template<class T>
385 void load_key(T *k, bool check_readable=true) const
386 {
387 if(check_readable)
388 check_key_();
389 else
390 assert_key_(); // assert otherwise
391 // we can call read_key() directly because we checked
392 // everything (or the caller told us so)
393 // use the adapter ctor to accomodate legacy read_key() implementations
394 const ReadResult result(read_key((ConstImpl const&)*this, k), id_);
395 if C4_UNLIKELY(!result)
396 err_visit_(tree_, result.node, "could not deserialize key");
397 }
398 /** (2) like (1), but for wrapper tag types such as @ref
399 * c4::fmt::base64() */
400 template<class Wrapper>
401 void load_key(Wrapper const& wrapper, bool check_readable=true) const
402 {
403 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
404 if(check_readable)
405 check_key_();
406 else
407 assert_key_(); // assert otherwise
408 // we can call read_key() directly because we checked
409 // everything (or the caller told us so)
410 // use the adapter ctor to accomodate legacy read_key() implementations
411 const ReadResult result(read_key((ConstImpl const&)*this, wrapper), id_);
412 if C4_UNLIKELY(!result)
413 err_visit_(tree_, result.node, "could not deserialize key");
414 }
415
416 /** @} */
417
418public:
419
420 /** @name deserialization: asserts node readability, returns success status */
421 /** @{ */
422
423 /** (1) deserialize the node's contents (val or container) to the
424 * given variable, forwarding to the user-overrideable @ref read()
425 * function (see @ref doc_serialization_node_read).
426 * @return a @ref ReadResult with the deserialization status. */
427 template<class T>
428 C4_NODISCARD ReadResult deserialize(T *v) const
429 {
430 assert_val_();
431 // use the adapter ctor to accomodate legacy read() implementations
432 return ReadResult(read((ConstImpl const&)*this, v), id_);
433 }
434 /** (2) like (1), but for wrapper tag types such as @ref
435 * c4::fmt::base64() */
436 template<class Wrapper>
437 C4_NODISCARD ReadResult deserialize(Wrapper const& wrapper) const
438 {
439 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
440 assert_val_();
441 // use the adapter ctor to accomodate legacy read() implementations
442 return ReadResult(read((ConstImpl const&)*this, wrapper), id_);
443 }
444
445 /** (1) deserialize the node's key (necessarily a scalar) to the
446 * given variable, forwarding to the user-overrideable @ref
447 * read_key() function (see @ref doc_serialization_node_read).
448 *
449 * @return a @ref ReadResult with the deserialization status. */
450 template<class T>
451 C4_NODISCARD ReadResult deserialize_key(T *v) const
452 {
453 assert_key_();
454 // use the adapter ctor to accomodate legacy read_key() implementations
455 return ReadResult(read_key((ConstImpl const&)*this, v), id_);
456 }
457 /** (2) like (1), but for wrapper tag types such as @ref
458 * c4::fmt::base64() */
459 template<class Wrapper>
460 C4_NODISCARD ReadResult deserialize_key(Wrapper const& wrapper) const
461 {
462 RYML_CHECK_TYPE_IS_WRAPPER_LIKE_(Wrapper);
463 assert_key_();
464 // use the adapter ctor to accomodate legacy read_key() implementations
465 return ReadResult(read_key((ConstImpl const&)*this, wrapper), id_);
466 }
467
468 /** @} */
469
470public:
471
472 /** @name lookup and deserialize */
473 /** @{ */
474
475 /** (1) find a child by name and deserialize its contents to the
476 * given variable (ie call .deserialize() on the child if it
477 * exists). Otherwise, the variable is kept unchanged.
478 *
479 * @return a @ref ReadResult set with this node's id if no child
480 * exists, or the ReadResult from the deserialization.
481 *
482 * @see see also @ref ConstNodeRef::find_child_r()
483 */
484 template<class T>
485 C4_NODISCARD C4_ALWAYS_INLINE ReadResult deserialize_child(csubstr child_key, T *v) const
486 {
487 this_assert_readable_();
488 ConstImpl ch;
489 ReadResult r = this_->find_child_r(child_key, &ch);
490 if(r)
491 r = ch.deserialize(v);
492 return r;
493 }
494 /** (2) like (1), but assign from fallback if no such child exists. */
495 template<class T>
496 C4_NODISCARD C4_ALWAYS_INLINE ReadResult deserialize_child(csubstr child_key, T *v, T const& fallback) const
497 {
498 this_assert_readable_();
499 ConstImpl ch;
500 if(this_->find_child_r(child_key, &ch))
501 return ch.deserialize(v);
502 *v = fallback;
503 return ReadResult();
504 }
505 /** (3) like (1), but for wrapper tag types such as @ref c4::fmt::base64() */
506 template<class Wrapper>
507 C4_NODISCARD C4_ALWAYS_INLINE ReadResult deserialize_child(csubstr child_key, Wrapper const& v) const
508 {
509 this_assert_readable_();
510 ConstImpl ch;
511 ReadResult r = this_->find_child_r(child_key, &ch);
512 if(r)
513 r = ch.deserialize(v);
514 return r;
515 }
516
517 /** (1) find a child by position and deserialize its contents to
518 * the given variable (ie call .deserialize() on the child if it
519 * exists). Otherwise, the variable is kept unchanged.
520 *
521 * @return a @ref ReadResult set with this node's id if no child
522 * exists, or the ReadResult from the deserialization.
523 *
524 * @see see also @ref ConstNodeRef::child_r() */
525 template<class T>
526 C4_NODISCARD C4_ALWAYS_INLINE ReadResult deserialize_child(id_type child_pos, T *v) const
527 {
528 this_assert_readable_();
529 ConstImpl ch;
530 ReadResult r = this_->child_r(child_pos, &ch);
531 if(r)
532 r = ch.deserialize(v);
533 return r;
534 }
535 /** (2) like (1), but assign from fallback if no such child exists */
536 template<class T>
537 C4_NODISCARD C4_ALWAYS_INLINE ReadResult deserialize_child(id_type child_pos, T *v, T const& fallback) const
538 {
539 this_assert_readable_();
540 ConstImpl ch;
541 if(this_->child_r(child_pos, &ch))
542 return ch.deserialize(v);
543 *v = fallback;
544 return ReadResult();
545 }
546 /** (3) like (1), but for wrapper tag types such as @ref
547 * c4::fmt::base64() */
548 template<class Wrapper>
549 C4_NODISCARD C4_ALWAYS_INLINE ReadResult deserialize_child(id_type child_pos, Wrapper const& wrapper) const
550 {
551 this_assert_readable_();
552 ConstImpl ch;
553 ReadResult r = this_->child_r(child_pos, &ch);
554 if(r)
555 r = ch.deserialize(wrapper);
556 return r;
557 }
558
559 /** @} */
560
561public:
562
563 C4_SUPPRESS_WARNING_PUSH
564 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated")
565 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated-declarations")
566 C4_SUPPRESS_WARNING_MSVC(4996) // deprecated
567
568 /** @name legacy operators */
569 /** @{ */
570
571 template<class T>
572 RYML_LEGACY_OPERATOR("use .load()")
573 Impl const& operator>> (T &v) const { load(&v); return (Impl const&)*this; }
574
575 template<class T>
576 RYML_LEGACY_OPERATOR("use .load()")
577 Impl const& operator>> (T const& wrapper) const { load(wrapper); return (Impl const&)*this; }
578
579 template<class T>
580 RYML_LEGACY_OPERATOR("use .load_key()")
581 Impl const& operator>> (Key<T> const& v) const { load_key(&v.k); return (Impl const&)*this; }
582
583 /** @} */
584
585 C4_SUPPRESS_WARNING_POP
586
587protected: // error helpers
588
589 void check_val_() const
590 {
591 if C4_UNLIKELY(!tree_)
592 err_basic_("node not readable");
593 else if C4_UNLIKELY(!(((Impl const* C4_RESTRICT)this)->readable()))
594 err_visit_(tree_, id_, "node not readable");
595 else if C4_UNLIKELY(!(tree_->type(id_) & (VAL|MAP|SEQ)))
596 err_visit_(tree_, id_, "node has no contents");
597 }
598 void check_key_() const
599 {
600 if C4_UNLIKELY(!tree_)
601 err_basic_("node not readable");
602 else if C4_UNLIKELY(!(((Impl const* C4_RESTRICT)this)->readable()))
603 err_visit_(tree_, id_, "node not readable");
604 else if C4_UNLIKELY(!(tree_->type(id_) & KEY))
605 err_visit_(tree_, id_, "node has no key");
606 }
607
608 C4_NORETURN C4_NO_INLINE C4_COLD
609 static void err_basic_(const char *msg)
610 {
611 RYML_ERR_BASIC_(msg);
612 }
613
614 C4_NORETURN C4_NO_INLINE C4_COLD
615 static void err_visit_(Tree const *tree, id_type id, const char *msg)
616 {
617 RYML_ERR_VISIT_CB_(tree->m_callbacks, tree, id, msg);
618 }
619
620 #if RYML_USE_ASSERT
621 void assert_val_() const { check_val_(); }
622 void assert_key_() const { check_key_(); }
623 #else
624 C4_ALWAYS_INLINE void assert_val_() const noexcept {}
625 C4_ALWAYS_INLINE void assert_key_() const noexcept {}
626 #endif
627
628public: // deprecated functions
629
630 // these functions will be removed in future releases. If you
631 // disagree with a particular function being deprecated, let us
632 // know by opening a new issue at https://github.com/biojppm/rapidyaml/issues
633
634 /** @cond dev */ // LCOV_EXCL_START
635 C4_SUPPRESS_WARNING_PUSH
636 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated")
637 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated-declarations")
638 C4_SUPPRESS_WARNING_MSVC(4996) // deprecated
639 RYML_DEPRECATED("use .type().type_str(buf)") const char* type_str() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->type_str(id_); } /**< Forward to @ref Tree::type_str(). Node must be readable. */
640 RYML_DEPRECATED("use has_other_siblings()") bool has_siblings() const RYML_NOEXCEPT { this_assert_readable_(); return tree_->has_siblings(id_); }
641 RYML_DEPRECATED("use has_key_anchor()") bool is_key_anchor() const noexcept { this_assert_readable_(); return tree_->has_key_anchor(id_); }
642 RYML_DEPRECATED("use has_val_anchor()") bool is_val_hanchor() const noexcept { this_assert_readable_(); return tree_->has_val_anchor(id_); }
643 RYML_DEPRECATED("use has_anchor()") bool is_anchor() const noexcept { this_assert_readable_(); return tree_->has_anchor(id_); }
644 RYML_DEPRECATED("use has_anchor() || is_ref()") bool is_anchor_or_ref() const noexcept { this_assert_readable_(); return tree_->is_anchor_or_ref(id_); }
645 template<class T>
646 RYML_DEPRECATED("use .deserialize_child()") bool get_if(csubstr name, T *var) const
647 {
648 this_assert_readable_();
649 ConstImpl ch = ((ConstImpl const*)this)->find_child(name);
650 if(ch.readable())
651 {
652 ch.load(var);
653 return true;
654 }
655 return false;
656 }
657 template<class T>
658 RYML_DEPRECATED("use .deserialize_child()") bool get_if(id_type pos, T *var) const
659 {
660 this_assert_readable_();
661 ConstImpl ch = ((ConstImpl const*)this)->child(pos);
662 if(ch.readable())
663 {
664 ch.load(var);
665 return true;
666 }
667 return false;
668 }
669 template<class T>
670 RYML_DEPRECATED("use .deserialize_child()")
671 bool get_if(csubstr name, T *var, T const& fallback) const
672 {
673 if(get_if(name, var))
674 return true;
675 *var = fallback;
676 return false;
677 }
678 template<class T>
679 RYML_DEPRECATED("use .deserialize_child()")
680 bool get_if(id_type pos, T *var, T const& fallback) const
681 {
682 if(get_if(pos, var))
683 return true;
684 *var = fallback;
685 return false;
686 }
687 template<class Visitor>
688 RYML_DEPRECATED("") bool visit(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT
689 {
690 this_assert_readable_();
691 return detail::_visit(*(ConstImpl const*)this, fn, indentation_level, skip_root);
692 }
693 template <class Visitor, class U = Impl>
694 RYML_DEPRECATED("")
695 auto visit(Visitor fn, id_type indentation_level = 0, bool skip_root = true) RYML_NOEXCEPT
696 -> typename std ::enable_if<!std ::is_same<U, ConstImpl>::value, bool>::type
697 {
698 this_assert_readable_();
699 return detail::_visit(*(Impl *)this, fn, indentation_level, skip_root);
700 }
701 template<class Visitor>
702 RYML_DEPRECATED("") bool visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT
703 {
704 this_assert_readable_();
705 return detail::_visit_stacked(*(ConstImpl const*)this, fn, indentation_level, skip_root);
706 }
707 template<class Visitor, class U=Impl>
708 RYML_DEPRECATED("") auto visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) RYML_NOEXCEPT
709 -> typename std ::enable_if<!std ::is_same<U, ConstImpl>::value, bool>::type
710 {
711 this_assert_readable_();
712 return detail::_visit_stacked(*(Impl*)this, fn, indentation_level, skip_root);
713 }
714 /** @endcond */ // LCOV_EXCL_STOP
715 C4_SUPPRESS_WARNING_POP
716
717 #undef this_assert_readable_
718 #undef this_
719 #undef mtree_
720 #undef tree_
721 #undef id_
722
723 C4_SUPPRESS_WARNING_GCC_CLANG_POP
724};
725} // detail
726
727
728//-----------------------------------------------------------------------------
729//-----------------------------------------------------------------------------
730//-----------------------------------------------------------------------------
731/** Holds a pointer to an existing tree, and a node id. It can be used
732 * only to read from the tree.
733 *
734 * @warning The lifetime of the tree must be larger than that of this
735 * object. It is up to the user to ensure that this happens. */
736class RYML_EXPORT ConstNodeRef : public detail::RoNodeMethods<ConstNodeRef, ConstNodeRef> // NOLINT
737{
738public:
739
740 using tree_type = Tree const;
741
742public:
743
744 Tree const* C4_RESTRICT m_tree;
746
747private:
748
749 friend NodeRef;
751
752public:
753
754 /** @name construction */
755 /** @{ */
756
757 ConstNodeRef() noexcept : m_tree(nullptr), m_id(NONE) {}
758 ConstNodeRef(Tree const &t) noexcept : m_tree(&t), m_id(t .root_id()) {}
759 ConstNodeRef(Tree const *t) noexcept : m_tree(t ), m_id(t->root_id()) {}
760 ConstNodeRef(Tree const *t, id_type id) noexcept : m_tree(t), m_id(id) {}
761
762 ConstNodeRef(ConstNodeRef const&) noexcept = default;
763 ConstNodeRef(ConstNodeRef &&) noexcept = default;
764
765 inline ConstNodeRef(NodeRef const&) noexcept;
766 inline ConstNodeRef(NodeRef &&) noexcept;
767
768 /** @} */
769
770public:
771
772 /** @name assignment */
773 /** @{ */
774
775 ConstNodeRef& operator= (ConstNodeRef const&) noexcept = default;
776 ConstNodeRef& operator= (ConstNodeRef &&) noexcept = default;
777
778 ConstNodeRef& operator= (NodeRef const&) noexcept;
779 ConstNodeRef& operator= (NodeRef &&) noexcept;
780
781 /** @} */
782
783public:
784
785 /** @name state queries
786 *
787 * see @ref NodeRef for an explanation on what these states mean */
788 /** @{ */
789
790 C4_ALWAYS_INLINE bool invalid() const noexcept { return (!m_tree) || (m_id == NONE); }
791 /** because a ConstNodeRef cannot be used to write to the tree,
792 * readable() has the same meaning as !invalid() */
793 C4_ALWAYS_INLINE bool readable() const noexcept { return m_tree != nullptr && m_id != NONE; }
794 /** because a ConstNodeRef cannot be used to write to the tree, it can never be a seed.
795 * This method is provided for API equivalence between ConstNodeRef and NodeRef. */
796 constexpr static C4_ALWAYS_INLINE bool is_seed() noexcept { return false; }
797
798 /** @} */
799
800private:
801
802 void assert_readable_() const
803 {
804 RYML_ASSERT_BASIC_(m_tree != nullptr);
805 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_id != NONE && (m_id < m_tree->capacity()), m_tree, m_id);
806 }
807
808 void check_readable_() const
809 {
810 if C4_UNLIKELY(!m_tree)
811 RYML_ERR_BASIC_("invalid node");
812 if C4_UNLIKELY(!m_tree || m_id == NONE || (m_id > m_tree->capacity()))
813 RYML_ERR_VISIT_CB_(m_tree->m_callbacks, m_tree, m_id, "invalid node");
814 }
815
816public:
817
818 /** @name member getters */
819 /** @{ */
820
821 C4_ALWAYS_INLINE Tree const* tree() const noexcept { return m_tree; }
822 C4_ALWAYS_INLINE id_type id() const noexcept { return m_id; }
823
824 /** @} */
825
826public:
827
828 /** @name comparisons */
829 /** @{ */
830
831 C4_ALWAYS_INLINE bool operator== (ConstNodeRef const& that) const RYML_NOEXCEPT { return that.m_tree == m_tree && m_id == that.m_id; }
832 C4_ALWAYS_INLINE bool operator!= (ConstNodeRef const& that) const RYML_NOEXCEPT { return ! this->operator== (that); }
833
834 /** @} */
835
836public:
837
838 /** @name node property getters */
839 /** @{ */
840
841 C4_ALWAYS_INLINE NodeData const* get() const RYML_NOEXCEPT { return readable() ? m_tree->get(m_id) : nullptr; } /**< Forward to @ref Tree::type(). Node must be readable. */
842
843 /** @} */
844
845public:
846
847 /** @name hierarchy getters */
848 /** @{ */
849
850 // vertically aligned to highlight differences.
851 // documentation to the right -->
852
853 C4_ALWAYS_INLINE ConstNodeRef parent() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->parent(m_id)}; } /**< Forward to @ref Tree::parent(). Node must be readable. */
854 C4_ALWAYS_INLINE ConstNodeRef first_child() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->first_child(m_id)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */
855 C4_ALWAYS_INLINE ConstNodeRef last_child() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->last_child (m_id)}; } /**< Forward to @ref Tree::last_child(). Node must be readable. */
856 C4_ALWAYS_INLINE ConstNodeRef child(id_type pos) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->child(m_id, pos)}; } /**< Forward to @ref Tree::child(). Node must be readable. */
857 C4_ALWAYS_INLINE ConstNodeRef find_child(csubstr name) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->find_child(m_id, name)}; } /**< Forward to @ref Tree::find_child(). Node must be readable. */
858 C4_ALWAYS_INLINE ConstNodeRef prev_sibling() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->prev_sibling(m_id)}; } /**< Forward to @ref Tree::prev_sibling(). Node must be readable. */
859 C4_ALWAYS_INLINE ConstNodeRef next_sibling() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->next_sibling(m_id)}; } /**< Forward to @ref Tree::next_sibling(). Node must be readable. */
860 C4_ALWAYS_INLINE ConstNodeRef first_sibling() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->first_sibling(m_id)}; } /**< Forward to @ref Tree::first_sibling(). Node must be readable. */
861 C4_ALWAYS_INLINE ConstNodeRef last_sibling () const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->last_sibling(m_id)}; } /**< Forward to @ref Tree::last_sibling(). Node must be readable. */
862 C4_ALWAYS_INLINE ConstNodeRef sibling(id_type pos) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->sibling(m_id, pos)}; } /**< Forward to @ref Tree::sibling(). Node must be readable. */
863 C4_ALWAYS_INLINE ConstNodeRef find_sibling(csubstr name) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->find_sibling(m_id, name)}; } /**< Forward to @ref Tree::find_sibling(). Node must be readable. */
864 C4_ALWAYS_INLINE ConstNodeRef ancestor_doc() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->ancestor_doc(m_id)}; } /**< Forward to @ref Tree::ancestor_doc(). Node must be readable. */
865 C4_ALWAYS_INLINE ConstNodeRef doc(id_type i) const RYML_NOEXCEPT { RYML_ASSERT_BASIC_(m_tree); return {m_tree, m_tree->doc(i)}; } /**< Forward to @ref Tree::doc(). Node must be readable. succeeds even when the node may have invalid or seed id */
866
867 C4_NODISCARD C4_ALWAYS_INLINE ReadResult child_r(id_type pos, ConstNodeRef *child) const RYML_NOEXCEPT { assert_readable_(); child->m_tree = m_tree; ReadResult result = m_tree-> child_r(m_id, pos, &child->m_id); return result; }; /**< Forward to @ref Tree::child_r(). Node must be readable. */
868 C4_NODISCARD C4_ALWAYS_INLINE ReadResult find_child_r(csubstr name, ConstNodeRef *child) const RYML_NOEXCEPT { assert_readable_(); child->m_tree = m_tree; ReadResult result = m_tree->find_child_r(m_id, name, &child->m_id); return result; }; /**< Forward to @ref Tree::find_child_r(). Node must be readable. */
869
870 C4_NODISCARD C4_ALWAYS_INLINE ReadResult sibling_r(id_type pos, ConstNodeRef *sibling) const RYML_NOEXCEPT { assert_readable_(); sibling->m_tree = m_tree; ReadResult result = m_tree-> sibling_r(m_id, pos, &sibling->m_id); return result; }; /**< Forward to @ref Tree::sibling_r(). Node must be readable. */
871 C4_NODISCARD C4_ALWAYS_INLINE ReadResult find_sibling_r(csubstr name, ConstNodeRef *sibling) const RYML_NOEXCEPT { assert_readable_(); sibling->m_tree = m_tree; ReadResult result = m_tree->find_sibling_r(m_id, name, &sibling->m_id); return result; }; /**< Forward to @ref Tree::find_sibling_r(). Node must be readable. */
872
873 /** @} */
874
875public:
876
877 /** @name square_brackets
878 * operator[] */
879 /** @{ */
880
881 /** Find a child by key; complexity is O(num_children).
882 *
883 * Behaves similar to the non-const overload, but further asserts
884 * that the returned node is readable (because it can never be in
885 * a seed state). The assertion is performed only if @ref
886 * RYML_USE_ASSERT is set to true. As with the non-const overload,
887 * it is UB to use the return value if it is not valid.
888 *
889 * @see https://github.com/biojppm/rapidyaml/issues/389 */
890 C4_ALWAYS_INLINE ConstNodeRef operator[] (csubstr key) const RYML_NOEXCEPT
891 {
892 assert_readable_();
893 id_type ch = m_tree->find_child(m_id, key);
894 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
895 return {m_tree, ch};
896 }
897
898 /** Find a child by position; complexity is O(pos).
899 *
900 * Behaves similar to the non-const overload, but further asserts
901 * that the returned node is readable (because it can never be in
902 * a seed state). This assertion is performed only if @ref
903 * RYML_USE_ASSERT is set to true. As with the non-const overload,
904 * it is UB to use the return value if it is not valid.
905 *
906 * @see https://github.com/biojppm/rapidyaml/issues/389 */
907 C4_ALWAYS_INLINE ConstNodeRef operator[] (id_type pos) const RYML_NOEXCEPT
908 {
909 assert_readable_();
910 id_type ch = m_tree->child(m_id, pos);
911 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
912 return {m_tree, ch};
913 }
914
915 /** @} */
916
917public:
918
919 /** @name at
920 *
921 * These functions are the analogue to operator[], with the
922 * difference that they emit an error instead of an
923 * assertion. That is, if any of the pre or post conditions is
924 * violated, an error is always emitted (resulting in a call to
925 * the error callback).
926 *
927 * @{ */
928
929 /** Get a child by name, with error checking; complexity is
930 * O(num_children).
931 *
932 * Behaves as operator[](csubstr) const, but always raises an
933 * error (even when RYML_USE_ASSERT is set to false) when the
934 * returned node does not exist, or when this node is not
935 * readable, or when it is not a map. This behaviour is similar to
936 * std::vector::at(), but the error consists in calling the error
937 * callback instead of directly raising an exception. */
939 {
940 check_readable_();
941 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->is_map(m_id), m_tree, m_id);
942 id_type ch = m_tree->find_child(m_id, key);
943 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
944 return {m_tree, ch};
945 }
946
947 /** Get a child by position, with error checking; complexity is
948 * O(pos).
949 *
950 * Behaves as operator[](id_type) const, but always raises an error
951 * (even when RYML_USE_ASSERT is set to false) when the returned
952 * node does not exist, or when this node is not readable, or when
953 * it is not a container. This behaviour is similar to
954 * std::vector::at(), but the error consists in calling the error
955 * callback instead of directly raising an exception. */
957 {
958 check_readable_();
959 const id_type cap = m_tree->capacity();
960 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (pos >= 0 && pos < cap), m_tree, m_id);
961 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->is_container(m_id), m_tree, m_id);
962 const id_type ch = m_tree->child(m_id, pos);
963 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
964 return {m_tree, ch};
965 }
966
967 /** @} */
968
969public:
970
971 /** @name iteration */
972 /** @{ */
973
974 using iterator = detail::child_iterator<ConstNodeRef>;
975 using const_iterator = detail::child_iterator<ConstNodeRef>;
976 using children_view = detail::children_view<ConstNodeRef>;
977 using const_children_view = detail::children_view<ConstNodeRef>;
978
979
980 C4_ALWAYS_INLINE const_iterator begin() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, m_tree->first_child(m_id)); } /**< get an iterator to the first child */
981 C4_ALWAYS_INLINE const_iterator cbegin() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, m_tree->first_child(m_id)); } /**< get an iterator to the first child */
982
983 C4_ALWAYS_INLINE const_iterator end() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, NONE); } /**< get an iterator to after the last child */
984 C4_ALWAYS_INLINE const_iterator cend() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, NONE); } /**< get an iterator to after the last child */
985
986
987 C4_ALWAYS_INLINE const_children_view children() const RYML_NOEXCEPT { assert_readable_(); return detail::make_children_view<const_children_view>(m_tree, m_id); } /**< get an iterable view over children */
988 C4_ALWAYS_INLINE const_children_view cchildren() const RYML_NOEXCEPT { assert_readable_(); return detail::make_children_view<const_children_view>(m_tree, m_id); } /**< get an iterable view over children */
989
990 C4_ALWAYS_INLINE const_children_view siblings() const RYML_NOEXCEPT { assert_readable_(); return detail::make_siblings_view<const_children_view>(m_tree, m_id); } /** get an iterable view over all siblings (including the calling node) */
991 C4_ALWAYS_INLINE const_children_view csiblings() const RYML_NOEXCEPT { assert_readable_(); return detail::make_siblings_view<const_children_view>(m_tree, m_id); } /** get an iterable view over all siblings (including the calling node) */
992
993 /** @} */
994
995public: // deprecated functions
996
997 // these functions will be removed in future releases. If you
998 // disagree with a particular function being deprecated, let us
999 // know by opening a new issue at https://github.com/biojppm/rapidyaml/issues
1000
1001 /** @cond dev */ // LCOV_EXCL_START
1002 C4_SUPPRESS_WARNING_PUSH
1003 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated")
1004 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated-declarations")
1005 C4_SUPPRESS_WARNING_MSVC(4996) // deprecated
1006
1007 RYML_DEPRECATED("use ConstNodeRef()") ConstNodeRef(std::nullptr_t) noexcept : m_tree(nullptr), m_id(NONE) {}
1008 RYML_DEPRECATED("use node = {}") ConstNodeRef& operator= (std::nullptr_t) noexcept { m_tree = nullptr; m_id = NONE; return *this; }
1009
1010 RYML_DEPRECATED("use one of readable(), is_seed() or !invalid()") bool valid() const noexcept { return m_tree != nullptr && m_id != NONE; }
1011 RYML_DEPRECATED("use invalid()") bool operator== (std::nullptr_t) const noexcept { return m_tree == nullptr || m_id == NONE; }
1012 RYML_DEPRECATED("use !invalid()") bool operator!= (std::nullptr_t) const noexcept { return !(m_tree == nullptr || m_id == NONE); }
1013 RYML_DEPRECATED("use (this->val() == s)") bool operator== (csubstr s) const RYML_NOEXCEPT { RYML_ASSERT_BASIC_(m_tree); RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_id != NONE, m_tree, NONE); return m_tree->val(m_id) == s; }
1014 RYML_DEPRECATED("use (this->val() != s)") bool operator!= (csubstr s) const RYML_NOEXCEPT { RYML_ASSERT_BASIC_(m_tree); RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_id != NONE, m_tree, NONE); return m_tree->val(m_id) != s; }
1015 /** @endcond */ // LCOV_EXCL_STOP
1016
1017};
1018
1019
1020//-----------------------------------------------------------------------------
1021//-----------------------------------------------------------------------------
1022//-----------------------------------------------------------------------------
1023
1024// NOLINTBEGIN(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator)
1025
1026/** A reference to a node in an existing yaml tree, offering a more
1027 * convenient API than the index-based API used in the tree.
1028 *
1029 * Unlike its imutable ConstNodeRef peer, a NodeRef can be used to
1030 * mutate the tree, both by writing to existing nodes and by creating
1031 * new nodes to subsequently write to. Semantically, a NodeRef
1032 * object can be in one of three states:
1033 *
1034 * ```text
1035 * invalid := not pointing at anything
1036 * readable := points at an existing tree/node
1037 * seed := points at an existing tree, and the node
1038 * may come to exist, if we write to it.
1039 * ```
1040 *
1041 * So both `readable` and `seed` are states where the node is also `valid`.
1042 *
1043 * ```cpp
1044 * Tree t = parse_in_arena("{a: b}");
1045 * NodeRef invalid; // not pointing at anything.
1046 * NodeRef readable = t["a"]; // also valid, because "a" exists
1047 * NodeRef seed = t["none"]; // also valid, but is seed because "none" is not in the map
1048 * ```
1049 *
1050 * When the object is in seed state, using it to read from the tree is
1051 * UB. The seed node can be used to write to the tree, provided that
1052 * its create() method is called prior to writing, which happens in
1053 * most modifying methods in NodeRef.
1054 *
1055 * It is the owners's responsibility to verify that an existing
1056 * node is readable before subsequently using it to read from the
1057 * tree.
1058 *
1059 * @warning The lifetime of the tree must be larger than that of this
1060 * object. It is up to the user to ensure that this happens.
1061 */
1062class RYML_EXPORT NodeRef : public detail::RoNodeMethods<NodeRef, ConstNodeRef> // NOLINT
1063{
1064public:
1065
1068
1069private:
1070
1071 Tree *C4_RESTRICT m_tree;
1072 id_type m_id;
1073
1074 /** This member is used to enable lazy operator[] writing.
1075 *
1076 * When a child with a key or index is not found, m_id is set to
1077 * the id of the parent and the asked-for key or index are stored
1078 * in this member until a write does happen. Then it is given as
1079 * key or index for creating the child.
1080 *
1081 * When a key is used, the csubstr stores it (so the csubstr's
1082 * string is non-null and the csubstr's size is different from
1083 * NONE). When an index is used instead, the csubstr's string is
1084 * set to null, and only the csubstr's size is set to a value
1085 * different from NONE.
1086 *
1087 * Otherwise, when operator[] does find the child, then this member
1088 * is empty: m_seed.str is null and m_seed.len is NONE. */
1089 csubstr m_seed;
1090
1091 C4_ALWAYS_INLINE void _clear_seed() noexcept
1092 {
1093 // this must be done manually or an assert is triggered:
1094 m_seed.str = nullptr;
1095 m_seed.len = NONE;
1096 }
1097
1098 friend ConstNodeRef;
1099 friend struct detail::RoNodeMethods<NodeRef, ConstNodeRef>;
1100
1101public:
1102
1103 /** @name construction */
1104 /** @{ */
1105
1106 NodeRef() noexcept : m_tree(nullptr), m_id(NONE), m_seed() { _clear_seed(); }
1107 NodeRef(Tree &t) noexcept : m_tree(&t), m_id(t .root_id()), m_seed() { _clear_seed(); }
1108 NodeRef(Tree *t) noexcept : m_tree(t ), m_id(t->root_id()), m_seed() { _clear_seed(); }
1109 NodeRef(Tree *t, id_type id) noexcept : m_tree(t), m_id(id), m_seed() { _clear_seed(); }
1110 NodeRef(Tree *t, id_type id, id_type seed_pos) noexcept : m_tree(t), m_id(id), m_seed() { m_seed.str = nullptr; m_seed.len = (size_t)seed_pos; }
1111 NodeRef(Tree *t, id_type id, csubstr seed_key) noexcept : m_tree(t), m_id(id), m_seed(seed_key) {}
1112
1113 /** @} */
1114
1115public:
1116
1117 /** @name assignment */
1118 /** @{ */
1119
1120 NodeRef(NodeRef const&) noexcept = default;
1121 NodeRef(NodeRef &&) noexcept = default;
1122
1123 NodeRef& operator= (NodeRef const&) noexcept = default;
1124 NodeRef& operator= (NodeRef &&) noexcept = default;
1125
1126 /** @} */
1127
1128public:
1129
1130 /** @name state_queries
1131 * @{ */
1132
1133 /** true if the object is not referring to any existing or seed node. @see the doc for @ref NodeRef */
1134 bool invalid() const noexcept { return m_tree == nullptr || m_id == NONE; }
1135 /** true if the object is not invalid and in seed state. @see the doc for @ref NodeRef */
1136 bool is_seed() const noexcept { return (m_tree != nullptr && m_id != NONE) && has_seed_(); }
1137 /** true if the object is not invalid and not in seed state. @see the doc for @ref NodeRef */
1138 bool readable() const noexcept { return (m_tree != nullptr && m_id != NONE) && !has_seed_(); }
1139
1140 /** @} */
1141
1142private:
1143
1144 C4_ALWAYS_INLINE bool valid_id_() const noexcept { return m_id != NONE && m_id < m_tree->capacity(); }
1145 C4_ALWAYS_INLINE bool has_seed_() const noexcept { return m_seed.str != nullptr || m_seed.len != (size_t)NONE; }
1146
1147 void assert_readable_() const
1148 {
1149 RYML_ASSERT_BASIC_(m_tree != nullptr);
1150 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, valid_id_() && !has_seed_(), m_tree, m_id);
1151 }
1152
1153 void check_readable_() const
1154 {
1155 if C4_UNLIKELY(!m_tree)
1156 err_basic_("invalid node");
1157 if C4_UNLIKELY((m_id == NONE || (m_id > m_tree->capacity()) ||
1158 (m_seed.str != nullptr || m_seed.len != (size_t)NONE)))
1159 err_visit_(m_tree, m_id, "invalid node");
1160 }
1161
1162 void check_writeable_() const
1163 {
1164 if C4_UNLIKELY(!m_tree)
1165 err_basic_("invalid node");
1166 }
1167
1168 void assert_writeable_() const
1169 {
1170 RYML_ASSERT_BASIC_(m_tree != nullptr);
1171 }
1172
1173public:
1174
1175 /** @name comparisons */
1176 /** @{ */
1177
1178 bool operator== (NodeRef const& that) const
1179 {
1180 if(m_tree == that.m_tree && m_id == that.m_id)
1181 {
1182 bool seed = is_seed();
1183 if(seed == that.is_seed())
1184 {
1185 if(seed)
1186 {
1187 return (m_seed.len == that.m_seed.len)
1188 && (m_seed.str == that.m_seed.str
1189 || m_seed == that.m_seed); // do strcmp only in the last resort
1190 }
1191 return true;
1192 }
1193 }
1194 return false;
1195 }
1196 bool operator!= (NodeRef const& that) const { return ! this->operator==(that); }
1197
1198 bool operator== (ConstNodeRef const& that) const { return m_tree == that.m_tree && m_id == that.m_id && !is_seed(); }
1199 bool operator!= (ConstNodeRef const& that) const { return ! this->operator==(that); }
1200
1201 /** @} */
1202
1203public:
1204
1205 /** @name node_property_getters
1206 * @{ */
1207
1208 C4_ALWAYS_INLINE id_type id() const noexcept { return m_id; }
1209
1210 C4_ALWAYS_INLINE Tree const* tree() const noexcept { return m_tree; }
1211 C4_ALWAYS_INLINE Tree * tree() noexcept { return m_tree; }
1212
1213 C4_ALWAYS_INLINE NodeData const* get() const RYML_NOEXCEPT { return readable() ? m_tree->get(m_id) : nullptr; } /**< Forward to @ref Tree::type(). Node must be readable. */
1214 C4_ALWAYS_INLINE NodeData * get() RYML_NOEXCEPT { return readable() ? m_tree->get(m_id) : nullptr; } /**< Forward to @ref Tree::type(). Node must be readable. */
1215
1216 /** @} */
1217
1218
1219public:
1220
1221 /** @name node_setters */
1222 /** @{ */
1223
1224 /// if this node is in seed state, create the node in the tree
1225 void create()
1226 {
1227 RYML_ASSERT_BASIC_(m_tree != nullptr);
1228 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_id != NONE && m_id < m_tree->capacity(), m_tree, m_id);
1229 if(m_seed.str) // we have a seed key: use it to create the new map child
1230 {
1231 m_id = m_tree->append_child(m_id);
1232 m_tree->set_key(m_id, m_seed);
1233 m_seed.str = nullptr;
1234 m_seed.len = (size_t)NONE;
1235 }
1236 else if(m_seed.len != (size_t)NONE) // we have a seed index: create a seq child at that position
1237 {
1238 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, (size_t)m_tree->num_children(m_id) == m_seed.len, m_tree, m_id);
1239 m_id = m_tree->append_child(m_id);
1240 m_seed.str = nullptr;
1241 m_seed.len = (size_t)NONE;
1242 }
1243 }
1244
1245 void set_stream() { create(); m_tree->set_stream(m_id); }
1246 void set_doc() { create(); m_tree->set_doc(m_id); }
1247
1248 void set_key(csubstr key) { create(); m_tree->set_key(m_id, key); }
1249 void set_key(csubstr key, NodeType more_flags) { create(); m_tree->set_key(m_id, key, more_flags); }
1250
1251 void set_val(csubstr val) { create(); m_tree->set_val(m_id, val); }
1252 void set_val(csubstr val, NodeType more_flags) { create(); m_tree->set_val(m_id, val, more_flags); }
1253
1254 void set_seq() { create(); m_tree->set_seq(m_id); }
1255 void set_seq(NodeType more_flags) { create(); m_tree->set_seq(m_id, more_flags); }
1256
1257 void set_map() { create(); m_tree->set_map(m_id); }
1258 void set_map(NodeType more_flags) { create(); m_tree->set_map(m_id, more_flags); }
1259
1260 void set_key_tag(csubstr key_tag) { create(); m_tree->set_key_tag(m_id, key_tag); }
1261 void set_val_tag(csubstr val_tag) { create(); m_tree->set_val_tag(m_id, val_tag); }
1262 void set_key_anchor(csubstr key_anchor) { create(); m_tree->set_key_anchor(m_id, key_anchor); }
1263 void set_val_anchor(csubstr val_anchor) { create(); m_tree->set_val_anchor(m_id, val_anchor); }
1264 void set_key_ref(csubstr key_ref) { create(); m_tree->set_key_ref(m_id, key_ref); }
1265 void set_val_ref(csubstr val_ref) { create(); m_tree->set_val_ref(m_id, val_ref); }
1266
1267 void set_container_style(type_bits style) { create(); m_tree->set_container_style(m_id, style); }
1268 void set_key_style(type_bits style) { create(); m_tree->set_key_style(m_id, style); }
1269 void set_val_style(type_bits style) { create(); m_tree->set_val_style(m_id, style); }
1270
1271 /** @} */
1272
1273public:
1274
1275 /** @name node_modifiers */
1276 /** @{ */
1277
1279 {
1280 assert_readable_();
1281 m_tree->change_type(m_id, t);
1282 }
1283
1284 /** remove the KEY (flags included) from a scalar */
1286 {
1287 assert_readable_();
1288 m_tree->_clear_key(m_id);
1289 }
1290
1291 /** remove the VAL (flags included) from a scalar */
1293 {
1294 assert_readable_();
1295 m_tree->_clear_val(m_id);
1296 }
1297
1298 /** remove the children from a scalar */
1300 {
1301 assert_readable_();
1302 m_tree->remove_children(m_id);
1303 }
1304
1305 void clear_style(bool recurse=false)
1306 {
1307 assert_readable_();
1308 m_tree->clear_style(m_id, recurse);
1309 }
1310
1312 NodeType rem_style_flags,
1313 NodeType add_style_flags,
1314 bool recurse=false)
1315 {
1316 assert_readable_();
1317 m_tree->set_style_conditionally(m_id, type_mask, rem_style_flags, add_style_flags, recurse);
1318 }
1319
1320 /** @} */
1321
1322public:
1323
1324 /** @name serialization */
1325 /** @{ */
1326
1327 /** forward to @ref Tree::to_arena() . Serializes a scalar type to
1328 * the tree's arena. The type must be serializeable as a scalar. */
1329 template<class T>
1330 csubstr to_arena(T const& C4_RESTRICT s)
1331 {
1332 RYML_ASSERT_BASIC_(m_tree); // no need for valid or readable
1333 return m_tree->to_arena(s);
1334 }
1335
1336 template<class T>
1337 void save(T const& C4_RESTRICT k)
1338 {
1339 check_writeable_();
1340 create();
1341 write(*this, k);
1342 }
1343 template<class T>
1344 void save(T const& C4_RESTRICT k, NodeType style_flags)
1345 {
1346 check_writeable_();
1347 create();
1348 write(*this, k);
1349 RYML_ASSERT_BASIC_(!(style_flags & ~STYLE));
1350 _add_flags(style_flags);
1351 }
1352
1353 template<class T>
1354 void save_key(T const& C4_RESTRICT k)
1355 {
1356 check_writeable_();
1357 create();
1358 write_key(*this, k);
1359 }
1360 template<class T>
1361 void save_key(T const& C4_RESTRICT k, NodeType style_flags)
1362 {
1363 check_writeable_();
1364 create();
1365 write_key(*this, k);
1366 RYML_ASSERT_BASIC_(!(style_flags & ~STYLE));
1367 _add_flags(style_flags);
1368 }
1369
1370 /** serialize a variable to this node. If the variable is a
1371 * scalar, it is first serialized to the arena, and then assigned
1372 * to the node's val. Otherwise, the node will be made a
1373 * container, and its contents populated from the variable. */
1374 template<class T>
1375 void set_serialized(T const& C4_RESTRICT v)
1376 {
1377 assert_writeable_();
1378 create();
1379 write(*this, v);
1380 }
1381 template<class T>
1382 void set_serialized(T const& C4_RESTRICT v, NodeType style_flags)
1383 {
1384 assert_writeable_();
1385 create();
1386 write(*this, v);
1387 RYML_ASSERT_BASIC_(!(style_flags & ~STYLE));
1388 _add_flags(style_flags);
1389 }
1390
1391 /** serialize a variable, then assign the result to the node's key
1392 *
1393 * @warning The variable must be serialized as a scalar, ie it
1394 * cannot be serialized as a container. */
1395 template<class T>
1396 void set_key_serialized(T const& C4_RESTRICT k)
1397 {
1398 assert_writeable_();
1399 create();
1400 write_key(*this, k);
1401 }
1402 template<class T>
1403 void set_key_serialized(T const& C4_RESTRICT k, NodeType style_flags)
1404 {
1405 assert_writeable_();
1406 create();
1407 write_key(*this, k);
1408 RYML_ASSERT_BASIC_(!(style_flags & ~STYLE));
1409 _add_flags(style_flags);
1410 }
1411
1412 /** @} */
1413
1414public:
1415
1416 /** @name hierarchy getters */
1417 /** @{ */
1418
1419 // vertically aligned to highlight differences.
1420 // documentation to the right -->
1421
1422 C4_ALWAYS_INLINE NodeRef parent() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->parent(m_id)}; } /**< Forward to @ref Tree::parent(). Node must be readable. */
1423 C4_ALWAYS_INLINE ConstNodeRef parent() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->parent(m_id)}; } /**< Forward to @ref Tree::parent(). Node must be readable. */
1424
1425 C4_ALWAYS_INLINE NodeRef first_child() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->first_child(m_id)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */
1426 C4_ALWAYS_INLINE ConstNodeRef first_child() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->first_child(m_id)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */
1427
1428 C4_ALWAYS_INLINE NodeRef last_child() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->last_child(m_id)}; } /**< Forward to @ref Tree::last_child(). Node must be readable. */
1429 C4_ALWAYS_INLINE ConstNodeRef last_child() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->last_child (m_id)}; } /**< Forward to @ref Tree::last_child(). Node must be readable. */
1430
1431 C4_ALWAYS_INLINE NodeRef child(id_type pos) RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->child(m_id, pos)}; } /**< Forward to @ref Tree::child(). Node must be readable. */
1432 C4_ALWAYS_INLINE ConstNodeRef child(id_type pos) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->child(m_id, pos)}; } /**< Forward to @ref Tree::child(). Node must be readable. */
1433
1434 C4_NODISCARD C4_ALWAYS_INLINE ReadResult child_r(id_type pos, NodeRef *child) RYML_NOEXCEPT { assert_readable_(); child->m_tree = m_tree; ReadResult result = m_tree->child_r(m_id, pos, &child->m_id); return result; }; /**< Forward to @ref Tree::child_r(). Node must be readable. */
1435 C4_NODISCARD C4_ALWAYS_INLINE ReadResult child_r(id_type pos, ConstNodeRef *child) const RYML_NOEXCEPT { assert_readable_(); child->m_tree = m_tree; ReadResult result = m_tree->child_r(m_id, pos, &child->m_id); return result; }; /**< Forward to @ref Tree::child_r(). Node must be readable. */
1436
1437 C4_ALWAYS_INLINE NodeRef find_child(csubstr name) RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->find_child(m_id, name)}; } /**< Forward to @ref Tree::find_child(). Node must be readable. */
1438 C4_ALWAYS_INLINE ConstNodeRef find_child(csubstr name) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->find_child(m_id, name)}; } /**< Forward to @ref Tree::find_child(). Node must be readable. */
1439
1440 C4_NODISCARD C4_ALWAYS_INLINE ReadResult find_child_r(csubstr name, NodeRef *child) RYML_NOEXCEPT { assert_readable_(); child->m_tree = m_tree; ReadResult result = m_tree->find_child_r(m_id, name, &child->m_id); return result; }; /**< Forward to @ref Tree::find_child_r(). Node must be readable. */
1441 C4_NODISCARD C4_ALWAYS_INLINE ReadResult find_child_r(csubstr name, ConstNodeRef *child) const RYML_NOEXCEPT { assert_readable_(); child->m_tree = m_tree; ReadResult result = m_tree->find_child_r(m_id, name, &child->m_id); return result; }; /**< Forward to @ref Tree::find_child_r(). Node must be readable. */
1442
1443 C4_ALWAYS_INLINE NodeRef prev_sibling() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->prev_sibling(m_id)}; } /**< Forward to @ref Tree::prev_sibling(). Node must be readable. */
1444 C4_ALWAYS_INLINE ConstNodeRef prev_sibling() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->prev_sibling(m_id)}; } /**< Forward to @ref Tree::prev_sibling(). Node must be readable. */
1445
1446 C4_ALWAYS_INLINE NodeRef next_sibling() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->next_sibling(m_id)}; } /**< Forward to @ref Tree::next_sibling(). Node must be readable. */
1447 C4_ALWAYS_INLINE ConstNodeRef next_sibling() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->next_sibling(m_id)}; } /**< Forward to @ref Tree::next_sibling(). Node must be readable. */
1448
1449 C4_ALWAYS_INLINE NodeRef first_sibling() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->first_sibling(m_id)}; } /**< Forward to @ref Tree::first_sibling(). Node must be readable. */
1450 C4_ALWAYS_INLINE ConstNodeRef first_sibling() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->first_sibling(m_id)}; } /**< Forward to @ref Tree::first_sibling(). Node must be readable. */
1451
1452 C4_ALWAYS_INLINE NodeRef last_sibling() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->last_sibling(m_id)}; } /**< Forward to @ref Tree::last_sibling(). Node must be readable. */
1453 C4_ALWAYS_INLINE ConstNodeRef last_sibling() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->last_sibling(m_id)}; } /**< Forward to @ref Tree::last_sibling(). Node must be readable. */
1454
1455 C4_ALWAYS_INLINE NodeRef sibling(id_type pos) RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->sibling(m_id, pos)}; } /**< Forward to @ref Tree::sibling(). Node must be readable. */
1456 C4_ALWAYS_INLINE ConstNodeRef sibling(id_type pos) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->sibling(m_id, pos)}; } /**< Forward to @ref Tree::sibling(). Node must be readable. */
1457
1458 C4_ALWAYS_INLINE ReadResult sibling_r(id_type pos, NodeRef *sibling) RYML_NOEXCEPT { assert_readable_(); sibling->m_tree = m_tree; ReadResult result = m_tree->sibling_r(m_id, pos, &sibling->m_id); return result; }; /**< Forward to @ref Tree::sibling_r(). Node must be readable. */
1459 C4_ALWAYS_INLINE ReadResult sibling_r(id_type pos, ConstNodeRef *sibling) const RYML_NOEXCEPT { assert_readable_(); sibling->m_tree = m_tree; ReadResult result = m_tree->sibling_r(m_id, pos, &sibling->m_id); return result; }; /**< Forward to @ref Tree::sibling_r(). Node must be readable. */
1460
1461 C4_ALWAYS_INLINE NodeRef find_sibling(csubstr name) RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->find_sibling(m_id, name)}; } /**< Forward to @ref Tree::find_sibling(). Node must be readable. */
1462 C4_ALWAYS_INLINE ConstNodeRef find_sibling(csubstr name) const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->find_sibling(m_id, name)}; } /**< Forward to @ref Tree::find_sibling(). Node must be readable. */
1463
1464 C4_ALWAYS_INLINE ReadResult find_sibling_r(csubstr name, NodeRef *sibling) RYML_NOEXCEPT { assert_readable_(); sibling->m_tree = m_tree; ReadResult result = m_tree->find_sibling_r(m_id, name, &sibling->m_id); return result; }; /**< Forward to @ref Tree::find_sibling_r(). Node must be readable. */
1465 C4_ALWAYS_INLINE ReadResult find_sibling_r(csubstr name, ConstNodeRef *sibling) const RYML_NOEXCEPT { assert_readable_(); sibling->m_tree = m_tree; ReadResult result = m_tree->find_sibling_r(m_id, name, &sibling->m_id); return result; }; /**< Forward to @ref Tree::find_sibling_r(). Node must be readable. */
1466
1467 C4_ALWAYS_INLINE NodeRef ancestor_doc() RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->ancestor_doc(m_id)}; } /**< Forward to @ref Tree::ancestor_doc(). Node must be readable. */
1468 C4_ALWAYS_INLINE ConstNodeRef ancestor_doc() const RYML_NOEXCEPT { assert_readable_(); return {m_tree, m_tree->ancestor_doc(m_id)}; } /**< Forward to @ref Tree::ancestor_doc(). Node must be readable. */
1469
1470 C4_ALWAYS_INLINE NodeRef doc(id_type i) RYML_NOEXCEPT { RYML_ASSERT_BASIC_(m_tree); return {m_tree, m_tree->doc(i)}; } /**< Forward to @ref Tree::doc(). Node must be readable. */
1471 C4_ALWAYS_INLINE ConstNodeRef doc(id_type i) const RYML_NOEXCEPT { RYML_ASSERT_BASIC_(m_tree); return {m_tree, m_tree->doc(i)}; } /**< Forward to @ref Tree::doc(). Node must be readable. succeeds even when the node may have invalid or seed id */
1472
1473 /** @} */
1474
1475public:
1476
1477 /** @name square_brackets
1478 * operator[] */
1479 /** @{ */
1480
1481 /** Find child by key; complexity is O(num_children).
1482 *
1483 * Returns the requested node, or an object in seed state if no
1484 * such child is found (see @ref NodeRef for an explanation of
1485 * what is seed state). When the object is in seed state, using it
1486 * to read from the tree is UB. The seed node can be used to write
1487 * to the tree provided that its create() method is called prior
1488 * to writing, which happens in most modifying methods in
1489 * NodeRef. It is the caller's responsibility to verify that the
1490 * returned node is readable before subsequently using it to read
1491 * from the tree.
1492 *
1493 * @warning the calling object must be readable. This precondition
1494 * is asserted. The assertion is performed only if @ref
1495 * RYML_USE_ASSERT is set to true. As with the non-const overload,
1496 * it is UB to call this method if the node is not readable.
1497 *
1498 * @see https://github.com/biojppm/rapidyaml/issues/389 */
1499 C4_ALWAYS_INLINE NodeRef operator[] (csubstr key) RYML_NOEXCEPT
1500 {
1501 assert_readable_();
1502 id_type ch = m_tree->find_child(m_id, key);
1503 return ch != NONE ? NodeRef(m_tree, ch) : NodeRef(m_tree, m_id, key);
1504 }
1505
1506 /** Find child by position; complexity is O(pos).
1507 *
1508 * Returns the requested node, or an object in seed state if no
1509 * such child is found (see @ref NodeRef for an explanation of
1510 * what is seed state). When the object is in seed state, using it
1511 * to read from the tree is UB. The seed node can be used to write
1512 * to the tree provided that its create() method is called prior
1513 * to writing, which happens in most modifying methods in
1514 * NodeRef. It is the caller's responsibility to verify that the
1515 * returned node is readable before subsequently using it to read
1516 * from the tree.
1517 *
1518 * @warning the calling object must be readable. This precondition
1519 * is asserted. The assertion is performed only if @ref
1520 * RYML_USE_ASSERT is set to true. As with the non-const overload,
1521 * it is UB to call this method if the node is not readable.
1522 *
1523 * @see https://github.com/biojppm/rapidyaml/issues/389 */
1524 C4_ALWAYS_INLINE NodeRef operator[] (id_type pos) RYML_NOEXCEPT
1525 {
1526 assert_readable_();
1527 id_type ch = m_tree->child(m_id, pos);
1528 return ch != NONE ? NodeRef(m_tree, ch) : NodeRef(m_tree, m_id, pos);
1529 }
1530
1531 /** Find a child by key; complexity is O(num_children).
1532 *
1533 * Behaves similar to the non-const overload, but further asserts
1534 * that the returned node is readable (because it can never be in
1535 * a seed state). The assertion is performed only if @ref
1536 * RYML_USE_ASSERT is set to true. As with the non-const overload,
1537 * it is UB to use the return value if it is not valid.
1538 *
1539 * @see https://github.com/biojppm/rapidyaml/issues/389 */
1540 C4_ALWAYS_INLINE ConstNodeRef operator[] (csubstr key) const RYML_NOEXCEPT
1541 {
1542 assert_readable_();
1543 id_type ch = m_tree->find_child(m_id, key);
1544 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
1545 return {m_tree, ch};
1546 }
1547
1548 /** Find a child by position; complexity is O(pos).
1549 *
1550 * Behaves similar to the non-const overload, but further asserts
1551 * that the returned node is readable (because it can never be in
1552 * a seed state). This assertion is performed only if @ref
1553 * RYML_USE_ASSERT is set to true. As with the non-const overload,
1554 * it is UB to use the return value if it is not valid.
1555 *
1556 * @see https://github.com/biojppm/rapidyaml/issues/389 */
1557 C4_ALWAYS_INLINE ConstNodeRef operator[] (id_type pos) const RYML_NOEXCEPT
1558 {
1559 assert_readable_();
1560 id_type ch = m_tree->child(m_id, pos);
1561 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
1562 return {m_tree, ch};
1563 }
1564
1565 /** @} */
1566
1567public:
1568
1569 /** @name at
1570 *
1571 * These functions are the analogue to operator[], with the
1572 * difference that they emit an error instead of an
1573 * assertion. That is, if any of the pre or post conditions is
1574 * violated, an error is always emitted (resulting in a call to
1575 * the error callback).
1576 *
1577 * @{ */
1578
1579 /** Find child by key; complexity is O(num_children).
1580 *
1581 * Returns the requested node, or an object in seed state if no
1582 * such child is found (see @ref NodeRef for an explanation of
1583 * what is seed state). When the object is in seed state, using it
1584 * to read from the tree is UB. The seed node can be subsequently
1585 * used to write to the tree provided that its create() method is
1586 * called prior to writing, which happens inside most mutating
1587 * methods in NodeRef. It is the caller's responsibility to verify
1588 * that the returned node is readable before subsequently using it
1589 * to read from the tree.
1590 *
1591 * @warning This method will call the error callback (regardless
1592 * of build type or of the value of RYML_USE_ASSERT) whenever any
1593 * of the following preconditions is violated: a) the object is
1594 * valid (points at a tree and a node), b) the calling object must
1595 * be readable (must not be in seed state), c) the calling object
1596 * must be pointing at a MAP node. The preconditions are similar
1597 * to the non-const operator[](csubstr), but instead of using
1598 * assertions, this function directly checks those conditions and
1599 * calls the error callback if any of the checks fail.
1600 *
1601 * @note since it is valid behavior for the returned node to be in
1602 * seed state, the error callback is not invoked when this
1603 * happens. */
1604 C4_ALWAYS_INLINE NodeRef at(csubstr key)
1605 {
1606 RYML_CHECK_BASIC_(m_tree != nullptr);
1607 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (m_id >= 0 && m_id < m_tree->capacity()), m_tree, m_id);
1608 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, readable(), m_tree, m_id);
1609 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->is_map(m_id), m_tree, m_id);
1610 id_type ch = m_tree->find_child(m_id, key);
1611 return ch != NONE ? NodeRef(m_tree, ch) : NodeRef(m_tree, m_id, key);
1612 }
1613
1614 /** Find child by position; complexity is O(pos).
1615 *
1616 * Returns the requested node, or an object in seed state if no
1617 * such child is found (see @ref NodeRef for an explanation of
1618 * what is seed state). When the object is in seed state, using it
1619 * to read from the tree is UB. The seed node can be used to write
1620 * to the tree provided that its create() method is called prior
1621 * to writing, which happens in most modifying methods in
1622 * NodeRef. It is the caller's responsibility to verify that the
1623 * returned node is readable before subsequently using it to read
1624 * from the tree.
1625 *
1626 * @warning This method will call the error callback (regardless
1627 * of build type or of the value of RYML_USE_ASSERT) whenever any
1628 * of the following preconditions is violated: a) the object is
1629 * valid (points at a tree and a node), b) the calling object must
1630 * be readable (must not be in seed state), c) the calling object
1631 * must be pointing at a MAP node. The preconditions are similar
1632 * to the non-const operator[](id_type), but instead of using
1633 * assertions, this function directly checks those conditions and
1634 * calls the error callback if any of the checks fail.
1635 *
1636 * @note since it is valid behavior for the returned node to be in
1637 * seed state, the error callback is not invoked when this
1638 * happens. */
1639 C4_ALWAYS_INLINE NodeRef at(id_type pos)
1640 {
1641 RYML_CHECK_BASIC_(m_tree != nullptr);
1642 const id_type cap = m_tree->capacity();
1643 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (m_id >= 0 && m_id < cap), m_tree, m_id);
1644 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (pos >= 0 && pos < cap), m_tree, m_id);
1645 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, readable(), m_tree, m_id);
1646 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->is_container(m_id), m_tree, m_id);
1647 id_type ch = m_tree->child(m_id, pos);
1648 return ch != NONE ? NodeRef(m_tree, ch) : NodeRef(m_tree, m_id, pos);
1649 }
1650
1651 /** Get a child by name, with error checking; complexity is
1652 * O(num_children).
1653 *
1654 * Behaves as operator[](csubstr) const, but always raises an
1655 * error (even when RYML_USE_ASSERT is set to false) when the
1656 * returned node does not exist, or when this node is not
1657 * readable, or when it is not a map. This behaviour is similar to
1658 * std::vector::at(), but the error consists in calling the error
1659 * callback instead of directly raising an exception. */
1660 ConstNodeRef at(csubstr key) const
1661 {
1662 RYML_CHECK_BASIC_(m_tree != nullptr);
1663 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (m_id >= 0 && m_id < m_tree->capacity()), m_tree, m_id);
1664 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, readable(), m_tree, m_id);
1665 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->is_map(m_id), m_tree, m_id);
1666 id_type ch = m_tree->find_child(m_id, key);
1667 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
1668 return {m_tree, ch};
1669 }
1670
1671 /** Get a child by position, with error checking; complexity is
1672 * O(pos).
1673 *
1674 * Behaves as operator[](id_type) const, but always raises an error
1675 * (even when RYML_USE_ASSERT is set to false) when the returned
1676 * node does not exist, or when this node is not readable, or when
1677 * it is not a container. This behaviour is similar to
1678 * std::vector::at(), but the error consists in calling the error
1679 * callback instead of directly raising an exception. */
1680 ConstNodeRef at(id_type pos) const
1681 {
1682 RYML_CHECK_BASIC_(m_tree != nullptr);
1683 const id_type cap = m_tree->capacity();
1684 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (m_id >= 0 && m_id < cap), m_tree, m_id);
1685 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, (pos >= 0 && pos < cap), m_tree, m_id);
1686 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, readable(), m_tree, m_id);
1687 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, m_tree->is_container(m_id), m_tree, m_id);
1688 const id_type ch = m_tree->child(m_id, pos);
1689 RYML_CHECK_VISIT_CB_(m_tree->m_callbacks, ch != NONE, m_tree, m_id);
1690 return {m_tree, ch};
1691 }
1692
1693 /** @} */
1694
1695public:
1696
1697 /** @name modification of hierarchy */
1698 /** @{ */
1699
1701 {
1702 assert_readable_();
1703 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1704 NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
1705 return r;
1706 }
1707
1709 {
1710 assert_readable_();
1711 NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
1712 return r;
1713 }
1714
1716 {
1717 assert_readable_();
1718 NodeRef r(m_tree, m_tree->append_child(m_id));
1719 return r;
1720 }
1721
1722 NodeRef insert_sibling(ConstNodeRef const& after)
1723 {
1724 assert_readable_();
1725 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1726 NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
1727 return r;
1728 }
1729
1731 {
1732 assert_readable_();
1733 NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
1734 return r;
1735 }
1736
1738 {
1739 assert_readable_();
1740 NodeRef r(m_tree, m_tree->append_sibling(m_id));
1741 return r;
1742 }
1743
1744public:
1745
1747 {
1748 assert_readable_();
1749 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, has_child(child), m_tree, m_id);
1750 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, child.parent().id() == id(), m_tree, m_id);
1751 m_tree->remove(child.id());
1752 child = NodeRef{};
1753 }
1754
1755 //! remove the nth child of this node
1757 {
1758 assert_readable_();
1759 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, pos >= 0 && pos < num_children(), m_tree, m_id);
1760 id_type child = m_tree->child(m_id, pos);
1761 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, child != NONE, m_tree, m_id);
1762 m_tree->remove(child);
1763 }
1764
1765 //! remove a child by name
1767 {
1768 assert_readable_();
1769 id_type child = m_tree->find_child(m_id, key);
1770 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, child != NONE, m_tree, m_id);
1771 m_tree->remove(child);
1772 }
1773
1774public:
1775
1776 /** move the node to a different @p parent (which may belong to a
1777 * different tree), placing it after @p after. When the
1778 * destination parent is in a new tree, then this node's tree
1779 * pointer is reset to the tree of the parent node. */
1780 void move(NodeRef const& parent, ConstNodeRef const& after)
1781 {
1782 assert_readable_();
1783 parent.assert_readable_();
1784 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, parent.m_tree == after.m_tree || after.m_id == NONE, m_tree, m_id);
1785 if(parent.m_tree == m_tree)
1786 {
1787 m_tree->move(m_id, parent.m_id, after.m_id);
1788 }
1789 else
1790 {
1791 parent.m_tree->move(m_tree, m_id, parent.m_id, after.m_id);
1792 m_tree = parent.m_tree;
1793 }
1794 }
1795
1796 /** duplicate the current node somewhere into a different @p parent
1797 * (possibly from a different tree), and place it after the node
1798 * @p after. To place into the first position of the parent,
1799 * simply pass an empty or default-constructed reference like
1800 * this: `n.move({})`. */
1801 NodeRef duplicate(NodeRef const& parent, ConstNodeRef const& after) const
1802 {
1803 assert_readable_();
1804 parent.assert_readable_();
1805 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, parent.m_tree == after.m_tree || after.m_id == NONE, m_tree, m_id);
1806 id_type dup = parent.m_tree->duplicate(m_tree, m_id, parent.m_id, after.m_id);
1807 NodeRef r(parent.m_tree, dup);
1808 return r;
1809 }
1810
1811 NodeRef duplicate_children(NodeRef const& parent, ConstNodeRef const& after) const
1812 {
1813 assert_readable_();
1814 parent.assert_readable_();
1815 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, parent.m_tree == after.m_tree || after.m_id == NONE, m_tree, m_id);
1816 id_type last_dup = parent.m_tree->duplicate_children(m_tree, m_id, parent.m_id, after.m_id);
1817 NodeRef r(parent.m_tree, last_dup);
1818 return r;
1819 }
1820
1821 /** @} */
1822
1823public:
1824
1825 /** @name iteration */
1826 /** @{ */
1827
1828 using iterator = detail::child_iterator<NodeRef>;
1829 using const_iterator = detail::child_iterator<ConstNodeRef>;
1830 using children_view = detail::children_view<NodeRef>;
1831 using const_children_view = detail::children_view<ConstNodeRef>;
1832
1833
1834 C4_ALWAYS_INLINE iterator begin() RYML_NOEXCEPT { assert_readable_(); return iterator(m_tree, m_tree->first_child(m_id)); } /**< get a mutable iterator to the first child. NOT AVAILABLE for ConstNodeRef. */
1835 C4_ALWAYS_INLINE const_iterator begin() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, m_tree->first_child(m_id)); } /**< get an iterator to the first child */
1836 C4_ALWAYS_INLINE const_iterator cbegin() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, m_tree->first_child(m_id)); } /**< get an iterator to the first child */
1837
1838 C4_ALWAYS_INLINE iterator end() RYML_NOEXCEPT { assert_readable_(); return iterator(m_tree, NONE); } /**< get an iterator to after the last child. NOT AVAILABLE for ConstNodeRef. */
1839 C4_ALWAYS_INLINE const_iterator end() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, NONE); } /**< get an iterator to after the last child */
1840 C4_ALWAYS_INLINE const_iterator cend() const RYML_NOEXCEPT { assert_readable_(); return const_iterator(m_tree, NONE); } /**< get an iterator to after the last child */
1841
1842
1843 C4_ALWAYS_INLINE children_view children() RYML_NOEXCEPT { assert_readable_(); return detail::make_children_view<children_view>(m_tree, m_id); } /**< get an iterable view over children */
1844 C4_ALWAYS_INLINE const_children_view children() const RYML_NOEXCEPT { assert_readable_(); return detail::make_children_view<const_children_view>(m_tree, m_id); } /**< get an iterable view over children */
1845 C4_ALWAYS_INLINE const_children_view cchildren() const RYML_NOEXCEPT { assert_readable_(); return detail::make_children_view<const_children_view>(m_tree, m_id); } /**< get an iterable view over children */
1846
1847 C4_ALWAYS_INLINE children_view siblings() RYML_NOEXCEPT { assert_readable_(); return detail::make_siblings_view<children_view>(m_tree, m_id); } /** get an iterable view over all siblings (including the calling node) */
1848 C4_ALWAYS_INLINE const_children_view siblings() const RYML_NOEXCEPT { assert_readable_(); return detail::make_siblings_view<const_children_view>(m_tree, m_id); } /** get an iterable view over all siblings (including the calling node) */
1849 C4_ALWAYS_INLINE const_children_view csiblings() const RYML_NOEXCEPT { assert_readable_(); return detail::make_siblings_view<const_children_view>(m_tree, m_id); } /** get an iterable view over all siblings (including the calling node) */
1850
1851 /** @} */
1852
1853public:
1854
1855 /** @name legacy operators
1856 *
1857 * these methods will be removed in future releases. If you
1858 * disagree with a particular function being deprecated, let us
1859 * know by opening a new issue at
1860 * https://github.com/biojppm/rapidyaml/issues
1861 */
1862 /** @{ */
1863
1864 RYML_LEGACY_OPERATOR(".use the appropriate .set_*() overload")
1865 void operator= (type_bits t) { create(); m_tree->_p(m_id)->m_type = t; }
1866
1867 RYML_LEGACY_OPERATOR(".use the appropriate .set_*() overload")
1868 void operator|= (type_bits t) { create(); m_tree->_add_flags(m_id, t); }
1869
1870 RYML_LEGACY_OPERATOR("use .set_val()")
1871 NodeRef& operator= (csubstr v) { set_val(v); return *this; }
1872
1873 template<size_t N>
1874 RYML_LEGACY_OPERATOR("use .set_val()")
1875 NodeRef& operator= (const char (&v)[N]) { csubstr sv; sv.assign<N>(v); set_val(sv); return *this; }
1876
1877 RYML_LEGACY_OPERATOR("use .set_val()")
1878 NodeRef& operator= (std::nullptr_t) { set_val(csubstr{}); return *this; }
1879
1880 template<class T>
1881 RYML_LEGACY_OPERATOR("use .set_key()")
1882 NodeRef& operator= (Key<T> const& C4_RESTRICT v) { set_key(v.k); return *this; }
1883
1884 template<class T>
1885 RYML_LEGACY_OPERATOR("use .save()")
1886 NodeRef& operator<< (T const& C4_RESTRICT v) { save(v); return *this; }
1887
1888 RYML_LEGACY_OPERATOR("use .save()")
1889 NodeRef& operator<< (csubstr v) { save(v); return *this; }
1890
1891 template<class T>
1892 RYML_LEGACY_OPERATOR("use .save_key()")
1893 NodeRef& operator<< (Key<T> const& C4_RESTRICT v) { save_key(v.k); return *this; }
1894
1895 /** @} */
1896
1897public: // deprecated functions
1898
1899 // these methods will be removed in future releases. If you
1900 // disagree with a particular function being deprecated, let us
1901 // know by opening a new issue at
1902 // https://github.com/biojppm/rapidyaml/issues
1903
1904 /** @cond dev */ // LCOV_EXCL_START
1905 C4_SUPPRESS_WARNING_PUSH
1906 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated")
1907 C4_SUPPRESS_WARNING_GCC_CLANG("-Wdeprecated-declarations")
1908 C4_SUPPRESS_WARNING_MSVC(4996) // deprecated
1909 RYML_DEPRECATED("use NodeRef()") NodeRef(std::nullptr_t) noexcept : m_tree(nullptr), m_id(NONE), m_seed() {}
1910
1911 RYML_DEPRECATED("use one of readable(), is_seed() or !invalid()") inline bool valid() const { return m_tree != nullptr && m_id != NONE; }
1912 RYML_DEPRECATED("use !readable()") bool operator== (std::nullptr_t) const { return m_tree == nullptr || m_id == NONE || is_seed(); }
1913 RYML_DEPRECATED("use readable()") bool operator!= (std::nullptr_t) const { return !(m_tree == nullptr || m_id == NONE || is_seed()); }
1914 RYML_DEPRECATED("use `this->val() == s`") bool operator== (csubstr s) const { assert_readable_(); RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, has_val(), m_tree, m_id); return m_tree->val(m_id) == s; }
1915 RYML_DEPRECATED("use `this->val() != s`") bool operator!= (csubstr s) const { assert_readable_(); RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, has_val(), m_tree, m_id); return m_tree->val(m_id) != s; }
1916
1917 RYML_DEPRECATED("use .set_*()") void operator= (NodeInit const& v)
1918 {
1919 create();
1920 _apply(v);
1921 }
1922
1923 RYML_DEPRECATED("use .set_*()") void operator= (NodeScalar const& v)
1924 {
1925 create();
1926 _apply(v);
1927 }
1928
1929 RYML_DEPRECATED("") void clear()
1930 {
1931 assert_readable_();
1932 m_tree->remove_children(m_id);
1933 m_tree->_clear(m_id);
1934 }
1935
1936 RYML_DEPRECATED("") void _apply(csubstr v)
1937 {
1938 m_tree->set_val(m_id, v);
1939 }
1940
1941 RYML_DEPRECATED("") void _apply(NodeScalar const& v)
1942 {
1943 m_tree->_set_val(m_id, v);
1944 }
1945
1946 RYML_DEPRECATED("") void _apply(NodeInit const& i)
1947 {
1948 m_tree->_set(m_id, i);
1949 }
1950
1951 RYML_DEPRECATED("") NodeRef insert_child(NodeInit const& i, NodeRef after)
1952 {
1953 assert_readable_();
1954 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1955 NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
1956 r._apply(i);
1957 return r;
1958 }
1959
1960 RYML_DEPRECATED("") NodeRef prepend_child(NodeInit const& i)
1961 {
1962 assert_readable_();
1963 NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
1964 r._apply(i);
1965 return r;
1966 }
1967
1968 RYML_DEPRECATED("") NodeRef append_child(NodeInit const& i)
1969 {
1970 assert_readable_();
1971 NodeRef r(m_tree, m_tree->append_child(m_id));
1972 r._apply(i);
1973 return r;
1974 }
1975
1976 RYML_DEPRECATED("") NodeRef insert_sibling(NodeInit const& i, ConstNodeRef const& after)
1977 {
1978 assert_readable_();
1979 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1980 NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
1981 r._apply(i);
1982 return r;
1983 }
1984
1985 RYML_DEPRECATED("") NodeRef prepend_sibling(NodeInit const& i)
1986 {
1987 assert_readable_();
1988 NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
1989 r._apply(i);
1990 return r;
1991 }
1992
1993 RYML_DEPRECATED("") NodeRef append_sibling(NodeInit const& i)
1994 {
1995 assert_readable_();
1996 NodeRef r(m_tree, m_tree->append_sibling(m_id));
1997 r._apply(i);
1998 return r;
1999 }
2000
2001 RYML_DEPRECATED("") void move(ConstNodeRef const& after)
2002 {
2003 assert_readable_();
2004 m_tree->move(m_id, after.m_id);
2005 }
2006
2007 RYML_DEPRECATED("") NodeRef duplicate(ConstNodeRef const& after) const
2008 {
2009 assert_readable_();
2010 RYML_ASSERT_VISIT_CB_(m_tree->m_callbacks, m_tree == after.m_tree || after.m_id == NONE, m_tree, m_id);
2011 id_type dup = m_tree->duplicate(m_id, m_tree->parent(m_id), after.m_id);
2012 NodeRef r(m_tree, dup);
2013 return r;
2014 }
2015
2016 C4_SUPPRESS_WARNING_POP
2017
2018 void _add_flags(NodeType f)
2019 {
2020 assert_readable_();
2021 m_tree->_add_flags(m_id, f);
2022 }
2023 /** @endcond */ // LCOV_EXCL_STOP
2024
2025};
2026
2027// NOLINTEND(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator)
2028
2029/** @} */
2030
2031
2032//-----------------------------------------------------------------------------
2033
2034inline ConstNodeRef::ConstNodeRef(NodeRef const& that) noexcept
2035 : m_tree(that.m_tree)
2036 , m_id(!that.is_seed() ? that.id() : (id_type)NONE)
2037{
2038}
2039
2040inline ConstNodeRef::ConstNodeRef(NodeRef && that) noexcept // NOLINT
2041 : m_tree(that.m_tree)
2042 , m_id(!that.is_seed() ? that.id() : (id_type)NONE)
2043{
2044}
2045
2046
2047inline ConstNodeRef& ConstNodeRef::operator= (NodeRef const& that) noexcept
2048{
2049 m_tree = (that.m_tree);
2050 m_id = (!that.is_seed() ? that.id() : (id_type)NONE);
2051 return *this;
2052}
2053
2054inline ConstNodeRef& ConstNodeRef::operator= (NodeRef && that) noexcept // NOLINT
2055{
2056 m_tree = (that.m_tree);
2057 m_id = (!that.is_seed() ? that.id() : (id_type)NONE);
2058 return *this;
2059}
2060
2061
2062//-----------------------------------------------------------------------------
2063
2064/** @addtogroup doc_serialization_node_read
2065 *
2066 * freestanding read() and read_key() implementing ryml's built-in
2067 * deserialization of fundamental types.
2068 *
2069 * @{
2070 */
2071
2072
2073template<class T>
2074C4_NODISCARD C4_ALWAYS_INLINE ReadResult read(ConstNodeRef const& C4_RESTRICT n, T *v)
2075{
2076 // defer to the tree implementation
2077 return n.m_tree->deserialize(n.m_id, v);
2078}
2079template<class T>
2080C4_NODISCARD C4_ALWAYS_INLINE ReadResult read(ConstNodeRef const& C4_RESTRICT n, T const& wrapper)
2081{
2082 // defer to the tree implementation
2083 return n.m_tree->deserialize(n.m_id, wrapper);
2084}
2085
2086
2087template<class T>
2088C4_NODISCARD C4_ALWAYS_INLINE ReadResult read_key(ConstNodeRef const& C4_RESTRICT n, T *v)
2089{
2090 // defer to the tree implementation
2091 return n.m_tree->deserialize_key(n.m_id, v);
2092}
2093template<class T>
2094C4_NODISCARD C4_ALWAYS_INLINE ReadResult read_key(ConstNodeRef const& C4_RESTRICT n, T const& wrapper)
2095{
2096 // defer to the tree implementation
2097 return n.m_tree->deserialize_key(n.m_id, wrapper);
2098}
2099
2100/** @} */
2101
2102
2103//-----------------------------------------------------------------------------
2104
2105/** @addtogroup doc_serialization_node_write
2106 *
2107 * freestanding write() and write_key() implementing ryml's
2108 * built-in serialization of fundamental types.
2109 *
2110 * @{
2111 */
2112
2113template<class T>
2114C4_ALWAYS_INLINE void write(NodeRef *n, T const& v)
2115{
2116 n->tree()->set_serialized(n->id(), v); // defer to the tree implementation
2117}
2118template<class T>
2119C4_ALWAYS_INLINE void write_key(NodeRef *n, T const& v)
2120{
2121 n->tree()->set_key_serialized(n->id(), v); // defer to the tree implementation
2122}
2123
2124template<class T>
2125C4_ALWAYS_INLINE void write(NodeRef &n, T const& v)
2126{
2127 // forward to the pointer call, to ensure the user's function is
2128 // called regardless if it is write(NodeRef*,T), write(NodeRef&,T)
2129 // or write(NodeRef,T)
2130 write(&n, v);
2131}
2132template<class T>
2133C4_ALWAYS_INLINE void write_key(NodeRef &n, T const& v)
2134{
2135 // forward to the pointer call, to ensure the user's function is
2136 // called regardless if it is write(NodeRef*,T), write(NodeRef&,T)
2137 // or write(NodeRef,T)
2138 write_key(&n, v);
2139}
2140
2141/** @} */
2142
2143
2144} // namespace yml
2145} // namespace c4
2146
2147// NOLINTEND(modernize-avoid-c-style-cast)
2148
2149C4_SUPPRESS_WARNING_POP
2150
2151#endif /* C4_YML_NODE_HPP_ */
Holds a pointer to an existing tree, and a node id.
Definition node.hpp:737
detail::children_view< ConstNodeRef > children_view
Definition node.hpp:976
NodeData const * get() const RYML_NOEXCEPT
Forward to Tree::type().
Definition node.hpp:841
ConstNodeRef parent() const RYML_NOEXCEPT
Forward to Tree::parent().
Definition node.hpp:853
const_iterator cend() const RYML_NOEXCEPT
get an iterator to after the last child
Definition node.hpp:984
const_iterator cbegin() const RYML_NOEXCEPT
get an iterator to the first child
Definition node.hpp:981
const_children_view cchildren() const RYML_NOEXCEPT
get an iterable view over children
Definition node.hpp:988
ReadResult find_child_r(csubstr name, ConstNodeRef *child) const RYML_NOEXCEPT
Forward to Tree::child_r().
Definition node.hpp:868
ConstNodeRef() noexcept
Definition node.hpp:757
ConstNodeRef child(id_type pos) const RYML_NOEXCEPT
Forward to Tree::child().
Definition node.hpp:856
ConstNodeRef & operator=(ConstNodeRef const &) noexcept=default
ConstNodeRef first_sibling() const RYML_NOEXCEPT
Forward to Tree::first_sibling().
Definition node.hpp:860
ConstNodeRef(ConstNodeRef const &) noexcept=default
id_type id() const noexcept
Definition node.hpp:822
ConstNodeRef ancestor_doc() const RYML_NOEXCEPT
Forward to Tree::ancestor_doc().
Definition node.hpp:864
ConstNodeRef first_child() const RYML_NOEXCEPT
Forward to Tree::first_child().
Definition node.hpp:854
ConstNodeRef find_child(csubstr name) const RYML_NOEXCEPT
Forward to Tree::find_child().
Definition node.hpp:857
ReadResult sibling_r(id_type pos, ConstNodeRef *sibling) const RYML_NOEXCEPT
Forward to Tree::find_child_r().
Definition node.hpp:870
ConstNodeRef last_child() const RYML_NOEXCEPT
Forward to Tree::last_child().
Definition node.hpp:855
ConstNodeRef(ConstNodeRef &&) noexcept=default
ConstNodeRef(Tree const *t) noexcept
Definition node.hpp:759
detail::child_iterator< ConstNodeRef > iterator
Definition node.hpp:974
ConstNodeRef at(id_type pos) const
Get a child by position, with error checking; complexity is O(pos).
Definition node.hpp:956
bool invalid() const noexcept
Definition node.hpp:790
ConstNodeRef find_sibling(csubstr name) const RYML_NOEXCEPT
Forward to Tree::find_sibling().
Definition node.hpp:863
const_iterator begin() const RYML_NOEXCEPT
get an iterator to the first child
Definition node.hpp:980
detail::child_iterator< ConstNodeRef > const_iterator
Definition node.hpp:975
ReadResult find_sibling_r(csubstr name, ConstNodeRef *sibling) const RYML_NOEXCEPT
Forward to Tree::sibling_r().
Definition node.hpp:871
const_children_view children() const RYML_NOEXCEPT
get an iterable view over children
Definition node.hpp:987
ConstNodeRef last_sibling() const RYML_NOEXCEPT
Forward to Tree::last_sibling().
Definition node.hpp:861
ConstNodeRef at(csubstr key) const
Get a child by name, with error checking; complexity is O(num_children).
Definition node.hpp:938
ConstNodeRef(Tree const *t, id_type id) noexcept
Definition node.hpp:760
ConstNodeRef(Tree const &t) noexcept
Definition node.hpp:758
Tree const * tree() const noexcept
Definition node.hpp:821
detail::children_view< ConstNodeRef > const_children_view
Definition node.hpp:977
Tree const tree_type
Definition node.hpp:740
ConstNodeRef next_sibling() const RYML_NOEXCEPT
Forward to Tree::next_sibling().
Definition node.hpp:859
ConstNodeRef doc(id_type i) const RYML_NOEXCEPT
Forward to Tree::doc().
Definition node.hpp:865
Tree const * m_tree
Definition node.hpp:744
static constexpr bool is_seed() noexcept
because a ConstNodeRef cannot be used to write to the tree, it can never be a seed.
Definition node.hpp:796
ConstNodeRef prev_sibling() const RYML_NOEXCEPT
Forward to Tree::prev_sibling().
Definition node.hpp:858
ConstNodeRef sibling(id_type pos) const RYML_NOEXCEPT
Forward to Tree::sibling().
Definition node.hpp:862
const_children_view siblings() const RYML_NOEXCEPT
Definition node.hpp:990
const_iterator end() const RYML_NOEXCEPT
get an iterator to after the last child
Definition node.hpp:983
bool readable() const noexcept
because a ConstNodeRef cannot be used to write to the tree, readable() has the same meaning as !...
Definition node.hpp:793
ReadResult child_r(id_type pos, ConstNodeRef *child) const RYML_NOEXCEPT
Definition node.hpp:867
const_children_view csiblings() const RYML_NOEXCEPT
get an iterable view over all siblings (including the calling node)
Definition node.hpp:991
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition node.hpp:1063
void set_val_anchor(csubstr val_anchor)
Definition node.hpp:1263
NodeRef parent() RYML_NOEXCEPT
Forward to Tree::parent().
Definition node.hpp:1422
const_iterator begin() const RYML_NOEXCEPT
get an iterator to the first child
Definition node.hpp:1835
void set_stream()
Definition node.hpp:1245
void set_style_conditionally(NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
Definition node.hpp:1311
detail::children_view< NodeRef > children_view
Definition node.hpp:1830
ReadResult find_sibling_r(csubstr name, NodeRef *sibling) RYML_NOEXCEPT
Definition node.hpp:1464
ConstNodeRef prev_sibling() const RYML_NOEXCEPT
Forward to Tree::prev_sibling().
Definition node.hpp:1444
NodeRef last_sibling() RYML_NOEXCEPT
Forward to Tree::last_sibling().
Definition node.hpp:1452
NodeRef prev_sibling() RYML_NOEXCEPT
Forward to Tree::find_child_r().
Definition node.hpp:1443
detail::child_iterator< NodeRef > iterator
Definition node.hpp:1828
ConstNodeRef find_sibling(csubstr name) const RYML_NOEXCEPT
Forward to Tree::find_sibling().
Definition node.hpp:1462
detail::RoNodeMethods< NodeRef, ConstNodeRef > base_type
Definition node.hpp:1067
void save(T const &k)
Definition node.hpp:1337
NodeRef insert_sibling(ConstNodeRef const &after)
Definition node.hpp:1722
NodeRef child(id_type pos) RYML_NOEXCEPT
Forward to Tree::child().
Definition node.hpp:1431
Tree * tree() noexcept
Definition node.hpp:1211
void set_val(csubstr val, NodeType more_flags)
Definition node.hpp:1252
iterator begin() RYML_NOEXCEPT
get a mutable iterator to the first child.
Definition node.hpp:1834
ConstNodeRef last_child() const RYML_NOEXCEPT
Forward to Tree::last_child().
Definition node.hpp:1429
ReadResult child_r(id_type pos, ConstNodeRef *child) const RYML_NOEXCEPT
Forward to Tree::child_r().
Definition node.hpp:1435
NodeRef(Tree *t, id_type id, csubstr seed_key) noexcept
Definition node.hpp:1111
detail::child_iterator< ConstNodeRef > const_iterator
Definition node.hpp:1829
void set_serialized(T const &v)
serialize a variable to this node.
Definition node.hpp:1375
void set_val_tag(csubstr val_tag)
Definition node.hpp:1261
NodeRef next_sibling() RYML_NOEXCEPT
Forward to Tree::next_sibling().
Definition node.hpp:1446
void clear_style(bool recurse=false)
Definition node.hpp:1305
Tree const * tree() const noexcept
Definition node.hpp:1210
void save_key(T const &k)
Definition node.hpp:1354
NodeRef(NodeRef &&) noexcept=default
ReadResult find_child_r(csubstr name, ConstNodeRef *child) const RYML_NOEXCEPT
Forward to Tree::find_child_r().
Definition node.hpp:1441
const_iterator cbegin() const RYML_NOEXCEPT
get an iterator to the first child
Definition node.hpp:1836
NodeRef(Tree *t, id_type id, id_type seed_pos) noexcept
Definition node.hpp:1110
NodeRef at(id_type pos)
Find child by position; complexity is O(pos).
Definition node.hpp:1639
NodeRef at(csubstr key)
Find child by key; complexity is O(num_children).
Definition node.hpp:1604
csubstr to_arena(T const &s)
forward to Tree::to_arena() .
Definition node.hpp:1330
children_view children() RYML_NOEXCEPT
get an iterable view over children
Definition node.hpp:1843
NodeRef insert_child(NodeRef after)
Definition node.hpp:1700
void set_val(csubstr val)
Definition node.hpp:1251
NodeRef prepend_sibling()
Definition node.hpp:1730
ConstNodeRef first_child() const RYML_NOEXCEPT
Forward to Tree::first_child().
Definition node.hpp:1426
void set_key_serialized(T const &k)
serialize a variable, then assign the result to the node's key
Definition node.hpp:1396
void clear_children()
remove the children from a scalar
Definition node.hpp:1299
NodeRef(Tree *t, id_type id) noexcept
Definition node.hpp:1109
void set_map(NodeType more_flags)
Definition node.hpp:1258
ConstNodeRef last_sibling() const RYML_NOEXCEPT
Forward to Tree::last_sibling().
Definition node.hpp:1453
ConstNodeRef at(csubstr key) const
Get a child by name, with error checking; complexity is O(num_children).
Definition node.hpp:1660
NodeRef() noexcept
Definition node.hpp:1106
ConstNodeRef find_child(csubstr name) const RYML_NOEXCEPT
Forward to Tree::find_child().
Definition node.hpp:1438
void set_key_serialized(T const &k, NodeType style_flags)
Definition node.hpp:1403
ConstNodeRef at(id_type pos) const
Get a child by position, with error checking; complexity is O(pos).
Definition node.hpp:1680
void clear_val()
remove the VAL (flags included) from a scalar
Definition node.hpp:1292
NodeRef ancestor_doc() RYML_NOEXCEPT
Forward to Tree::find_sibling_r().
Definition node.hpp:1467
void set_container_style(type_bits style)
Definition node.hpp:1267
NodeRef append_sibling()
Definition node.hpp:1737
ConstNodeRef first_sibling() const RYML_NOEXCEPT
Forward to Tree::first_sibling().
Definition node.hpp:1450
ReadResult sibling_r(id_type pos, NodeRef *sibling) RYML_NOEXCEPT
Definition node.hpp:1458
const_iterator end() const RYML_NOEXCEPT
get an iterator to after the last child
Definition node.hpp:1839
const_children_view children() const RYML_NOEXCEPT
get an iterable view over children
Definition node.hpp:1844
ReadResult find_child_r(csubstr name, NodeRef *child) RYML_NOEXCEPT
Definition node.hpp:1440
void set_key(csubstr key, NodeType more_flags)
Definition node.hpp:1249
NodeData * get() RYML_NOEXCEPT
Forward to Tree::type().
Definition node.hpp:1214
children_view siblings() RYML_NOEXCEPT
Definition node.hpp:1847
NodeData const * get() const RYML_NOEXCEPT
Forward to Tree::type().
Definition node.hpp:1213
NodeRef last_child() RYML_NOEXCEPT
Forward to Tree::last_child().
Definition node.hpp:1428
id_type id() const noexcept
Definition node.hpp:1208
ConstNodeRef parent() const RYML_NOEXCEPT
Forward to Tree::parent().
Definition node.hpp:1423
bool invalid() const noexcept
true if the object is not referring to any existing or seed node.
Definition node.hpp:1134
detail::children_view< ConstNodeRef > const_children_view
Definition node.hpp:1831
ConstNodeRef child(id_type pos) const RYML_NOEXCEPT
Forward to Tree::child().
Definition node.hpp:1432
ReadResult child_r(id_type pos, NodeRef *child) RYML_NOEXCEPT
Definition node.hpp:1434
ReadResult find_sibling_r(csubstr name, ConstNodeRef *sibling) const RYML_NOEXCEPT
Forward to Tree::find_sibling_r().
Definition node.hpp:1465
NodeRef doc(id_type i) RYML_NOEXCEPT
Forward to Tree::doc().
Definition node.hpp:1470
void move(NodeRef const &parent, ConstNodeRef const &after)
move the node to a different parent (which may belong to a different tree), placing it after after.
Definition node.hpp:1780
void save(T const &k, NodeType style_flags)
Definition node.hpp:1344
void set_seq(NodeType more_flags)
Definition node.hpp:1255
void set_key_style(type_bits style)
Definition node.hpp:1268
bool readable() const noexcept
true if the object is not invalid and not in seed state.
Definition node.hpp:1138
ConstNodeRef sibling(id_type pos) const RYML_NOEXCEPT
Forward to Tree::sibling().
Definition node.hpp:1456
NodeRef sibling(id_type pos) RYML_NOEXCEPT
Forward to Tree::sibling().
Definition node.hpp:1455
NodeRef(Tree *t) noexcept
Definition node.hpp:1108
ConstNodeRef ancestor_doc() const RYML_NOEXCEPT
Forward to Tree::ancestor_doc().
Definition node.hpp:1468
NodeRef append_child()
Definition node.hpp:1715
NodeRef first_sibling() RYML_NOEXCEPT
Forward to Tree::first_sibling().
Definition node.hpp:1449
void clear_key()
remove the KEY (flags included) from a scalar
Definition node.hpp:1285
void create()
if this node is in seed state, create the node in the tree
Definition node.hpp:1225
NodeRef duplicate(NodeRef const &parent, ConstNodeRef const &after) const
duplicate the current node somewhere into a different parent (possibly from a different tree),...
Definition node.hpp:1801
ConstNodeRef doc(id_type i) const RYML_NOEXCEPT
Forward to Tree::doc().
Definition node.hpp:1471
ReadResult sibling_r(id_type pos, ConstNodeRef *sibling) const RYML_NOEXCEPT
Forward to Tree::sibling_r().
Definition node.hpp:1459
const_iterator cend() const RYML_NOEXCEPT
get an iterator to after the last child
Definition node.hpp:1840
void set_serialized(T const &v, NodeType style_flags)
Definition node.hpp:1382
NodeRef duplicate_children(NodeRef const &parent, ConstNodeRef const &after) const
Definition node.hpp:1811
void remove_child(csubstr key)
remove a child by name
Definition node.hpp:1766
NodeRef prepend_child()
Definition node.hpp:1708
NodeRef(NodeRef const &) noexcept=default
void set_key_tag(csubstr key_tag)
Definition node.hpp:1260
ConstNodeRef next_sibling() const RYML_NOEXCEPT
Forward to Tree::next_sibling().
Definition node.hpp:1447
const_children_view siblings() const RYML_NOEXCEPT
get an iterable view over all siblings (including the calling node)
Definition node.hpp:1848
void set_key_ref(csubstr key_ref)
Definition node.hpp:1264
NodeRef find_sibling(csubstr name) RYML_NOEXCEPT
Forward to Tree::sibling_r().
Definition node.hpp:1461
void remove_child(NodeRef &child)
Definition node.hpp:1746
NodeRef first_child() RYML_NOEXCEPT
Forward to Tree::first_child().
Definition node.hpp:1425
void save_key(T const &k, NodeType style_flags)
Definition node.hpp:1361
void set_val_style(type_bits style)
Definition node.hpp:1269
void set_key_anchor(csubstr key_anchor)
Definition node.hpp:1262
const_children_view cchildren() const RYML_NOEXCEPT
get an iterable view over children
Definition node.hpp:1845
void change_type(NodeType t)
Definition node.hpp:1278
NodeRef(Tree &t) noexcept
Definition node.hpp:1107
iterator end() RYML_NOEXCEPT
get an iterator to after the last child.
Definition node.hpp:1838
bool is_seed() const noexcept
true if the object is not invalid and in seed state.
Definition node.hpp:1136
void set_key(csubstr key)
Definition node.hpp:1248
void set_val_ref(csubstr val_ref)
Definition node.hpp:1265
NodeRef find_child(csubstr name) RYML_NOEXCEPT
Forward to Tree::child_r().
Definition node.hpp:1437
void remove_child(id_type pos)
remove the nth child of this node
Definition node.hpp:1756
const_children_view csiblings() const RYML_NOEXCEPT
get an iterable view over all siblings (including the calling node)
Definition node.hpp:1849
void set_serialized(id_type node, T const &val) RYML_NOEXCEPT
Definition tree.hpp:823
void set_key_serialized(id_type node, T const &key) RYML_NOEXCEPT
Definition tree.hpp:837
Callbacks m_callbacks
Definition tree.hpp:1686
#define RYML_NOEXCEPT
Conditionally expands to noexcept when RYML_USE_ASSERT is 0 and is empty otherwise.
#define RYML_EXPORT
Definition export.hpp:18
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition node_type.hpp:26
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition node_type.hpp:35
@ KEY
the scalar to the left of : in a map's member
Definition node_type.hpp:33
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition node_type.hpp:34
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
Definition node_type.hpp:36
@ STYLE
mask of SCALAR_STYLE | CONTAINER_STYLE : all style flags
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree (see Event Ha...
Definition fwd.hpp:19
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)
ReadResult read_key(ConstNodeRef const &n, T *v)
Definition node.hpp:2088
ReadResult read(ConstNodeRef const &n, T *v)
Definition node.hpp:2074
void write(NodeRef *n, T const &v)
Definition node.hpp:2114
void write_key(NodeRef *n, T const &v)
Definition node.hpp:2119
bool operator!=(const char c, basic_substring< C > const that) noexcept
Definition substr.hpp:2439
bool operator==(const char c, basic_substring< C > const that) noexcept
Definition substr.hpp:2438
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2356
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...
Definition common.hpp:124
@ NONE
an index to none
Definition common.hpp:131
#define b_(v)
Definition node_type.hpp:31
size_t len
the length of the substring
Definition substr.hpp:218
void assign(C(&s_)[N]) noexcept
Assign from an array.
Definition substr.hpp:300
C * str
a restricted pointer to the first character of the substring
Definition substr.hpp:216
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition common.hpp:229
contains the data for each YAML node.
Definition tree.hpp:288
a node scalar is a csubstr, which may be tagged and anchored.
Definition tree.hpp:170
Wraps a type_bits mask of NodeTypeBits flags with some syntactic sugar and predicates.
A lightweight truthy type, used to enable reporting the offending node when a deserializing error hap...
Definition common.hpp:162
a CRTP base providing read-only methods for ConstNodeRef and NodeRef
Definition node.hpp:153
void load(Wrapper const &wrapper, bool check_readable=true) const
(2) like (1), but for wrapper tag types such as c4::fmt::base64()
Definition node.hpp:361
ReadResult deserialize_child(id_type child_pos, Wrapper const &wrapper) const
(3) like (1), but for wrapper tag types such as c4::fmt::base64()
Definition node.hpp:549
bool type_has_all(type_bits bits) const RYML_NOEXCEPT
Forward to Tree::type_has_all().
Definition node.hpp:235
id_type depth_asc() const RYML_NOEXCEPT
Definition node.hpp:308
id_type depth_desc() const RYML_NOEXCEPT
O(log(num_nodes)).
Definition node.hpp:309
bool has_anchor() const RYML_NOEXCEPT
Forward to Tree::has_anchor().
Definition node.hpp:217
NodeScalar const & valsc() const RYML_NOEXCEPT
Forward to Tree::valsc().
Definition node.hpp:185
bool is_val() const RYML_NOEXCEPT
Forward to Tree::is_val().
Definition node.hpp:211
bool is_key_styled() const RYML_NOEXCEPT
Forward to Tree::is_key_styled().
Definition node.hpp:252
void load_key(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...
Definition node.hpp:385
bool is_root() const RYML_NOEXCEPT
Forward to Tree::is_root().
Definition node.hpp:278
csubstr key_anchor() const RYML_NOEXCEPT
Forward to Tree::key_anchor().
Definition node.hpp:177
bool has_val_anchor() const RYML_NOEXCEPT
Forward to Tree::has_val_anchor().
Definition node.hpp:216
bool type_has_any(type_bits bits) const RYML_NOEXCEPT
Forward to Tree::type_has_any().
Definition node.hpp:234
bool is_key_plain() const RYML_NOEXCEPT
Forward to Tree::is_key_plain().
Definition node.hpp:262
bool is_key_quoted() const RYML_NOEXCEPT
Forward to Tree::is_key_quoted().
Definition node.hpp:264
bool is_stream() const RYML_NOEXCEPT
Forward to Tree::is_stream().
Definition node.hpp:204
NodeType type() const RYML_NOEXCEPT
Forward to Tree::type().
Definition node.hpp:172
bool empty() const RYML_NOEXCEPT
Forward to Tree::empty().
Definition node.hpp:203
bool has_key_anchor() const RYML_NOEXCEPT
Forward to Tree::has_key_anchor().
Definition node.hpp:215
bool is_key_unfiltered() const noexcept
Forward to Tree::is_key_unfiltered().
Definition node.hpp:190
id_type sibling_pos(ConstImpl const &n) const RYML_NOEXCEPT
O(num_siblings).
Definition node.hpp:306
bool is_key_literal() const RYML_NOEXCEPT
Forward to Tree::is_key_literal().
Definition node.hpp:254
csubstr key_ref() const RYML_NOEXCEPT
Forward to Tree::key_ref().
Definition node.hpp:176
bool type_has_none(type_bits bits) const RYML_NOEXCEPT
Forward to Tree::type_has_none().
Definition node.hpp:236
bool has_child(ConstImpl const &n) const RYML_NOEXCEPT
Forward to Tree::has_child().
Definition node.hpp:282
void load_key(Wrapper const &wrapper, bool check_readable=true) const
(2) like (1), but for wrapper tag types such as c4::fmt::base64()
Definition node.hpp:401
bool is_quoted() const RYML_NOEXCEPT
Forward to Tree::is_quoted().
Definition node.hpp:266
bool parent_is_map() const RYML_NOEXCEPT
Forward to Tree::parent_is_map().
Definition node.hpp:222
bool has_child(csubstr name) const RYML_NOEXCEPT
Forward to Tree::has_child().
Definition node.hpp:284
bool is_map() const RYML_NOEXCEPT
Forward to Tree::is_map().
Definition node.hpp:207
bool is_flow_ml1() const RYML_NOEXCEPT
Forward to Tree::is_flow_ml1().
Definition node.hpp:247
NodeScalar const & keysc() const RYML_NOEXCEPT
Forward to Tree::keysc().
Definition node.hpp:184
ReadResult deserialize_child(csubstr child_key, Wrapper const &v) const
(3) like (1), but for wrapper tag types such as c4::fmt::base64()
Definition node.hpp:507
bool is_container() const RYML_NOEXCEPT
Forward to Tree::is_container().
Definition node.hpp:206
id_type num_siblings() const RYML_NOEXCEPT
O(num_children).
Definition node.hpp:303
bool has_key() const RYML_NOEXCEPT
Forward to Tree::has_key().
Definition node.hpp:210
csubstr key_tag() const RYML_NOEXCEPT
Forward to Tree::key_tag().
Definition node.hpp:175
csubstr val_ref() const RYML_NOEXCEPT
Forward to Tree::val_ref().
Definition node.hpp:181
csubstr key() const RYML_NOEXCEPT
Forward to Tree::key().
Definition node.hpp:174
bool has_sibling(csubstr name) const RYML_NOEXCEPT
Forward to Tree::has_sibling().
Definition node.hpp:289
NodeType key_style() const RYML_NOEXCEPT
Forward to Tree::key_style().
Definition node.hpp:238
bool has_key_tag() const RYML_NOEXCEPT
Forward to Tree::has_key_tag().
Definition node.hpp:213
csubstr val_tag() const RYML_NOEXCEPT
Forward to Tree::val_tag().
Definition node.hpp:180
bool is_ancestor(ConstImpl const &ancestor) const RYML_NOEXCEPT
Forward to Tree::is_ancestor() Node must be readable.
Definition node.hpp:280
csubstr val_anchor() const RYML_NOEXCEPT
Forward to Tree::val_anchor().
Definition node.hpp:182
bool has_parent() const RYML_NOEXCEPT
Forward to Tree::has_parent() Node must be readable.
Definition node.hpp:279
bool is_val_squo() const RYML_NOEXCEPT
Forward to Tree::is_val_squo().
Definition node.hpp:259
bool is_val_ref() const RYML_NOEXCEPT
Forward to Tree::is_val_ref().
Definition node.hpp:219
bool has_other_siblings() const RYML_NOEXCEPT
Forward to Tree::has_other_siblings().
Definition node.hpp:290
bool has_flow_space() const RYML_NOEXCEPT
Forward to Tree::has_flow_space().
Definition node.hpp:250
bool is_val_styled() const RYML_NOEXCEPT
Forward to Tree::is_val_styled().
Definition node.hpp:253
bool val_is_null() const RYML_NOEXCEPT
Forward to Tree::val_is_null().
Definition node.hpp:188
bool has_sibling(id_type node) const RYML_NOEXCEPT
Forward to Tree::has_sibling().
Definition node.hpp:288
id_type child_pos(ConstImpl const &n) const RYML_NOEXCEPT
O(num_children).
Definition node.hpp:305
bool is_container_styled() const RYML_NOEXCEPT
Forward to Tree::is_container_styled().
Definition node.hpp:241
ReadResult deserialize_child(id_type child_pos, T *v) const
(1) find a child by position and deserialize its contents to the given variable (ie call ....
Definition node.hpp:526
csubstr val() const RYML_NOEXCEPT
Forward to Tree::val().
Definition node.hpp:179
ReadResult deserialize_child(csubstr child_key, T *v) const
(1) find a child by name and deserialize its contents to the given variable (ie call ....
Definition node.hpp:485
bool is_key_ref() const RYML_NOEXCEPT
Forward to Tree::is_key_ref().
Definition node.hpp:218
bool key_is_null() const RYML_NOEXCEPT
Forward to Tree::key_is_null().
Definition node.hpp:187
NodeType val_style() const RYML_NOEXCEPT
Forward to Tree::val_style().
Definition node.hpp:239
ReadResult deserialize_child(csubstr child_key, T *v, T const &fallback) const
(2) like (1), but assign from fallback if no such child exists.
Definition node.hpp:496
bool parent_is_seq() const RYML_NOEXCEPT
Forward to Tree::parent_is_seq().
Definition node.hpp:221
bool is_doc() const RYML_NOEXCEPT
Forward to Tree::is_doc().
Definition node.hpp:205
ReadResult deserialize(Wrapper const &wrapper) const
(2) like (1), but for wrapper tag types such as c4::fmt::base64()
Definition node.hpp:437
bool is_key_dquo() const RYML_NOEXCEPT
Forward to Tree::is_key_dquo().
Definition node.hpp:260
id_type num_children() const RYML_NOEXCEPT
O(num_children).
Definition node.hpp:302
bool is_val_unfiltered() const noexcept
Forward to Tree::is_val_unfiltered().
Definition node.hpp:191
bool is_flow_mlx() const RYML_NOEXCEPT
Forward to Tree::is_flow_mlx().
Definition node.hpp:249
ReadResult deserialize(T *v) const
(1) deserialize the node's contents (val or container) to the given variable, forwarding to the user-...
Definition node.hpp:428
bool is_flow_sl() const RYML_NOEXCEPT
Forward to Tree::is_flow_sl().
Definition node.hpp:244
bool is_flow() const RYML_NOEXCEPT
Forward to Tree::is_flow().
Definition node.hpp:243
ReadResult deserialize_key(Wrapper const &wrapper) const
(2) like (1), but for wrapper tag types such as c4::fmt::base64()
Definition node.hpp:460
bool is_block() const RYML_NOEXCEPT
Forward to Tree::is_block().
Definition node.hpp:242
bool is_key_folded() const RYML_NOEXCEPT
Forward to Tree::is_key_folded().
Definition node.hpp:256
Location location(Parser const &parser) const
Definition node.hpp:318
ReadResult deserialize_child(id_type child_pos, T *v, T const &fallback) const
(2) like (1), but assign from fallback if no such child exists
Definition node.hpp:537
bool is_val_plain() const RYML_NOEXCEPT
Forward to Tree::is_val_plain().
Definition node.hpp:263
bool is_seq() const RYML_NOEXCEPT
Forward to Tree::is_seq().
Definition node.hpp:208
bool is_val_folded() const RYML_NOEXCEPT
Forward to Tree::is_val_folded().
Definition node.hpp:257
static void err_visit_(Tree const *tree, id_type id, const char *msg)
Definition node.hpp:615
bool has_children() const RYML_NOEXCEPT
Forward to Tree::has_children().
Definition node.hpp:285
bool is_val_quoted() const RYML_NOEXCEPT
Forward to Tree::is_val_quoted().
Definition node.hpp:265
bool is_val_literal() const RYML_NOEXCEPT
Forward to Tree::is_val_literal().
Definition node.hpp:255
bool has_child(id_type node) const RYML_NOEXCEPT
Forward to Tree::has_child().
Definition node.hpp:283
bool is_key_squo() const RYML_NOEXCEPT
Forward to Tree::is_key_squo().
Definition node.hpp:258
bool is_flow_mln() const RYML_NOEXCEPT
Forward to Tree::is_flow_mln().
Definition node.hpp:248
void load(T *v, bool check_readable=true) const
(1) deserialize the node's contents (val or container) to the given variable, forwarding to the user-...
Definition node.hpp:345
ReadResult deserialize_key(T *v) const
(1) deserialize the node's key (necessarily a scalar) to the given variable, forwarding to the user-o...
Definition node.hpp:451
bool has_val() const RYML_NOEXCEPT
Forward to Tree::has_val().
Definition node.hpp:209
bool has_sibling(ConstImpl const &n) const RYML_NOEXCEPT
Forward to Tree::has_sibling().
Definition node.hpp:287
bool is_keyval() const RYML_NOEXCEPT
Forward to Tree::is_keyval().
Definition node.hpp:212
bool has_val_tag() const RYML_NOEXCEPT
Forward to Tree::has_val_tag().
Definition node.hpp:214
id_type num_other_siblings() const RYML_NOEXCEPT
O(num_siblings).
Definition node.hpp:304
bool is_val_dquo() const RYML_NOEXCEPT
Forward to Tree::is_val_dquo().
Definition node.hpp:261
bool is_ref() const RYML_NOEXCEPT
Forward to Tree::is_ref().
Definition node.hpp:220