rapidyaml  0.12.1
parse and emit YAML, and do it fast
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 #include <cstddef>
7 
8 #include "c4/yml/tree.hpp"
9 #include "c4/base64.hpp"
10 
11 #ifdef __clang__
12 # pragma clang diagnostic push
13 # pragma clang diagnostic ignored "-Wtype-limits"
14 # pragma clang diagnostic ignored "-Wold-style-cast"
15 #elif defined(__GNUC__)
16 # pragma GCC diagnostic push
17 # pragma GCC diagnostic ignored "-Wtype-limits"
18 # pragma GCC diagnostic ignored "-Wold-style-cast"
19 # pragma GCC diagnostic ignored "-Wuseless-cast"
20 #elif defined(_MSC_VER)
21 # pragma warning(push)
22 # pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
23 # pragma warning(disable: 4296/*expression is always 'boolean_value'*/)
24 #endif
25 
26 // NOLINTBEGIN(modernize-avoid-c-style-cast)
27 
28 namespace c4 {
29 namespace yml {
30 
31 /** @addtogroup doc_node_classes
32  *
33  * @{
34  */
35 
36 
37 /** @defgroup doc_serialization_helpers Serialization helpers
38  *
39  * @{
40  */
41 template<class K> struct Key { K & k; }; // NOLINT
43 template<> struct Key<fmt::base64_wrapper> { fmt::base64_wrapper wrapper; };
44 
45 template<class K> C4_ALWAYS_INLINE Key<K> key(K & k) { return Key<K>{k}; }
47 C4_ALWAYS_INLINE Key<fmt::base64_wrapper> key(fmt::base64_wrapper w) { return {w}; }
48 
49 
50 template<class T> void write(NodeRef *n, T const& v);
51 
52 template<class T> inline bool read(ConstNodeRef const& C4_RESTRICT n, T *v);
53 template<class T> inline bool read(NodeRef const& C4_RESTRICT n, T *v);
54 template<class T> inline bool readkey(ConstNodeRef const& C4_RESTRICT n, T *v);
55 template<class T> inline bool readkey(NodeRef const& C4_RESTRICT n, T *v);
56 
57 /** @} */
58 
59 
60 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
62 //-----------------------------------------------------------------------------
63 
64 // forward decls
65 class NodeRef;
66 class ConstNodeRef;
67 
68 
69 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
71 //-----------------------------------------------------------------------------
72 
73 /** @cond dev */
74 namespace detail {
75 
76 template<class NodeRefType>
77 struct child_iterator
78 {
79  using value_type = NodeRefType;
80  using tree_type = typename NodeRefType::tree_type;
81 
82  tree_type * C4_RESTRICT m_tree;
83  id_type m_child_id;
84 
85  child_iterator(tree_type * t, id_type id) : m_tree(t), m_child_id(id) {}
86 
87  child_iterator& operator++ () { _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_child_id != NONE, m_tree, NONE); m_child_id = m_tree->next_sibling(m_child_id); return *this; }
88  child_iterator& operator-- () { _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_child_id != NONE, m_tree, NONE); m_child_id = m_tree->prev_sibling(m_child_id); return *this; }
89 
90  NodeRefType operator* () const { return NodeRefType(m_tree, m_child_id); }
91  NodeRefType operator-> () const { return NodeRefType(m_tree, m_child_id); }
92 
93  bool operator!= (child_iterator that) const { _RYML_ASSERT_VISIT(m_tree == that.m_tree, m_tree, NONE); return m_child_id != that.m_child_id; }
94  bool operator== (child_iterator that) const { _RYML_ASSERT_VISIT(m_tree == that.m_tree, m_tree, NONE); return m_child_id == that.m_child_id; }
95 };
96 
97 template<class NodeRefType>
98 struct children_view_
99 {
100  using n_iterator = child_iterator<NodeRefType>;
101 
102  n_iterator b, e;
103 
104  children_view_(n_iterator const& C4_RESTRICT b_,
105  n_iterator const& C4_RESTRICT e_) : b(b_), e(e_) {}
106 
107  n_iterator begin() const { return b; }
108  n_iterator end () const { return e; }
109 };
110 
111 template<class NodeRefType, class Visitor>
112 bool _visit(NodeRefType &node, Visitor fn, id_type indentation_level, bool skip_root=false)
113 {
114  id_type increment = 0;
115  if( ! (node.is_root() && skip_root))
116  {
117  if(fn(node, indentation_level))
118  return true;
119  ++increment;
120  }
121  if(node.has_children())
122  {
123  for(auto ch : node.children())
124  {
125  if(_visit(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
126  {
127  return true;
128  }
129  }
130  }
131  return false;
132 }
133 
134 template<class NodeRefType, class Visitor>
135 bool _visit_stacked(NodeRefType &node, Visitor fn, id_type indentation_level, bool skip_root=false)
136 {
137  id_type increment = 0;
138  if( ! (node.is_root() && skip_root))
139  {
140  if(fn(node, indentation_level))
141  {
142  return true;
143  }
144  ++increment;
145  }
146  if(node.has_children())
147  {
148  fn.push(node, indentation_level);
149  for(auto ch : node.children())
150  {
151  if(_visit_stacked(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
152  {
153  fn.pop(node, indentation_level);
154  return true;
155  }
156  }
157  fn.pop(node, indentation_level);
158  }
159  return false;
160 }
161 
162 template<class Impl, class ConstImpl>
163 struct RoNodeMethods;
164 } // detail
165 /** @endcond */
166 
167 //-----------------------------------------------------------------------------
168 //-----------------------------------------------------------------------------
169 //-----------------------------------------------------------------------------
170 
171 
172 /** a CRTP base providing read-only methods for @ref ConstNodeRef and @ref NodeRef */
173 namespace detail {
174 template<class Impl, class ConstImpl>
175 struct RoNodeMethods // NOLINT
176 {
177  C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wcast-align")
178  /** @cond dev */
179  // helper CRTP macros, undefined at the end
180  #define tree_ ((ConstImpl const* C4_RESTRICT)this)->m_tree
181  #define id_ ((ConstImpl const* C4_RESTRICT)this)->m_id
182  #define tree__ ((Impl const* C4_RESTRICT)this)->m_tree
183  #define id__ ((Impl const* C4_RESTRICT)this)->m_id
184  // require readable: this is a precondition for reading from the
185  // tree using this object.
186  #define _C4RR() \
187  _RYML_ASSERT_BASIC(tree_ != nullptr); \
188  _RYML_ASSERT_VISIT_(tree_->m_callbacks, id_ != NONE, tree_, id_); \
189  _RYML_ASSERT_VISIT_(tree_->m_callbacks, (((Impl const* C4_RESTRICT)this)->readable()), tree_, id_)
190  // a SFINAE beautifier to enable a function only if the
191  // implementation is mutable
192  #define _C4_IF_MUTABLE(ty) typename std::enable_if<!std::is_same<U, ConstImpl>::value, ty>::type
193  /** @endcond */
194 
195 public:
196 
197  /** @name node property getters */
198  /** @{ */
199 
200  /** returns the data or null when the id is NONE */
201  C4_ALWAYS_INLINE NodeData const* get() const RYML_NOEXCEPT { return ((Impl const*)this)->readable() ? tree_->get(id_) : nullptr; }
202 
203  /** returns the data or null when the id is NONE */
204  template<class U=Impl>
205  C4_ALWAYS_INLINE auto get() RYML_NOEXCEPT -> _C4_IF_MUTABLE(NodeData*) { return ((Impl const*)this)->readable() ? tree__->get(id__) : nullptr; }
206 
207  C4_ALWAYS_INLINE NodeType type() const RYML_NOEXCEPT { _C4RR(); return tree_->type(id_); } /**< Forward to @ref Tree::type(). Node must be readable. */
208  C4_ALWAYS_INLINE const char* type_str() const RYML_NOEXCEPT { _C4RR(); return tree_->type_str(id_); } /**< Forward to @ref Tree::type_str(). Node must be readable. */
209 
210  C4_ALWAYS_INLINE csubstr key() const RYML_NOEXCEPT { _C4RR(); return tree_->key(id_); } /**< Forward to @ref Tree::key(). Node must be readable. */
211  C4_ALWAYS_INLINE csubstr key_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->key_tag(id_); } /**< Forward to @ref Tree::key_tag(). Node must be readable. */
212  C4_ALWAYS_INLINE csubstr key_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->key_ref(id_); } /**< Forward to @ref Tree::key_ref(). Node must be readable. */
213  C4_ALWAYS_INLINE csubstr key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->key_anchor(id_); } /**< Forward to @ref Tree::key_anchor(). Node must be readable. */
214 
215  C4_ALWAYS_INLINE csubstr val() const RYML_NOEXCEPT { _C4RR(); return tree_->val(id_); } /**< Forward to @ref Tree::val(). Node must be readable. */
216  C4_ALWAYS_INLINE csubstr val_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->val_tag(id_); } /**< Forward to @ref Tree::val_tag(). Node must be readable. */
217  C4_ALWAYS_INLINE csubstr val_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->val_ref(id_); } /**< Forward to @ref Tree::val_ref(). Node must be readable. */
218  C4_ALWAYS_INLINE csubstr val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->val_anchor(id_); } /**< Forward to @ref Tree::val_anchor(). Node must be readable. */
219 
220  C4_ALWAYS_INLINE NodeScalar const& keysc() const RYML_NOEXCEPT { _C4RR(); return tree_->keysc(id_); } /**< Forward to @ref Tree::keysc(). Node must be readable. */
221  C4_ALWAYS_INLINE NodeScalar const& valsc() const RYML_NOEXCEPT { _C4RR(); return tree_->valsc(id_); } /**< Forward to @ref Tree::valsc(). Node must be readable. */
222 
223  C4_ALWAYS_INLINE bool key_is_null() const RYML_NOEXCEPT { _C4RR(); return tree_->key_is_null(id_); } /**< Forward to @ref Tree::key_is_null(). Node must be readable. */
224  C4_ALWAYS_INLINE bool val_is_null() const RYML_NOEXCEPT { _C4RR(); return tree_->val_is_null(id_); } /**< Forward to @ref Tree::val_is_null(). Node must be readable. */
225 
226  C4_ALWAYS_INLINE bool is_key_unfiltered() const noexcept { _C4RR(); return tree_->is_key_unfiltered(id_); } /**< Forward to @ref Tree::is_key_unfiltered(). Node must be readable. */
227  C4_ALWAYS_INLINE bool is_val_unfiltered() const noexcept { _C4RR(); return tree_->is_val_unfiltered(id_); } /**< Forward to @ref Tree::is_val_unfiltered(). Node must be readable. */
228 
229  /** @} */
230 
231 public:
232 
233  /** @name node type predicates */
234  /** @{ */
235 
236  C4_ALWAYS_INLINE bool empty() const RYML_NOEXCEPT { _C4RR(); return tree_->empty(id_); } /**< Forward to @ref Tree::empty(). Node must be readable. */
237  C4_ALWAYS_INLINE bool is_stream() const RYML_NOEXCEPT { _C4RR(); return tree_->is_stream(id_); } /**< Forward to @ref Tree::is_stream(). Node must be readable. */
238  C4_ALWAYS_INLINE bool is_doc() const RYML_NOEXCEPT { _C4RR(); return tree_->is_doc(id_); } /**< Forward to @ref Tree::is_doc(). Node must be readable. */
239  C4_ALWAYS_INLINE bool is_container() const RYML_NOEXCEPT { _C4RR(); return tree_->is_container(id_); } /**< Forward to @ref Tree::is_container(). Node must be readable. */
240  C4_ALWAYS_INLINE bool is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->is_map(id_); } /**< Forward to @ref Tree::is_map(). Node must be readable. */
241  C4_ALWAYS_INLINE bool is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->is_seq(id_); } /**< Forward to @ref Tree::is_seq(). Node must be readable. */
242  C4_ALWAYS_INLINE bool has_val() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val(id_); } /**< Forward to @ref Tree::has_val(). Node must be readable. */
243  C4_ALWAYS_INLINE bool has_key() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key(id_); } /**< Forward to @ref Tree::has_key(). Node must be readable. */
244  C4_ALWAYS_INLINE bool is_val() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val(id_); } /**< Forward to @ref Tree::is_val(). Node must be readable. */
245  C4_ALWAYS_INLINE bool is_keyval() const RYML_NOEXCEPT { _C4RR(); return tree_->is_keyval(id_); } /**< Forward to @ref Tree::is_keyval(). Node must be readable. */
246  C4_ALWAYS_INLINE bool has_key_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_tag(id_); } /**< Forward to @ref Tree::has_key_tag(). Node must be readable. */
247  C4_ALWAYS_INLINE bool has_val_tag() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_tag(id_); } /**< Forward to @ref Tree::has_val_tag(). Node must be readable. */
248  C4_ALWAYS_INLINE bool has_key_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_key_anchor(id_); } /**< Forward to @ref Tree::has_key_anchor(). Node must be readable. */
249  C4_ALWAYS_INLINE bool has_val_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_val_anchor(id_); } /**< Forward to @ref Tree::has_val_anchor(). Node must be readable. */
250  C4_ALWAYS_INLINE bool has_anchor() const RYML_NOEXCEPT { _C4RR(); return tree_->has_anchor(id_); } /**< Forward to @ref Tree::has_anchor(). Node must be readable. */
251  C4_ALWAYS_INLINE bool is_key_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_ref(id_); } /**< Forward to @ref Tree::is_key_ref(). Node must be readable. */
252  C4_ALWAYS_INLINE bool is_val_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_ref(id_); } /**< Forward to @ref Tree::is_val_ref(). Node must be readable. */
253  C4_ALWAYS_INLINE bool is_ref() const RYML_NOEXCEPT { _C4RR(); return tree_->is_ref(id_); } /**< Forward to @ref Tree::is_ref(). Node must be readable. */
254  C4_ALWAYS_INLINE bool parent_is_seq() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_seq(id_); } /**< Forward to @ref Tree::parent_is_seq(). Node must be readable. */
255  C4_ALWAYS_INLINE bool parent_is_map() const RYML_NOEXCEPT { _C4RR(); return tree_->parent_is_map(id_); } /**< Forward to @ref Tree::parent_is_map(). Node must be readable. */
256 
257  RYML_DEPRECATED("use has_key_anchor()") bool is_key_anchor() const noexcept { _C4RR(); return tree_->has_key_anchor(id_); }
258  RYML_DEPRECATED("use has_val_anchor()") bool is_val_hanchor() const noexcept { _C4RR(); return tree_->has_val_anchor(id_); }
259  RYML_DEPRECATED("use has_anchor()") bool is_anchor() const noexcept { _C4RR(); return tree_->has_anchor(id_); }
260  RYML_DEPRECATED("use has_anchor() || is_ref()") bool is_anchor_or_ref() const noexcept { _C4RR(); return tree_->is_anchor_or_ref(id_); }
261 
262  /** @} */
263 
264 public:
265 
266  /** @name style predicates */
267  /** @{ */
268 
269  // documentation to the right -->
270 
271  C4_ALWAYS_INLINE bool type_has_any(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_any(id_, bits); } /**< Forward to @ref Tree::type_has_any(). Node must be readable. */
272  C4_ALWAYS_INLINE bool type_has_all(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_all(id_, bits); } /**< Forward to @ref Tree::type_has_all(). Node must be readable. */
273  C4_ALWAYS_INLINE bool type_has_none(NodeType_e bits) const RYML_NOEXCEPT { _C4RR(); return tree_->type_has_none(id_, bits); } /**< Forward to @ref Tree::type_has_none(). Node must be readable. */
274 
275  C4_ALWAYS_INLINE NodeType key_style() const RYML_NOEXCEPT { _C4RR(); return tree_->key_style(id_); } /**< Forward to @ref Tree::key_style(). Node must be readable. */
276  C4_ALWAYS_INLINE NodeType val_style() const RYML_NOEXCEPT { _C4RR(); return tree_->val_style(id_); } /**< Forward to @ref Tree::val_style(). Node must be readable. */
277 
278  C4_ALWAYS_INLINE bool is_container_styled() const RYML_NOEXCEPT { _C4RR(); return tree_->is_container_styled(id_); } /**< Forward to @ref Tree::is_container_styled(). Node must be readable. */
279  C4_ALWAYS_INLINE bool is_block() const RYML_NOEXCEPT { _C4RR(); return tree_->is_block(id_); } /**< Forward to @ref Tree::is_block(). Node must be readable. */
280  C4_ALWAYS_INLINE bool is_flow_sl() const RYML_NOEXCEPT { _C4RR(); return tree_->is_flow_sl(id_); } /**< Forward to @ref Tree::is_flow_sl(). Node must be readable. */
281  C4_ALWAYS_INLINE bool is_flow_ml() const RYML_NOEXCEPT { _C4RR(); return tree_->is_flow_ml(id_); } /**< Forward to @ref Tree::is_flow_ml(). Node must be readable. */
282  C4_ALWAYS_INLINE bool is_flow() const RYML_NOEXCEPT { _C4RR(); return tree_->is_flow(id_); } /**< Forward to @ref Tree::is_flow(). Node must be readable. */
283 
284  C4_ALWAYS_INLINE bool is_key_styled() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_styled(id_); } /**< Forward to @ref Tree::is_key_styled(). Node must be readable. */
285  C4_ALWAYS_INLINE bool is_val_styled() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_styled(id_); } /**< Forward to @ref Tree::is_val_styled(). Node must be readable. */
286  C4_ALWAYS_INLINE bool is_key_literal() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_literal(id_); } /**< Forward to @ref Tree::is_key_literal(). Node must be readable. */
287  C4_ALWAYS_INLINE bool is_val_literal() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_literal(id_); } /**< Forward to @ref Tree::is_val_literal(). Node must be readable. */
288  C4_ALWAYS_INLINE bool is_key_folded() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_folded(id_); } /**< Forward to @ref Tree::is_key_folded(). Node must be readable. */
289  C4_ALWAYS_INLINE bool is_val_folded() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_folded(id_); } /**< Forward to @ref Tree::is_val_folded(). Node must be readable. */
290  C4_ALWAYS_INLINE bool is_key_squo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_squo(id_); } /**< Forward to @ref Tree::is_key_squo(). Node must be readable. */
291  C4_ALWAYS_INLINE bool is_val_squo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_squo(id_); } /**< Forward to @ref Tree::is_val_squo(). Node must be readable. */
292  C4_ALWAYS_INLINE bool is_key_dquo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_dquo(id_); } /**< Forward to @ref Tree::is_key_dquo(). Node must be readable. */
293  C4_ALWAYS_INLINE bool is_val_dquo() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_dquo(id_); } /**< Forward to @ref Tree::is_val_dquo(). Node must be readable. */
294  C4_ALWAYS_INLINE bool is_key_plain() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_plain(id_); } /**< Forward to @ref Tree::is_key_plain(). Node must be readable. */
295  C4_ALWAYS_INLINE bool is_val_plain() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_plain(id_); } /**< Forward to @ref Tree::is_val_plain(). Node must be readable. */
296  C4_ALWAYS_INLINE bool is_key_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_key_quoted(id_); } /**< Forward to @ref Tree::is_key_quoted(). Node must be readable. */
297  C4_ALWAYS_INLINE bool is_val_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_val_quoted(id_); } /**< Forward to @ref Tree::is_val_quoted(). Node must be readable. */
298  C4_ALWAYS_INLINE bool is_quoted() const RYML_NOEXCEPT { _C4RR(); return tree_->is_quoted(id_); } /**< Forward to @ref Tree::is_quoted(). Node must be readable. */
299 
300  /** @} */
301 
302 public:
303 
304  /** @name hierarchy predicates */
305  /** @{ */
306 
307  // documentation to the right -->
308 
309  C4_ALWAYS_INLINE bool is_root() const RYML_NOEXCEPT { _C4RR(); return tree_->is_root(id_); } /**< Forward to @ref Tree::is_root(). Node must be readable. */
310  C4_ALWAYS_INLINE bool has_parent() const RYML_NOEXCEPT { _C4RR(); return tree_->has_parent(id_); } /**< Forward to @ref Tree::has_parent() Node must be readable. */
311  C4_ALWAYS_INLINE bool is_ancestor(ConstImpl const& ancestor) const RYML_NOEXCEPT { _C4RR(); return tree_->is_ancestor(id_, ancestor.m_id); } /**< Forward to @ref Tree::is_ancestor() Node must be readable. */
312 
313  C4_ALWAYS_INLINE bool has_child(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_child(id_, n.m_id) : false; } /**< Forward to @ref Tree::has_child(). Node must be readable. */
314  C4_ALWAYS_INLINE bool has_child(id_type node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, node); } /**< Forward to @ref Tree::has_child(). Node must be readable. */
315  C4_ALWAYS_INLINE bool has_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_child(id_, name); } /**< Forward to @ref Tree::has_child(). Node must be readable. */
316  C4_ALWAYS_INLINE bool has_children() const RYML_NOEXCEPT { _C4RR(); return tree_->has_children(id_); } /**< Forward to @ref Tree::has_children(). Node must be readable. */
317 
318  C4_ALWAYS_INLINE bool has_sibling(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); return n.readable() ? tree_->has_sibling(id_, n.m_id) : false; } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */
319  C4_ALWAYS_INLINE bool has_sibling(id_type node) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, node); } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */
320  C4_ALWAYS_INLINE bool has_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return tree_->has_sibling(id_, name); } /**< Forward to @ref Tree::has_sibling(). Node must be readable. */
321  C4_ALWAYS_INLINE bool has_other_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->has_other_siblings(id_); } /**< Forward to @ref Tree::has_other_siblings(). Node must be readable. */
322 
323  RYML_DEPRECATED("use has_other_siblings()") bool has_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->has_siblings(id_); }
324 
325  /** @} */
326 
327 public:
328 
329  /** @name hierarchy getters */
330  /** @{ */
331 
332  // documentation to the right -->
333 
334  template<class U=Impl>
335  C4_ALWAYS_INLINE auto doc(id_type i) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _RYML_ASSERT_BASIC(tree_); return {tree__, tree__->doc(i)}; } /**< Forward to @ref Tree::doc(). Node must be readable. */
336  C4_ALWAYS_INLINE ConstImpl doc(id_type i) const RYML_NOEXCEPT { _RYML_ASSERT_BASIC(tree_); return {tree_, tree_->doc(i)}; } /**< Forward to @ref Tree::doc(). Node must be readable. succeeds even when the node may have invalid or seed id */
337 
338  template<class U=Impl>
339  C4_ALWAYS_INLINE auto parent() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->parent(id__)}; } /**< Forward to @ref Tree::parent(). Node must be readable. */
340  C4_ALWAYS_INLINE ConstImpl parent() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->parent(id_)}; } /**< Forward to @ref Tree::parent(). Node must be readable. */
341 
342  template<class U=Impl>
343  C4_ALWAYS_INLINE auto first_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_child(id__)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */
344  C4_ALWAYS_INLINE ConstImpl first_child() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_child(id_)}; } /**< Forward to @ref Tree::first_child(). Node must be readable. */
345 
346  template<class U=Impl>
347  C4_ALWAYS_INLINE auto last_child() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_child(id__)}; } /**< Forward to @ref Tree::last_child(). Node must be readable. */
348  C4_ALWAYS_INLINE ConstImpl last_child () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_child (id_)}; } /**< Forward to @ref Tree::last_child(). Node must be readable. */
349 
350  template<class U=Impl>
351  C4_ALWAYS_INLINE auto child(id_type pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->child(id__, pos)}; } /**< Forward to @ref Tree::child(). Node must be readable. */
352  C4_ALWAYS_INLINE ConstImpl child(id_type pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->child(id_, pos)}; } /**< Forward to @ref Tree::child(). Node must be readable. */
353 
354  template<class U=Impl>
355  C4_ALWAYS_INLINE auto find_child(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_child(id__, name)}; } /**< Forward to @ref Tree::find_child(). Node must be readable. */
356  C4_ALWAYS_INLINE ConstImpl find_child(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_child(id_, name)}; } /**< Forward to @ref Tree::find_child(). Node must be readable. */
357 
358  template<class U=Impl>
359  C4_ALWAYS_INLINE auto prev_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->prev_sibling(id__)}; } /**< Forward to @ref Tree::prev_sibling(). Node must be readable. */
360  C4_ALWAYS_INLINE ConstImpl prev_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->prev_sibling(id_)}; } /**< Forward to @ref Tree::prev_sibling(). Node must be readable. */
361 
362  template<class U=Impl>
363  C4_ALWAYS_INLINE auto next_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->next_sibling(id__)}; } /**< Forward to @ref Tree::next_sibling(). Node must be readable. */
364  C4_ALWAYS_INLINE ConstImpl next_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->next_sibling(id_)}; } /**< Forward to @ref Tree::next_sibling(). Node must be readable. */
365 
366  template<class U=Impl>
367  C4_ALWAYS_INLINE auto first_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->first_sibling(id__)}; } /**< Forward to @ref Tree::first_sibling(). Node must be readable. */
368  C4_ALWAYS_INLINE ConstImpl first_sibling() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->first_sibling(id_)}; } /**< Forward to @ref Tree::first_sibling(). Node must be readable. */
369 
370  template<class U=Impl>
371  C4_ALWAYS_INLINE auto last_sibling() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->last_sibling(id__)}; } /**< Forward to @ref Tree::last_sibling(). Node must be readable. */
372  C4_ALWAYS_INLINE ConstImpl last_sibling () const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->last_sibling(id_)}; } /**< Forward to @ref Tree::last_sibling(). Node must be readable. */
373 
374  template<class U=Impl>
375  C4_ALWAYS_INLINE auto sibling(id_type pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->sibling(id__, pos)}; } /**< Forward to @ref Tree::sibling(). Node must be readable. */
376  C4_ALWAYS_INLINE ConstImpl sibling(id_type pos) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->sibling(id_, pos)}; } /**< Forward to @ref Tree::sibling(). Node must be readable. */
377 
378  template<class U=Impl>
379  C4_ALWAYS_INLINE auto find_sibling(csubstr name) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->find_sibling(id__, name)}; } /**< Forward to @ref Tree::find_sibling(). Node must be readable. */
380  C4_ALWAYS_INLINE ConstImpl find_sibling(csubstr name) const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->find_sibling(id_, name)}; } /**< Forward to @ref Tree::find_sibling(). Node must be readable. */
381 
382  template<class U=Impl>
383  C4_ALWAYS_INLINE auto ancestor_doc() RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl) { _C4RR(); return {tree__, tree__->ancestor_doc(id__)}; } /**< Forward to @ref Tree::ancestor_doc(). Node must be readable. */
384  C4_ALWAYS_INLINE ConstImpl ancestor_doc() const RYML_NOEXCEPT { _C4RR(); return {tree_, tree_->ancestor_doc(id_)}; } /**< Forward to @ref Tree::ancestor_doc(). Node must be readable. */
385 
386  C4_ALWAYS_INLINE id_type num_children() const RYML_NOEXCEPT { _C4RR(); return tree_->num_children(id_); } /**< O(num_children). Forward to @ref Tree::num_children(). */
387  C4_ALWAYS_INLINE id_type num_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->num_siblings(id_); } /**< O(num_children). Forward to @ref Tree::num_siblings(). */
388  C4_ALWAYS_INLINE id_type num_other_siblings() const RYML_NOEXCEPT { _C4RR(); return tree_->num_other_siblings(id_); } /**< O(num_siblings). Forward to @ref Tree::num_other_siblings(). */
389  C4_ALWAYS_INLINE id_type child_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_ASSERT_VISIT_(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(). */
390  C4_ALWAYS_INLINE id_type sibling_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_ASSERT_VISIT_(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(). */
391 
392  C4_ALWAYS_INLINE id_type depth_asc() const RYML_NOEXCEPT { _C4RR(); return tree_->depth_asc(id_); } /** O(log(num_nodes)). Forward to Tree::depth_asc(). Node must be readable. */
393  C4_ALWAYS_INLINE id_type depth_desc() const RYML_NOEXCEPT { _C4RR(); return tree_->depth_desc(id_); } /** O(num_nodes). Forward to Tree::depth_desc(). Node must be readable. */
394 
395  /** @} */
396 
397 public:
398 
399  /** @name square_brackets
400  * operator[] */
401  /** @{ */
402 
403  /** Find child by key; complexity is O(num_children).
404  *
405  * Returns the requested node, or an object in seed state if no
406  * such child is found (see @ref NodeRef for an explanation of
407  * what is seed state). When the object is in seed state, using it
408  * to read from the tree is UB. The seed node can be used to write
409  * to the tree provided that its create() method is called prior
410  * to writing, which happens in most modifying methods in
411  * NodeRef. It is the caller's responsibility to verify that the
412  * returned node is readable before subsequently using it to read
413  * from the tree.
414  *
415  * @warning the calling object must be readable. This precondition
416  * is asserted. The assertion is performed only if @ref
417  * RYML_USE_ASSERT is set to true. As with the non-const overload,
418  * it is UB to call this method if the node is not readable.
419  *
420  * @see https://github.com/biojppm/rapidyaml/issues/389 */
421  template<class U=Impl>
422  C4_ALWAYS_INLINE auto operator[] (csubstr key) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl)
423  {
424  _C4RR();
425  id_type ch = tree__->find_child(id__, key);
426  return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, key);
427  }
428 
429  /** Find child by position; complexity is O(pos).
430  *
431  * Returns the requested node, or an object in seed state if no
432  * such child is found (see @ref NodeRef for an explanation of
433  * what is seed state). When the object is in seed state, using it
434  * to read from the tree is UB. The seed node can be used to write
435  * to the tree provided that its create() method is called prior
436  * to writing, which happens in most modifying methods in
437  * NodeRef. It is the caller's responsibility to verify that the
438  * returned node is readable before subsequently using it to read
439  * from the tree.
440  *
441  * @warning the calling object must be readable. This precondition
442  * is asserted. The assertion is performed only if @ref
443  * RYML_USE_ASSERT is set to true. As with the non-const overload,
444  * it is UB to call this method if the node is not readable.
445  *
446  * @see https://github.com/biojppm/rapidyaml/issues/389 */
447  template<class U=Impl>
448  C4_ALWAYS_INLINE auto operator[] (id_type pos) RYML_NOEXCEPT -> _C4_IF_MUTABLE(Impl)
449  {
450  _C4RR();
451  id_type ch = tree__->child(id__, pos);
452  return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, pos);
453  }
454 
455  /** Find a child by key; complexity is O(num_children).
456  *
457  * Behaves similar to the non-const overload, but further asserts
458  * that the returned node is readable (because it can never be in
459  * a seed state). The assertion is performed only if @ref
460  * RYML_USE_ASSERT is set to true. As with the non-const overload,
461  * it is UB to use the return value if it is not valid.
462  *
463  * @see https://github.com/biojppm/rapidyaml/issues/389 */
464  C4_ALWAYS_INLINE ConstImpl operator[] (csubstr key) const RYML_NOEXCEPT
465  {
466  _C4RR();
467  id_type ch = tree_->find_child(id_, key);
468  _RYML_ASSERT_VISIT_(tree_->m_callbacks, ch != NONE, tree_, id_);
469  return {tree_, ch};
470  }
471 
472  /** Find a child by position; complexity is O(pos).
473  *
474  * Behaves similar to the non-const overload, but further asserts
475  * that the returned node is readable (because it can never be in
476  * a seed state). This assertion is performed only if @ref
477  * RYML_USE_ASSERT is set to true. As with the non-const overload,
478  * it is UB to use the return value if it is not valid.
479  *
480  * @see https://github.com/biojppm/rapidyaml/issues/389 */
481  C4_ALWAYS_INLINE ConstImpl operator[] (id_type pos) const RYML_NOEXCEPT
482  {
483  _C4RR();
484  id_type ch = tree_->child(id_, pos);
485  _RYML_ASSERT_VISIT_(tree_->m_callbacks, ch != NONE, tree_, id_);
486  return {tree_, ch};
487  }
488 
489  /** @} */
490 
491 public:
492 
493  /** @name at
494  *
495  * These functions are the analogue to operator[], with the
496  * difference that they emit an error instead of an
497  * assertion. That is, if any of the pre or post conditions is
498  * violated, an error is always emitted (resulting in a call to
499  * the error callback).
500  *
501  * @{ */
502 
503  /** Find child by key; complexity is O(num_children).
504  *
505  * Returns the requested node, or an object in seed state if no
506  * such child is found (see @ref NodeRef for an explanation of
507  * what is seed state). When the object is in seed state, using it
508  * to read from the tree is UB. The seed node can be subsequently
509  * used to write to the tree provided that its create() method is
510  * called prior to writing, which happens inside most mutating
511  * methods in NodeRef. It is the caller's responsibility to verify
512  * that the returned node is readable before subsequently using it
513  * to read from the tree.
514  *
515  * @warning This method will call the error callback (regardless
516  * of build type or of the value of RYML_USE_ASSERT) whenever any
517  * of the following preconditions is violated: a) the object is
518  * valid (points at a tree and a node), b) the calling object must
519  * be readable (must not be in seed state), c) the calling object
520  * must be pointing at a MAP node. The preconditions are similar
521  * to the non-const operator[](csubstr), but instead of using
522  * assertions, this function directly checks those conditions and
523  * calls the error callback if any of the checks fail.
524  *
525  * @note since it is valid behavior for the returned node to be in
526  * seed state, the error callback is not invoked when this
527  * happens. */
528  template<class U=Impl>
529  C4_ALWAYS_INLINE auto at(csubstr key) -> _C4_IF_MUTABLE(Impl)
530  {
531  _RYML_CHECK_BASIC(tree_ != nullptr);
532  _RYML_CHECK_VISIT_(tree_->m_callbacks, (id_ >= 0 && id_ < tree_->capacity()), tree_, id_);
533  _RYML_CHECK_VISIT_(tree_->m_callbacks, ((Impl const*)this)->readable(), tree_, id_);
534  _RYML_CHECK_VISIT_(tree_->m_callbacks, tree_->is_map(id_), tree_, id_);
535  id_type ch = tree__->find_child(id__, key);
536  return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, key);
537  }
538 
539  /** Find child by position; complexity is O(pos).
540  *
541  * Returns the requested node, or an object in seed state if no
542  * such child is found (see @ref NodeRef for an explanation of
543  * what is seed state). When the object is in seed state, using it
544  * to read from the tree is UB. The seed node can be used to write
545  * to the tree provided that its create() method is called prior
546  * to writing, which happens in most modifying methods in
547  * NodeRef. It is the caller's responsibility to verify that the
548  * returned node is readable before subsequently using it to read
549  * from the tree.
550  *
551  * @warning This method will call the error callback (regardless
552  * of build type or of the value of RYML_USE_ASSERT) whenever any
553  * of the following preconditions is violated: a) the object is
554  * valid (points at a tree and a node), b) the calling object must
555  * be readable (must not be in seed state), c) the calling object
556  * must be pointing at a MAP node. The preconditions are similar
557  * to the non-const operator[](id_type), but instead of using
558  * assertions, this function directly checks those conditions and
559  * calls the error callback if any of the checks fail.
560  *
561  * @note since it is valid behavior for the returned node to be in
562  * seed state, the error callback is not invoked when this
563  * happens. */
564  template<class U=Impl>
565  C4_ALWAYS_INLINE auto at(id_type pos) -> _C4_IF_MUTABLE(Impl)
566  {
567  _RYML_CHECK_BASIC(tree_ != nullptr);
568  const id_type cap = tree_->capacity();
569  _RYML_CHECK_VISIT_(tree_->m_callbacks, (id_ >= 0 && id_ < cap), tree_, id_);
570  _RYML_CHECK_VISIT_(tree_->m_callbacks, (pos >= 0 && pos < cap), tree_, id_);
571  _RYML_CHECK_VISIT_(tree_->m_callbacks, ((Impl const*)this)->readable(), tree_, id_);
572  _RYML_CHECK_VISIT_(tree_->m_callbacks, tree_->is_container(id_), tree_, id_);
573  id_type ch = tree__->child(id__, pos);
574  return ch != NONE ? Impl(tree__, ch) : Impl(tree__, id__, pos);
575  }
576 
577  /** Get a child by name, with error checking; complexity is
578  * O(num_children).
579  *
580  * Behaves as operator[](csubstr) const, but always raises an
581  * error (even when RYML_USE_ASSERT is set to false) when the
582  * returned node does not exist, or when this node is not
583  * readable, or when it is not a map. This behaviour is similar to
584  * std::vector::at(), but the error consists in calling the error
585  * callback instead of directly raising an exception. */
586  ConstImpl at(csubstr key) const
587  {
588  _RYML_CHECK_BASIC(tree_ != nullptr);
589  _RYML_CHECK_VISIT_(tree_->m_callbacks, (id_ >= 0 && id_ < tree_->capacity()), tree_, id_);
590  _RYML_CHECK_VISIT_(tree_->m_callbacks, ((Impl const*)this)->readable(), tree_, id_);
591  _RYML_CHECK_VISIT_(tree_->m_callbacks, tree_->is_map(id_), tree_, id_);
592  id_type ch = tree_->find_child(id_, key);
593  _RYML_CHECK_VISIT_(tree_->m_callbacks, ch != NONE, tree_, id_);
594  return {tree_, ch};
595  }
596 
597  /** Get a child by position, with error checking; complexity is
598  * O(pos).
599  *
600  * Behaves as operator[](id_type) const, but always raises an error
601  * (even when RYML_USE_ASSERT is set to false) when the returned
602  * node does not exist, or when this node is not readable, or when
603  * it is not a container. This behaviour is similar to
604  * std::vector::at(), but the error consists in calling the error
605  * callback instead of directly raising an exception. */
606  ConstImpl at(id_type pos) const
607  {
608  _RYML_CHECK_BASIC(tree_ != nullptr);
609  const id_type cap = tree_->capacity();
610  _RYML_CHECK_VISIT_(tree_->m_callbacks, (id_ >= 0 && id_ < cap), tree_, id_);
611  _RYML_CHECK_VISIT_(tree_->m_callbacks, (pos >= 0 && pos < cap), tree_, id_);
612  _RYML_CHECK_VISIT_(tree_->m_callbacks, ((Impl const*)this)->readable(), tree_, id_);
613  _RYML_CHECK_VISIT_(tree_->m_callbacks, tree_->is_container(id_), tree_, id_);
614  const id_type ch = tree_->child(id_, pos);
615  _RYML_CHECK_VISIT_(tree_->m_callbacks, ch != NONE, tree_, id_);
616  return {tree_, ch};
617  }
618 
619  /** @} */
620 
621 public:
622 
623  /** @name locations */
624  /** @{ */
625 
626  Location location(Parser const& parser) const
627  {
628  _C4RR();
629  return tree_->location(parser, id_);
630  }
631 
632  /** @} */
633 
634 public:
635 
636  /** @name deserialization */
637  /** @{ */
638 
639  /** deserialize the node's val to the given variable, forwarding
640  * to the user-overrideable @ref read() function. */
641  template<class T>
642  ConstImpl const& operator>> (T &v) const
643  {
644  _C4RR();
645  if( ! read((ConstImpl const&)*this, &v))
646  _RYML_ERR_VISIT_(tree_->m_callbacks, tree_, id_, "could not deserialize value");
647  return *((ConstImpl const*)this);
648  }
649 
650  /** deserialize the node's key to the given variable, forwarding
651  * to the user-overrideable @ref read() function; use @ref key()
652  * to disambiguate; for example: `node >> ryml::key(var)` */
653  template<class T>
654  ConstImpl const& operator>> (Key<T> v) const
655  {
656  _C4RR();
657  if( ! readkey((ConstImpl const&)*this, &v.k))
658  _RYML_ERR_VISIT_(tree_->m_callbacks, tree_, id_, "could not deserialize key");
659  return *((ConstImpl const*)this);
660  }
661 
662  /** look for a child by name, if it exists assign to var. return
663  * true if the child existed. */
664  template<class T>
665  bool get_if(csubstr name, T *var) const
666  {
667  _C4RR();
668  ConstImpl ch = find_child(name);
669  if(!ch.readable())
670  return false;
671  ch >> *var;
672  return true;
673  }
674 
675  /** look for a child by name, if it exists assign to var,
676  * otherwise default to fallback. return true if the child
677  * existed. */
678  template<class T>
679  bool get_if(csubstr name, T *var, T const& fallback) const
680  {
681  _C4RR();
682  ConstImpl ch = find_child(name);
683  if(ch.readable())
684  {
685  ch >> *var;
686  return true;
687  }
688  else
689  {
690  *var = fallback;
691  return false;
692  }
693  }
694 
695  /** @name deserialization_base64 */
696  /** @{ */
697 
698  /** deserialize the node's key as base64. lightweight wrapper over @ref deserialize_key() */
699  ConstImpl const& operator>> (Key<fmt::base64_wrapper> w) const
700  {
702  return *((ConstImpl const*)this);
703  }
704 
705  /** deserialize the node's val as base64. lightweight wrapper over @ref deserialize_val() */
706  ConstImpl const& operator>> (fmt::base64_wrapper w) const
707  {
708  deserialize_val(w);
709  return *((ConstImpl const*)this);
710  }
711 
712  /** decode the base64-encoded key and assign the
713  * decoded blob to the given buffer/
714  * @return the size of base64-decoded blob */
716  {
717  _C4RR();
718  return from_chars(key(), &v);
719  }
720  /** decode the base64-encoded key and assign the
721  * decoded blob to the given buffer/
722  * @return the size of base64-decoded blob */
724  {
725  _C4RR();
726  return from_chars(val(), &v);
727  };
728 
729  /** @} */
730 
731  /** @} */
732 
733 public:
734 
735  #if defined(__clang__) // NOLINT
736  # pragma clang diagnostic push
737  # pragma clang diagnostic ignored "-Wnull-dereference"
738  #elif defined(__GNUC__)
739  # pragma GCC diagnostic push
740  # if __GNUC__ >= 6
741  # pragma GCC diagnostic ignored "-Wnull-dereference"
742  # endif
743  #endif
744 
745  /** @name iteration */
746  /** @{ */
747 
748  using iterator = detail::child_iterator<Impl>;
749  using const_iterator = detail::child_iterator<ConstImpl>;
750  using children_view = detail::children_view_<Impl>;
751  using const_children_view = detail::children_view_<ConstImpl>;
752 
753  template<class U=Impl>
754  C4_ALWAYS_INLINE auto begin() RYML_NOEXCEPT -> _C4_IF_MUTABLE(iterator) { _C4RR(); return iterator(tree__, tree__->first_child(id__)); } /**< get a mutable iterator to the first child. NOT AVAILABLE for ConstNodeRef. */
755  C4_ALWAYS_INLINE const_iterator begin() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, tree_->first_child(id_)); } /**< get an iterator to the first child */
756  C4_ALWAYS_INLINE const_iterator cbegin() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, tree_->first_child(id_)); } /**< get an iterator to the first child */
757 
758  template<class U=Impl>
759  C4_ALWAYS_INLINE auto end() RYML_NOEXCEPT -> _C4_IF_MUTABLE(iterator) { _C4RR(); return iterator(tree__, NONE); } /**< get an iterator to after the last child. NOT AVAILABLE for ConstNodeRef. */
760  /** get an iterator to after the last child */
761  C4_ALWAYS_INLINE const_iterator end() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, NONE); } /**< get an iterator to after the last child */
762  /** get an iterator to after the last child */
763  C4_ALWAYS_INLINE const_iterator cend() const RYML_NOEXCEPT { _C4RR(); return const_iterator(tree_, NONE); } /**< get an iterator to after the last child */
764 
765  template<class U=Impl>
766  C4_ALWAYS_INLINE auto children() RYML_NOEXCEPT -> _C4_IF_MUTABLE(children_view) { _C4RR(); return children_view(begin(), end()); } /**< get an iterable view over children. NOT AVAILABLE for ConstNodeRef. */
767  C4_ALWAYS_INLINE const_children_view children() const RYML_NOEXCEPT { _C4RR(); return const_children_view(begin(), end()); } /**< get an iterable view over children */
768  C4_ALWAYS_INLINE const_children_view cchildren() const RYML_NOEXCEPT { _C4RR(); return const_children_view(begin(), end()); } /**< get an iterable view over children */
769 
770  /** get an iterable view over all siblings (including the calling node) */
771  template<class U=Impl>
772  C4_ALWAYS_INLINE auto siblings() RYML_NOEXCEPT -> _C4_IF_MUTABLE(children_view)
773  {
774  _C4RR();
775  NodeData const *nd = tree__->get(id__);
776  return (nd->m_parent != NONE) ? // does it have a parent?
777  children_view(iterator(tree__, tree_->get(nd->m_parent)->m_first_child), iterator(tree__, NONE))
778  :
779  children_view(end(), end());
780  }
781  /** get an iterable view over all siblings (including the calling node) */
782  C4_ALWAYS_INLINE const_children_view siblings() const RYML_NOEXCEPT
783  {
784  _C4RR();
785  NodeData const *nd = tree_->get(id_);
786  return (nd->m_parent != NONE) ? // does it have a parent?
787  const_children_view(const_iterator(tree_, tree_->get(nd->m_parent)->m_first_child), const_iterator(tree_, NONE))
788  :
790  }
791  /** get an iterable view over all siblings (including the calling node) */
792  C4_ALWAYS_INLINE const_children_view csiblings() const RYML_NOEXCEPT { return siblings(); }
793 
794  /** visit every child node calling fn(node) */
795  template<class Visitor>
796  bool visit(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT
797  {
798  _C4RR();
799  return detail::_visit(*(ConstImpl const*)this, fn, indentation_level, skip_root);
800  }
801  /** visit every child node calling fn(node) */
802  template<class Visitor, class U=Impl>
803  auto visit(Visitor fn, id_type indentation_level=0, bool skip_root=true) RYML_NOEXCEPT
804  -> _C4_IF_MUTABLE(bool)
805  {
806  _C4RR();
807  return detail::_visit(*(Impl*)this, fn, indentation_level, skip_root);
808  }
809 
810  /** visit every child node calling fn(node, level) */
811  template<class Visitor>
812  bool visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT
813  {
814  _C4RR();
815  return detail::_visit_stacked(*(ConstImpl const*)this, fn, indentation_level, skip_root);
816  }
817  /** visit every child node calling fn(node, level) */
818  template<class Visitor, class U=Impl>
819  auto visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) RYML_NOEXCEPT
820  -> _C4_IF_MUTABLE(bool)
821  {
822  _C4RR();
823  return detail::_visit_stacked(*(Impl*)this, fn, indentation_level, skip_root);
824  }
825 
826  /** @} */
827 
828  #if defined(__clang__)
829  # pragma clang diagnostic pop
830  #elif defined(__GNUC__)
831  # pragma GCC diagnostic pop
832  #endif
833 
834  #undef _C4_IF_MUTABLE
835  #undef _C4RR
836  #undef tree_
837  #undef tree__
838  #undef id_
839  #undef id__
840 
841  C4_SUPPRESS_WARNING_GCC_CLANG_POP
842 };
843 } // detail
844 
845 
846 //-----------------------------------------------------------------------------
847 //-----------------------------------------------------------------------------
848 //-----------------------------------------------------------------------------
849 /** Holds a pointer to an existing tree, and a node id. It can be used
850  * only to read from the tree.
851  *
852  * @warning The lifetime of the tree must be larger than that of this
853  * object. It is up to the user to ensure that this happens. */
854 class RYML_EXPORT ConstNodeRef : public detail::RoNodeMethods<ConstNodeRef, ConstNodeRef> // NOLINT
855 {
856 public:
857 
858  using tree_type = Tree const;
859 
860 public:
861 
862  Tree const* C4_RESTRICT m_tree;
864 
865  friend NodeRef;
867 
868 public:
869 
870  /** @name construction */
871  /** @{ */
872 
873  ConstNodeRef() noexcept : m_tree(nullptr), m_id(NONE) {}
874  ConstNodeRef(Tree const &t) noexcept : m_tree(&t), m_id(t .root_id()) {}
875  ConstNodeRef(Tree const *t) noexcept : m_tree(t ), m_id(t->root_id()) {}
876  ConstNodeRef(Tree const *t, id_type id) noexcept : m_tree(t), m_id(id) {}
877  ConstNodeRef(std::nullptr_t) noexcept : m_tree(nullptr), m_id(NONE) {}
878 
879  ConstNodeRef(ConstNodeRef const&) noexcept = default;
880  ConstNodeRef(ConstNodeRef &&) noexcept = default;
881 
882  inline ConstNodeRef(NodeRef const&) noexcept;
883  inline ConstNodeRef(NodeRef &&) noexcept;
884 
885  /** @} */
886 
887 public:
888 
889  /** @name assignment */
890  /** @{ */
891 
892  ConstNodeRef& operator= (std::nullptr_t) noexcept { m_tree = nullptr; m_id = NONE; return *this; }
893 
894  ConstNodeRef& operator= (ConstNodeRef const&) noexcept = default;
895  ConstNodeRef& operator= (ConstNodeRef &&) noexcept = default;
896 
897  ConstNodeRef& operator= (NodeRef const&) noexcept;
898  ConstNodeRef& operator= (NodeRef &&) noexcept;
899 
900  /** @} */
901 
902 public:
903 
904  /** @name state queries
905  *
906  * see @ref NodeRef for an explanation on what these states mean */
907  /** @{ */
908 
909  C4_ALWAYS_INLINE bool invalid() const noexcept { return (!m_tree) || (m_id == NONE); }
910  /** because a ConstNodeRef cannot be used to write to the tree,
911  * readable() has the same meaning as !invalid() */
912  C4_ALWAYS_INLINE bool readable() const noexcept { return m_tree != nullptr && m_id != NONE; }
913  /** because a ConstNodeRef cannot be used to write to the tree, it can never be a seed.
914  * This method is provided for API equivalence between ConstNodeRef and NodeRef. */
915  constexpr static C4_ALWAYS_INLINE bool is_seed() noexcept { return false; }
916 
917  RYML_DEPRECATED("use one of readable(), is_seed() or !invalid()") bool valid() const noexcept { return m_tree != nullptr && m_id != NONE; }
918 
919  /** @} */
920 
921 public:
922 
923  /** @name member getters */
924  /** @{ */
925 
926  C4_ALWAYS_INLINE Tree const* tree() const noexcept { return m_tree; }
927  C4_ALWAYS_INLINE id_type id() const noexcept { return m_id; }
928 
929  /** @} */
930 
931 public:
932 
933  /** @name comparisons */
934  /** @{ */
935 
936  C4_ALWAYS_INLINE bool operator== (ConstNodeRef const& that) const RYML_NOEXCEPT { return that.m_tree == m_tree && m_id == that.m_id; }
937  C4_ALWAYS_INLINE bool operator!= (ConstNodeRef const& that) const RYML_NOEXCEPT { return ! this->operator== (that); }
938 
939  /** @cond dev */
940  RYML_DEPRECATED("use invalid()") bool operator== (std::nullptr_t) const noexcept { return m_tree == nullptr || m_id == NONE; }
941  RYML_DEPRECATED("use !invalid()") bool operator!= (std::nullptr_t) const noexcept { return !(m_tree == nullptr || m_id == NONE); }
942 
943  RYML_DEPRECATED("use (this->val() == s)") bool operator== (csubstr s) const RYML_NOEXCEPT { _RYML_ASSERT_BASIC(m_tree); _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_id != NONE, m_tree, NONE); return m_tree->val(m_id) == s; }
944  RYML_DEPRECATED("use (this->val() != s)") bool operator!= (csubstr s) const RYML_NOEXCEPT { _RYML_ASSERT_BASIC(m_tree); _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_id != NONE, m_tree, NONE); return m_tree->val(m_id) != s; }
945  /** @endcond */
946 
947  /** @} */
948 
949 };
950 
951 
952 //-----------------------------------------------------------------------------
953 //-----------------------------------------------------------------------------
954 //-----------------------------------------------------------------------------
955 
956 // NOLINTBEGIN(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator)
957 
958 /** A reference to a node in an existing yaml tree, offering a more
959  * convenient API than the index-based API used in the tree.
960  *
961  * Unlike its imutable ConstNodeRef peer, a NodeRef can be used to
962  * mutate the tree, both by writing to existing nodes and by creating
963  * new nodes to subsequently write to. Semantically, a NodeRef
964  * object can be in one of three states:
965  *
966  * ```text
967  * invalid := not pointing at anything
968  * readable := points at an existing tree/node
969  * seed := points at an existing tree, and the node
970  * may come to exist, if we write to it.
971  * ```
972  *
973  * So both `readable` and `seed` are states where the node is also `valid`.
974  *
975  * ```cpp
976  * Tree t = parse_in_arena("{a: b}");
977  * NodeRef invalid; // not pointing at anything.
978  * NodeRef readable = t["a"]; // also valid, because "a" exists
979  * NodeRef seed = t["none"]; // also valid, but is seed because "none" is not in the map
980  * ```
981  *
982  * When the object is in seed state, using it to read from the tree is
983  * UB. The seed node can be used to write to the tree, provided that
984  * its create() method is called prior to writing, which happens in
985  * most modifying methods in NodeRef.
986  *
987  * It is the owners's responsibility to verify that an existing
988  * node is readable before subsequently using it to read from the
989  * tree.
990  *
991  * @warning The lifetime of the tree must be larger than that of this
992  * object. It is up to the user to ensure that this happens.
993  */
994 class RYML_EXPORT NodeRef : public detail::RoNodeMethods<NodeRef, ConstNodeRef> // NOLINT
995 {
996 public:
997 
998  using tree_type = Tree;
1000 
1001 private:
1002 
1003  Tree *C4_RESTRICT m_tree;
1004  id_type m_id;
1005 
1006  /** This member is used to enable lazy operator[] writing. When a child
1007  * with a key or index is not found, m_id is set to the id of the parent
1008  * and the asked-for key or index are stored in this member until a write
1009  * does happen. Then it is given as key or index for creating the child.
1010  * When a key is used, the csubstr stores it (so the csubstr's string is
1011  * non-null and the csubstr's size is different from NONE). When an index is
1012  * used instead, the csubstr's string is set to null, and only the csubstr's
1013  * size is set to a value different from NONE. Otherwise, when operator[]
1014  * does find the child then this member is empty: the string is null and
1015  * the size is NONE. */
1016  csubstr m_seed;
1017 
1019  friend struct detail::RoNodeMethods<NodeRef, ConstNodeRef>;
1020 
1021  // require valid: a helper macro, undefined at the end
1022  #define _C4RR() \
1023  _RYML_ASSERT_BASIC(m_tree != nullptr); \
1024  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_id != NONE && !is_seed(), m_tree, m_id)
1025  // require id: a helper macro, undefined at the end
1026  #define _C4RID() \
1027  _RYML_ASSERT_BASIC(m_tree != nullptr); \
1028  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_id != NONE, m_tree, m_id)
1029 
1030 public:
1031 
1032  /** @name construction */
1033  /** @{ */
1034 
1035  NodeRef() noexcept : m_tree(nullptr), m_id(NONE), m_seed() { _clear_seed(); }
1036  NodeRef(Tree &t) noexcept : m_tree(&t), m_id(t .root_id()), m_seed() { _clear_seed(); }
1037  NodeRef(Tree *t) noexcept : m_tree(t ), m_id(t->root_id()), m_seed() { _clear_seed(); }
1038  NodeRef(Tree *t, id_type id) noexcept : m_tree(t), m_id(id), m_seed() { _clear_seed(); }
1039  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; }
1040  NodeRef(Tree *t, id_type id, csubstr seed_key) noexcept : m_tree(t), m_id(id), m_seed(seed_key) {}
1041  NodeRef(std::nullptr_t) noexcept : m_tree(nullptr), m_id(NONE), m_seed() {}
1042 
1043  void _clear_seed() noexcept { /*do the following manually or an assert is triggered: */ m_seed.str = nullptr; m_seed.len = npos; }
1044 
1045  /** @} */
1046 
1047 public:
1048 
1049  /** @name assignment */
1050  /** @{ */
1051 
1052  NodeRef(NodeRef const&) noexcept = default;
1053  NodeRef(NodeRef &&) noexcept = default;
1054 
1055  NodeRef& operator= (NodeRef const&) noexcept = default;
1056  NodeRef& operator= (NodeRef &&) noexcept = default;
1057 
1058  /** @} */
1059 
1060 public:
1061 
1062  /** @name state_queries
1063  * @{ */
1064 
1065  /** true if the object is not referring to any existing or seed node. @see the doc for @ref NodeRef */
1066  bool invalid() const noexcept { return m_tree == nullptr || m_id == NONE; }
1067  /** true if the object is not invalid and in seed state. @see the doc for @ref NodeRef */
1068  bool is_seed() const noexcept { return (m_tree != nullptr && m_id != NONE) && (m_seed.str != nullptr || m_seed.len != (size_t)NONE); }
1069  /** true if the object is not invalid and not in seed state. @see the doc for @ref NodeRef */
1070  bool readable() const noexcept { return (m_tree != nullptr && m_id != NONE) && (m_seed.str == nullptr && m_seed.len == (size_t)NONE); }
1071 
1072  RYML_DEPRECATED("use one of readable(), is_seed() or !invalid()") inline bool valid() const { return m_tree != nullptr && m_id != NONE; }
1073 
1074  /** @} */
1075 
1076 public:
1077 
1078  /** @name comparisons */
1079  /** @{ */
1080 
1081  bool operator== (NodeRef const& that) const
1082  {
1083  if(m_tree == that.m_tree && m_id == that.m_id)
1084  {
1085  bool seed = is_seed();
1086  if(seed == that.is_seed())
1087  {
1088  if(seed)
1089  {
1090  return (m_seed.len == that.m_seed.len)
1091  && (m_seed.str == that.m_seed.str
1092  || m_seed == that.m_seed); // do strcmp only in the last resort
1093  }
1094  return true;
1095  }
1096  }
1097  return false;
1098  }
1099  bool operator!= (NodeRef const& that) const { return ! this->operator==(that); }
1100 
1101  bool operator== (ConstNodeRef const& that) const { return m_tree == that.m_tree && m_id == that.m_id && !is_seed(); }
1102  bool operator!= (ConstNodeRef const& that) const { return ! this->operator==(that); }
1103 
1104  /** @cond dev */
1105  RYML_DEPRECATED("use !readable()") bool operator== (std::nullptr_t) const { return m_tree == nullptr || m_id == NONE || is_seed(); }
1106  RYML_DEPRECATED("use readable()") bool operator!= (std::nullptr_t) const { return !(m_tree == nullptr || m_id == NONE || is_seed()); }
1107 
1108  RYML_DEPRECATED("use `this->val() == s`") bool operator== (csubstr s) const { _C4RR(); _RYML_ASSERT_VISIT_(m_tree->m_callbacks, has_val(), m_tree, m_id); return m_tree->val(m_id) == s; }
1109  RYML_DEPRECATED("use `this->val() != s`") bool operator!= (csubstr s) const { _C4RR(); _RYML_ASSERT_VISIT_(m_tree->m_callbacks, has_val(), m_tree, m_id); return m_tree->val(m_id) != s; }
1110  /** @endcond */
1111 
1112 public:
1113 
1114  /** @name node_property_getters
1115  * @{ */
1116 
1117  C4_ALWAYS_INLINE Tree * tree() noexcept { return m_tree; }
1118  C4_ALWAYS_INLINE Tree const* tree() const noexcept { return m_tree; }
1119 
1120  C4_ALWAYS_INLINE id_type id() const noexcept { return m_id; }
1121 
1122  /** @} */
1123 
1124 public:
1125 
1126  /** @name node_modifiers */
1127  /** @{ */
1128 
1129  void create() { _apply_seed(); }
1130 
1131  void change_type(NodeType t) { _C4RR(); m_tree->change_type(m_id, t); }
1132 
1133  void set_type(NodeType t) { _apply_seed(); m_tree->_set_flags(m_id, t); }
1134  void set_key(csubstr key) { _apply_seed(); m_tree->_set_key(m_id, key); }
1135  void set_val(csubstr val) { _apply_seed(); m_tree->_set_val(m_id, val); }
1136  void set_key_tag(csubstr key_tag) { _apply_seed(); m_tree->set_key_tag(m_id, key_tag); }
1137  void set_val_tag(csubstr val_tag) { _apply_seed(); m_tree->set_val_tag(m_id, val_tag); }
1138  void set_key_anchor(csubstr key_anchor) { _apply_seed(); m_tree->set_key_anchor(m_id, key_anchor); }
1139  void set_val_anchor(csubstr val_anchor) { _apply_seed(); m_tree->set_val_anchor(m_id, val_anchor); }
1140  void set_key_ref(csubstr key_ref) { _apply_seed(); m_tree->set_key_ref(m_id, key_ref); }
1141  void set_val_ref(csubstr val_ref) { _apply_seed(); m_tree->set_val_ref(m_id, val_ref); }
1142 
1143  void set_container_style(NodeType_e style) { _C4RR(); m_tree->set_container_style(m_id, style); }
1144  void set_key_style(NodeType_e style) { _C4RR(); m_tree->set_key_style(m_id, style); }
1145  void set_val_style(NodeType_e style) { _C4RR(); m_tree->set_val_style(m_id, style); }
1146  void clear_style(bool recurse=false) { _C4RR(); m_tree->clear_style(m_id, recurse); }
1148  NodeType rem_style_flags,
1149  NodeType add_style_flags,
1150  bool recurse=false)
1151  {
1152  _C4RR(); m_tree->set_style_conditionally(m_id, type_mask, rem_style_flags, add_style_flags, recurse);
1153  }
1154 
1155 public:
1156 
1157  void clear()
1158  {
1159  if(is_seed())
1160  return;
1161  m_tree->remove_children(m_id);
1162  m_tree->_clear(m_id);
1163  }
1164 
1165  void clear_key()
1166  {
1167  if(is_seed())
1168  return;
1169  m_tree->_clear_key(m_id);
1170  }
1171 
1172  void clear_val()
1173  {
1174  if(is_seed())
1175  return;
1176  m_tree->_clear_val(m_id);
1177  }
1178 
1180  {
1181  if(is_seed())
1182  return;
1183  m_tree->remove_children(m_id);
1184  }
1185 
1186  void operator= (NodeType_e t)
1187  {
1188  _apply_seed();
1189  m_tree->_add_flags(m_id, t);
1190  }
1191 
1193  {
1194  _apply_seed();
1195  m_tree->_add_flags(m_id, t);
1196  }
1197 
1198  void operator= (NodeInit const& v)
1199  {
1200  _apply_seed();
1201  _apply(v);
1202  }
1203 
1204  void operator= (NodeScalar const& v)
1205  {
1206  _apply_seed();
1207  _apply(v);
1208  }
1209 
1210  void operator= (std::nullptr_t)
1211  {
1212  _apply_seed();
1213  _apply(csubstr{});
1214  }
1215 
1216  void operator= (csubstr v)
1217  {
1218  _apply_seed();
1219  _apply(v);
1220  }
1221 
1222  template<size_t N>
1223  void operator= (const char (&v)[N])
1224  {
1225  _apply_seed();
1226  csubstr sv;
1227  sv.assign<N>(v);
1228  _apply(sv);
1229  }
1230 
1231  /** @} */
1232 
1233 public:
1234 
1235  /** @name serialization */
1236  /** @{ */
1237 
1238  /** serialize a variable to the arena */
1239  template<class T>
1240  csubstr to_arena(T const& C4_RESTRICT s)
1241  {
1242  _RYML_ASSERT_BASIC(m_tree); // no need for valid or readable
1243  return m_tree->to_arena(s);
1244  }
1245 
1246  template<class T>
1247  size_t set_key_serialized(T const& C4_RESTRICT k)
1248  {
1249  _apply_seed();
1250  csubstr s = m_tree->to_arena(k);
1251  m_tree->_set_key(m_id, s);
1252  return s.len;
1253  }
1254  size_t set_key_serialized(std::nullptr_t)
1255  {
1256  _apply_seed();
1257  m_tree->_set_key(m_id, csubstr{});
1258  return 0;
1259  }
1260 
1261  template<class T>
1262  size_t set_val_serialized(T const& C4_RESTRICT v)
1263  {
1264  _apply_seed();
1265  csubstr s = m_tree->to_arena(v);
1266  m_tree->_set_val(m_id, s);
1267  return s.len;
1268  }
1269  size_t set_val_serialized(std::nullptr_t)
1270  {
1271  _apply_seed();
1272  m_tree->_set_val(m_id, csubstr{});
1273  return 0;
1274  }
1275 
1276  /** encode a blob as base64 into the tree's arena, then assign the
1277  * result to the node's key
1278  * @return the size of base64-encoded blob */
1279  size_t set_key_serialized(fmt::const_base64_wrapper w);
1280  /** encode a blob as base64 into the tree's arena, then assign the
1281  * result to the node's val
1282  * @return the size of base64-encoded blob */
1283  size_t set_val_serialized(fmt::const_base64_wrapper w);
1284 
1285  /** serialize a variable, then assign the result to the node's val */
1286  NodeRef& operator<< (csubstr s)
1287  {
1288  // this overload is needed to prevent ambiguity (there's also
1289  // operator<< for writing a substr to a stream)
1290  _apply_seed();
1291  write(this, s);
1292  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, val() == s, m_tree, m_id);
1293  return *this;
1294  }
1295 
1296  template<class T>
1297  NodeRef& operator<< (T const& C4_RESTRICT v)
1298  {
1299  _apply_seed();
1300  write(this, v);
1301  return *this;
1302  }
1303 
1304  /** serialize a variable, then assign the result to the node's key */
1305  template<class T>
1306  NodeRef& operator<< (Key<const T> const& C4_RESTRICT v)
1307  {
1308  _apply_seed();
1309  set_key_serialized(v.k);
1310  return *this;
1311  }
1312 
1313  /** serialize a variable, then assign the result to the node's key */
1314  template<class T>
1315  NodeRef& operator<< (Key<T> const& C4_RESTRICT v)
1316  {
1317  _apply_seed();
1318  set_key_serialized(v.k);
1319  return *this;
1320  }
1321 
1323  {
1324  set_key_serialized(w.wrapper);
1325  return *this;
1326  }
1327 
1329  {
1330  set_val_serialized(w);
1331  return *this;
1332  }
1333 
1334  /** @} */
1335 
1336 private:
1337 
1338  void _apply_seed()
1339  {
1340  _C4RID();
1341  if(m_seed.str) // we have a seed key: use it to create the new child
1342  {
1343  m_id = m_tree->append_child(m_id);
1344  m_tree->_set_key(m_id, m_seed);
1345  m_seed.str = nullptr;
1346  m_seed.len = (size_t)NONE;
1347  }
1348  else if(m_seed.len != (size_t)NONE) // we have a seed index: create a child at that position
1349  {
1350  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, (size_t)m_tree->num_children(m_id) == m_seed.len, m_tree, m_id);
1351  m_id = m_tree->append_child(m_id);
1352  m_seed.str = nullptr;
1353  m_seed.len = (size_t)NONE;
1354  }
1355  else
1356  {
1357  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, readable(), m_tree, m_id);
1358  }
1359  }
1360 
1361  void _apply(csubstr v)
1362  {
1363  m_tree->_set_val(m_id, v);
1364  }
1365 
1366  void _apply(NodeScalar const& v)
1367  {
1368  m_tree->_set_val(m_id, v);
1369  }
1370 
1371  void _apply(NodeInit const& i)
1372  {
1373  m_tree->_set(m_id, i);
1374  }
1375 
1376 public:
1377 
1378  /** @name modification of hierarchy */
1379  /** @{ */
1380 
1382  {
1383  _C4RR();
1384  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1385  NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
1386  return r;
1387  }
1388 
1390  {
1391  _C4RR();
1392  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1393  NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
1394  r._apply(i);
1395  return r;
1396  }
1397 
1399  {
1400  _C4RR();
1401  NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
1402  return r;
1403  }
1404 
1406  {
1407  _C4RR();
1408  NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
1409  r._apply(i);
1410  return r;
1411  }
1412 
1414  {
1415  _C4RR();
1416  NodeRef r(m_tree, m_tree->append_child(m_id));
1417  return r;
1418  }
1419 
1421  {
1422  _C4RR();
1423  NodeRef r(m_tree, m_tree->append_child(m_id));
1424  r._apply(i);
1425  return r;
1426  }
1427 
1429  {
1430  _C4RR();
1431  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1432  NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
1433  return r;
1434  }
1435 
1437  {
1438  _C4RR();
1439  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, after.m_tree == m_tree, m_tree, m_id);
1440  NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
1441  r._apply(i);
1442  return r;
1443  }
1444 
1446  {
1447  _C4RR();
1448  NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
1449  return r;
1450  }
1451 
1453  {
1454  _C4RR();
1455  NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
1456  r._apply(i);
1457  return r;
1458  }
1459 
1461  {
1462  _C4RR();
1463  NodeRef r(m_tree, m_tree->append_sibling(m_id));
1464  return r;
1465  }
1466 
1468  {
1469  _C4RR();
1470  NodeRef r(m_tree, m_tree->append_sibling(m_id));
1471  r._apply(i);
1472  return r;
1473  }
1474 
1475 public:
1476 
1477  void remove_child(NodeRef & child)
1478  {
1479  _C4RR();
1480  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, has_child(child), m_tree, m_id);
1481  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, child.parent().id() == id(), m_tree, m_id);
1482  m_tree->remove(child.id());
1483  child.clear();
1484  }
1485 
1486  //! remove the nth child of this node
1488  {
1489  _C4RR();
1490  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, pos >= 0 && pos < num_children(), m_tree, m_id);
1491  id_type child = m_tree->child(m_id, pos);
1492  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, child != NONE, m_tree, m_id);
1493  m_tree->remove(child);
1494  }
1495 
1496  //! remove a child by name
1497  void remove_child(csubstr key)
1498  {
1499  _C4RR();
1500  id_type child = m_tree->find_child(m_id, key);
1501  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, child != NONE, m_tree, m_id);
1502  m_tree->remove(child);
1503  }
1504 
1505 public:
1506 
1507  /** change the node's position within its parent, placing it after
1508  * @p after. To move to the first position in the parent, simply
1509  * pass an empty or default-constructed reference like this:
1510  * `n.move({})`. */
1511  void move(ConstNodeRef const& after)
1512  {
1513  _C4RR();
1514  m_tree->move(m_id, after.m_id);
1515  }
1516 
1517  /** move the node to a different @p parent (which may belong to a
1518  * different tree), placing it after @p after. When the
1519  * destination parent is in a new tree, then this node's tree
1520  * pointer is reset to the tree of the parent node. */
1521  void move(NodeRef const& parent, ConstNodeRef const& after)
1522  {
1523  _C4RR();
1524  if(parent.m_tree == m_tree)
1525  {
1526  m_tree->move(m_id, parent.m_id, after.m_id);
1527  }
1528  else
1529  {
1530  parent.m_tree->move(m_tree, m_id, parent.m_id, after.m_id);
1531  m_tree = parent.m_tree;
1532  }
1533  }
1534 
1535  /** duplicate the current node somewhere within its parent, and
1536  * place it after the node @p after. To place into the first
1537  * position of the parent, simply pass an empty or
1538  * default-constructed reference like this: `n.move({})`. */
1539  NodeRef duplicate(ConstNodeRef const& after) const
1540  {
1541  _C4RR();
1542  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, m_tree == after.m_tree || after.m_id == NONE, m_tree, m_id);
1543  id_type dup = m_tree->duplicate(m_id, m_tree->parent(m_id), after.m_id);
1544  NodeRef r(m_tree, dup);
1545  return r;
1546  }
1547 
1548  /** duplicate the current node somewhere into a different @p parent
1549  * (possibly from a different tree), and place it after the node
1550  * @p after. To place into the first position of the parent,
1551  * simply pass an empty or default-constructed reference like
1552  * this: `n.move({})`. */
1553  NodeRef duplicate(NodeRef const& parent, ConstNodeRef const& after) const
1554  {
1555  _C4RR();
1556  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, parent.m_tree == after.m_tree || after.m_id == NONE, m_tree, m_id);
1557  if(parent.m_tree == m_tree)
1558  {
1559  id_type dup = m_tree->duplicate(m_id, parent.m_id, after.m_id);
1560  NodeRef r(m_tree, dup);
1561  return r;
1562  }
1563  else
1564  {
1565  id_type dup = parent.m_tree->duplicate(m_tree, m_id, parent.m_id, after.m_id);
1566  NodeRef r(parent.m_tree, dup);
1567  return r;
1568  }
1569  }
1570 
1571  void duplicate_children(NodeRef const& parent, ConstNodeRef const& after) const
1572  {
1573  _C4RR();
1574  _RYML_ASSERT_VISIT_(m_tree->m_callbacks, parent.m_tree == after.m_tree, m_tree, m_id);
1575  if(parent.m_tree == m_tree)
1576  {
1577  m_tree->duplicate_children(m_id, parent.m_id, after.m_id);
1578  }
1579  else
1580  {
1581  parent.m_tree->duplicate_children(m_tree, m_id, parent.m_id, after.m_id);
1582  }
1583  }
1584 
1585  /** @} */
1586 
1587 #undef _C4RR
1588 #undef _C4RID
1589 };
1590 
1591 // NOLINTEND(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator)
1592 
1593 
1594 //-----------------------------------------------------------------------------
1595 
1596 inline ConstNodeRef::ConstNodeRef(NodeRef const& that) noexcept
1597  : m_tree(that.m_tree)
1598  , m_id(!that.is_seed() ? that.id() : (id_type)NONE)
1599 {
1600 }
1601 
1602 inline ConstNodeRef::ConstNodeRef(NodeRef && that) noexcept // NOLINT
1603  : m_tree(that.m_tree)
1604  , m_id(!that.is_seed() ? that.id() : (id_type)NONE)
1605 {
1606 }
1607 
1608 
1609 inline ConstNodeRef& ConstNodeRef::operator= (NodeRef const& that) noexcept
1610 {
1611  m_tree = (that.m_tree);
1612  m_id = (!that.is_seed() ? that.id() : (id_type)NONE);
1613  return *this;
1614 }
1615 
1616 inline ConstNodeRef& ConstNodeRef::operator= (NodeRef && that) noexcept // NOLINT
1617 {
1618  m_tree = (that.m_tree);
1619  m_id = (!that.is_seed() ? that.id() : (id_type)NONE);
1620  return *this;
1621 }
1622 
1623 
1624 //-----------------------------------------------------------------------------
1625 
1626 /** @addtogroup doc_serialization_helpers
1627  *
1628  * @{
1629  */
1630 
1631 template<class T>
1632 C4_ALWAYS_INLINE void write(NodeRef *n, T const& v)
1633 {
1634  n->set_val_serialized(v);
1635 }
1636 
1637 template<class T>
1638 C4_ALWAYS_INLINE bool read(ConstNodeRef const& C4_RESTRICT n, T *v)
1639 {
1640  return read(n.m_tree, n.m_id, v);
1641 }
1642 
1643 template<class T>
1644 C4_ALWAYS_INLINE bool read(NodeRef const& C4_RESTRICT n, T *v)
1645 {
1646  return read(n.tree(), n.id(), v);
1647 }
1648 
1649 template<class T>
1650 C4_ALWAYS_INLINE bool readkey(ConstNodeRef const& C4_RESTRICT n, T *v)
1651 {
1652  return readkey(n.m_tree, n.m_id, v);
1653 }
1654 
1655 template<class T>
1656 C4_ALWAYS_INLINE bool readkey(NodeRef const& C4_RESTRICT n, T *v)
1657 {
1658  return readkey(n.tree(), n.id(), v);
1659 }
1660 
1661 /** @} */
1662 
1663 /** @} */
1664 
1665 
1666 } // namespace yml
1667 } // namespace c4
1668 
1669 // NOLINTEND(modernize-avoid-c-style-cast)
1670 
1671 #ifdef __clang__
1672 # pragma clang diagnostic pop
1673 #elif defined(__GNUC__)
1674 # pragma GCC diagnostic pop
1675 #elif defined(_MSC_VER)
1676 # pragma warning(pop)
1677 #endif
1678 
1679 #endif /* _C4_YML_NODE_HPP_ */
encoding/decoding for base64.
Holds a pointer to an existing tree, and a node id.
Definition: node.hpp:855
Tree const * tree() const noexcept
Definition: node.hpp:926
ConstNodeRef() noexcept
Definition: node.hpp:873
ConstNodeRef(ConstNodeRef const &) noexcept=default
id_type id() const noexcept
Definition: node.hpp:927
ConstNodeRef(ConstNodeRef &&) noexcept=default
ConstNodeRef(Tree const *t) noexcept
Definition: node.hpp:875
ConstNodeRef(std::nullptr_t) noexcept
Definition: node.hpp:877
ConstNodeRef(Tree const *t, id_type id) noexcept
Definition: node.hpp:876
constexpr static bool is_seed() noexcept
because a ConstNodeRef cannot be used to write to the tree, it can never be a seed.
Definition: node.hpp:915
ConstNodeRef(Tree const &t) noexcept
Definition: node.hpp:874
Tree const tree_type
Definition: node.hpp:858
Tree const * m_tree
Definition: node.hpp:862
ConstNodeRef & operator=(std::nullptr_t) noexcept
Definition: node.hpp:892
bool readable() const noexcept
because a ConstNodeRef cannot be used to write to the tree, readable() has the same meaning as !...
Definition: node.hpp:912
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition: node.hpp:995
void set_val_anchor(csubstr val_anchor)
Definition: node.hpp:1139
void move(ConstNodeRef const &after)
change the node's position within its parent, placing it after after.
Definition: node.hpp:1511
void set_key_style(NodeType_e style)
Definition: node.hpp:1144
void set_style_conditionally(NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
Definition: node.hpp:1147
NodeRef prepend_child(NodeInit const &i)
Definition: node.hpp:1405
NodeRef insert_sibling(ConstNodeRef const &after)
Definition: node.hpp:1428
NodeRef(Tree *t, id_type id, csubstr seed_key) noexcept
Definition: node.hpp:1040
void set_val_tag(csubstr val_tag)
Definition: node.hpp:1137
void clear_style(bool recurse=false)
Definition: node.hpp:1146
NodeRef append_sibling(NodeInit const &i)
Definition: node.hpp:1467
NodeRef insert_sibling(NodeInit const &i, ConstNodeRef const &after)
Definition: node.hpp:1436
NodeRef(NodeRef &&) noexcept=default
NodeRef(Tree *t, id_type id, id_type seed_pos) noexcept
Definition: node.hpp:1039
NodeRef prepend_sibling(NodeInit const &i)
Definition: node.hpp:1452
csubstr to_arena(T const &s)
serialize a variable to the arena
Definition: node.hpp:1240
void _clear_seed() noexcept
Definition: node.hpp:1043
NodeRef insert_child(NodeRef after)
Definition: node.hpp:1381
void set_val(csubstr val)
Definition: node.hpp:1135
NodeRef prepend_sibling()
Definition: node.hpp:1445
void clear()
Definition: node.hpp:1157
size_t set_key_serialized(T const &k)
Definition: node.hpp:1247
void clear_children()
Definition: node.hpp:1179
void set_val_style(NodeType_e style)
Definition: node.hpp:1145
NodeRef(Tree *t, id_type id) noexcept
Definition: node.hpp:1038
NodeRef insert_child(NodeInit const &i, NodeRef after)
Definition: node.hpp:1389
Tree const * tree() const noexcept
Definition: node.hpp:1118
NodeRef() noexcept
Definition: node.hpp:1035
void clear_val()
Definition: node.hpp:1172
NodeRef append_sibling()
Definition: node.hpp:1460
size_t set_val_serialized(std::nullptr_t)
Definition: node.hpp:1269
id_type id() const noexcept
Definition: node.hpp:1120
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:1521
void set_container_style(NodeType_e style)
Definition: node.hpp:1143
NodeRef duplicate(ConstNodeRef const &after) const
duplicate the current node somewhere within its parent, and place it after the node after.
Definition: node.hpp:1539
bool readable() const noexcept
true if the object is not invalid and not in seed state.
Definition: node.hpp:1070
void duplicate_children(NodeRef const &parent, ConstNodeRef const &after) const
Definition: node.hpp:1571
NodeRef(Tree *t) noexcept
Definition: node.hpp:1037
NodeRef append_child()
Definition: node.hpp:1413
void clear_key()
Definition: node.hpp:1165
size_t set_val_serialized(T const &v)
Definition: node.hpp:1262
void create()
Definition: node.hpp:1129
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:1553
void set_type(NodeType t)
Definition: node.hpp:1133
void remove_child(csubstr key)
remove a child by name
Definition: node.hpp:1497
NodeRef prepend_child()
Definition: node.hpp:1398
NodeRef(NodeRef const &) noexcept=default
void set_key_tag(csubstr key_tag)
Definition: node.hpp:1136
size_t set_key_serialized(std::nullptr_t)
Definition: node.hpp:1254
NodeRef append_child(NodeInit const &i)
Definition: node.hpp:1420
NodeRef(std::nullptr_t) noexcept
Definition: node.hpp:1041
void set_key_ref(csubstr key_ref)
Definition: node.hpp:1140
void remove_child(NodeRef &child)
Definition: node.hpp:1477
void set_key_anchor(csubstr key_anchor)
Definition: node.hpp:1138
void change_type(NodeType t)
Definition: node.hpp:1131
NodeRef(Tree &t) noexcept
Definition: node.hpp:1036
bool is_seed() const noexcept
true if the object is not invalid and in seed state.
Definition: node.hpp:1068
void set_key(csubstr key)
Definition: node.hpp:1134
void set_val_ref(csubstr val_ref)
Definition: node.hpp:1141
Tree * tree() noexcept
Definition: node.hpp:1117
void remove_child(id_type pos)
remove the nth child of this node
Definition: node.hpp:1487
This is the main driver of parsing logic: it scans the YAML or JSON source for tokens,...
void move(id_type node, id_type after)
change the node's position in the parent
Definition: tree.cpp:819
id_type duplicate(id_type node, id_type new_parent, id_type after)
recursively duplicate a node from this tree into a new parent, placing it after one of its children
Definition: tree.cpp:959
id_type duplicate_children(id_type node, id_type parent, id_type after)
recursively duplicate the node's children (but not the node)
Definition: tree.cpp:981
#define RYML_NOEXCEPT
Conditionally expands to noexcept when RYML_USE_ASSERT is 0 and is empty otherwise.
Definition: common.hpp:192
#define RYML_EXPORT
Definition: export.hpp:15
base64_wrapper_< byte > base64_wrapper
a tag type to mark a payload to be encoded as base64
Definition: base64.hpp:80
base64_wrapper_< cbyte > const_base64_wrapper
a tag type to mark a payload as base64-encoded
Definition: base64.hpp:78
OStream & operator<<(OStream &s, Tree const &t)
emit YAML to an STL-like ostream
Definition: emit.hpp:521
bool from_chars(csubstr buf, uint8_t *v) noexcept
Definition: charconv.hpp:2366
NodeType_e & operator|=(NodeType_e &subject, NodeType_e bits) noexcept
Definition: node_type.hpp:112
NodeType_e
a bit mask for marking node types and styles
Definition: node_type.hpp:34
bool readkey(ConstNodeRef const &n, T *v)
Definition: node.hpp:1650
void write(NodeRef *n, T const &v)
Definition: node.hpp:1632
Key< K > key(K &k)
Definition: node.hpp:45
bool read(ConstNodeRef const &n, T *v)
Definition: node.hpp:1638
bool operator!=(const char(&s)[N], basic_substring< C > const that) noexcept
Definition: substr.hpp:2289
bool operator==(const char(&s)[N], basic_substring< C > const that) noexcept
Definition: substr.hpp:2288
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:244
@ npos
a null string position
Definition: common.hpp:258
@ NONE
an index to none
Definition: common.hpp:251
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
#define _C4RR()
Definition: node.hpp:1022
#define _C4RID()
Definition: node.hpp:1026
fmt::base64_wrapper wrapper
Definition: node.hpp:43
fmt::const_base64_wrapper wrapper
Definition: node.hpp:42
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition: common.hpp:283
contains the data for each YAML node.
Definition: tree.hpp:228
id_type m_parent
Definition: tree.hpp:234
convenience class to initialize nodes
Definition: tree.hpp:162
a node scalar is a csubstr, which may be tagged and anchored.
Definition: tree.hpp:111
wraps a NodeType_e element with some syntactic sugar and predicates
Definition: node_type.hpp:121
auto at(csubstr key) -> Impl
Find child by key; complexity is O(num_children).
Definition: node.hpp:529
bool type_has_none(NodeType_e bits) const RYML_NOEXCEPT
Forward to Tree::type_has_none().
Definition: node.hpp:273
const_children_view cchildren() const RYML_NOEXCEPT
get an iterable view over children
Definition: node.hpp:768
bool is_key_anchor() const noexcept
Definition: node.hpp:257
auto first_child() RYML_NOEXCEPT -> Impl
Forward to Tree::first_child().
Definition: node.hpp:343
id_type depth_asc() const RYML_NOEXCEPT
Definition: node.hpp:392
bool get_if(csubstr name, T *var) const
look for a child by name, if it exists assign to var.
Definition: node.hpp:665
id_type depth_desc() const RYML_NOEXCEPT
O(log(num_nodes)).
Definition: node.hpp:393
bool has_anchor() const RYML_NOEXCEPT
Forward to Tree::has_anchor().
Definition: node.hpp:250
auto children() RYML_NOEXCEPT -> children_view
get an iterable view over children.
Definition: node.hpp:766
bool is_flow_ml() const RYML_NOEXCEPT
Forward to Tree::is_flow_ml().
Definition: node.hpp:281
bool is_val() const RYML_NOEXCEPT
Forward to Tree::is_val().
Definition: node.hpp:244
bool is_key_styled() const RYML_NOEXCEPT
Forward to Tree::is_key_styled().
Definition: node.hpp:284
bool is_root() const RYML_NOEXCEPT
Forward to Tree::is_root().
Definition: node.hpp:309
csubstr key_anchor() const RYML_NOEXCEPT
Forward to Tree::key_anchor().
Definition: node.hpp:213
bool has_val_anchor() const RYML_NOEXCEPT
Forward to Tree::has_val_anchor().
Definition: node.hpp:249
bool has_siblings() const RYML_NOEXCEPT
Definition: node.hpp:323
auto last_child() RYML_NOEXCEPT -> Impl
Forward to Tree::last_child().
Definition: node.hpp:347
auto visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) RYML_NOEXCEPT -> bool
visit every child node calling fn(node, level)
Definition: node.hpp:819
bool is_key_plain() const RYML_NOEXCEPT
Forward to Tree::is_key_plain().
Definition: node.hpp:294
bool is_key_quoted() const RYML_NOEXCEPT
Forward to Tree::is_key_quoted().
Definition: node.hpp:296
bool is_stream() const RYML_NOEXCEPT
Forward to Tree::is_stream().
Definition: node.hpp:237
NodeType type() const RYML_NOEXCEPT
Forward to Tree::type().
Definition: node.hpp:207
bool empty() const RYML_NOEXCEPT
Forward to Tree::empty().
Definition: node.hpp:236
NodeScalar const & valsc() const RYML_NOEXCEPT
Forward to Tree::valsc().
Definition: node.hpp:221
auto parent() RYML_NOEXCEPT -> Impl
Forward to Tree::parent().
Definition: node.hpp:339
bool has_key_anchor() const RYML_NOEXCEPT
Forward to Tree::has_key_anchor().
Definition: node.hpp:248
bool is_key_unfiltered() const noexcept
Forward to Tree::is_key_unfiltered().
Definition: node.hpp:226
id_type sibling_pos(ConstImpl const &n) const RYML_NOEXCEPT
O(num_siblings).
Definition: node.hpp:390
const_children_view siblings() const RYML_NOEXCEPT
get an iterable view over all siblings (including the calling node)
Definition: node.hpp:782
bool is_key_literal() const RYML_NOEXCEPT
Forward to Tree::is_key_literal().
Definition: node.hpp:286
const_iterator cbegin() const RYML_NOEXCEPT
get an iterator to the first child
Definition: node.hpp:756
csubstr key_ref() const RYML_NOEXCEPT
Forward to Tree::key_ref().
Definition: node.hpp:212
ConstImpl sibling(id_type pos) const RYML_NOEXCEPT
Forward to Tree::sibling().
Definition: node.hpp:376
bool visit_stacked(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT
visit every child node calling fn(node, level)
Definition: node.hpp:812
bool has_child(ConstImpl const &n) const RYML_NOEXCEPT
Forward to Tree::has_child().
Definition: node.hpp:313
ConstImpl const & operator>>(T &v) const
deserialize the node's val to the given variable, forwarding to the user-overrideable read() function...
Definition: node.hpp:642
auto next_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::next_sibling().
Definition: node.hpp:363
bool visit(Visitor fn, id_type indentation_level=0, bool skip_root=true) const RYML_NOEXCEPT
visit every child node calling fn(node)
Definition: node.hpp:796
bool is_quoted() const RYML_NOEXCEPT
Forward to Tree::is_quoted().
Definition: node.hpp:298
bool parent_is_map() const RYML_NOEXCEPT
Forward to Tree::parent_is_map().
Definition: node.hpp:255
auto last_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::last_sibling().
Definition: node.hpp:371
bool has_child(csubstr name) const RYML_NOEXCEPT
Forward to Tree::has_child().
Definition: node.hpp:315
auto find_sibling(csubstr name) RYML_NOEXCEPT -> Impl
Forward to Tree::find_sibling().
Definition: node.hpp:379
bool get_if(csubstr name, T *var, T const &fallback) const
look for a child by name, if it exists assign to var, otherwise default to fallback.
Definition: node.hpp:679
bool is_map() const RYML_NOEXCEPT
Forward to Tree::is_map().
Definition: node.hpp:240
bool type_has_any(NodeType_e bits) const RYML_NOEXCEPT
Forward to Tree::type_has_any().
Definition: node.hpp:271
ConstImpl last_sibling() const RYML_NOEXCEPT
Forward to Tree::last_sibling().
Definition: node.hpp:372
bool is_container() const RYML_NOEXCEPT
Forward to Tree::is_container().
Definition: node.hpp:239
id_type num_siblings() const RYML_NOEXCEPT
O(num_children).
Definition: node.hpp:387
ConstImpl last_child() const RYML_NOEXCEPT
Forward to Tree::last_child().
Definition: node.hpp:348
bool has_key() const RYML_NOEXCEPT
Forward to Tree::has_key().
Definition: node.hpp:243
csubstr key_tag() const RYML_NOEXCEPT
Forward to Tree::key_tag().
Definition: node.hpp:211
const_children_view csiblings() const RYML_NOEXCEPT
get an iterable view over all siblings (including the calling node)
Definition: node.hpp:792
auto find_child(csubstr name) RYML_NOEXCEPT -> Impl
Forward to Tree::find_child().
Definition: node.hpp:355
detail::child_iterator< Impl > iterator
Definition: node.hpp:748
csubstr val_ref() const RYML_NOEXCEPT
Forward to Tree::val_ref().
Definition: node.hpp:217
csubstr key() const RYML_NOEXCEPT
Forward to Tree::key().
Definition: node.hpp:210
ConstImpl child(id_type pos) const RYML_NOEXCEPT
Forward to Tree::child().
Definition: node.hpp:352
bool has_sibling(csubstr name) const RYML_NOEXCEPT
Forward to Tree::has_sibling().
Definition: node.hpp:320
NodeType key_style() const RYML_NOEXCEPT
Forward to Tree::key_style().
Definition: node.hpp:275
NodeScalar const & keysc() const RYML_NOEXCEPT
Forward to Tree::keysc().
Definition: node.hpp:220
size_t deserialize_val(fmt::base64_wrapper v) const
decode the base64-encoded key and assign the decoded blob to the given buffer/
Definition: node.hpp:723
bool has_key_tag() const RYML_NOEXCEPT
Forward to Tree::has_key_tag().
Definition: node.hpp:246
bool is_anchor() const noexcept
Definition: node.hpp:259
csubstr val_tag() const RYML_NOEXCEPT
Forward to Tree::val_tag().
Definition: node.hpp:216
bool is_ancestor(ConstImpl const &ancestor) const RYML_NOEXCEPT
Forward to Tree::is_ancestor() Node must be readable.
Definition: node.hpp:311
ConstImpl next_sibling() const RYML_NOEXCEPT
Forward to Tree::next_sibling().
Definition: node.hpp:364
ConstImpl find_sibling(csubstr name) const RYML_NOEXCEPT
Forward to Tree::find_sibling().
Definition: node.hpp:380
bool is_anchor_or_ref() const noexcept
Definition: node.hpp:260
const char * type_str() const RYML_NOEXCEPT
Forward to Tree::type_str().
Definition: node.hpp:208
csubstr val_anchor() const RYML_NOEXCEPT
Forward to Tree::val_anchor().
Definition: node.hpp:218
const_children_view children() const RYML_NOEXCEPT
get an iterable view over children
Definition: node.hpp:767
auto end() RYML_NOEXCEPT -> iterator
get an iterator to after the last child.
Definition: node.hpp:759
auto siblings() RYML_NOEXCEPT -> children_view
get an iterable view over all siblings (including the calling node)
Definition: node.hpp:772
bool has_parent() const RYML_NOEXCEPT
Forward to Tree::has_parent() Node must be readable.
Definition: node.hpp:310
bool is_val_squo() const RYML_NOEXCEPT
Forward to Tree::is_val_squo().
Definition: node.hpp:291
ConstImpl find_child(csubstr name) const RYML_NOEXCEPT
Forward to Tree::find_child().
Definition: node.hpp:356
NodeData const * get() const RYML_NOEXCEPT
returns the data or null when the id is NONE
Definition: node.hpp:201
ConstImpl at(csubstr key) const
Get a child by name, with error checking; complexity is O(num_children).
Definition: node.hpp:586
bool is_val_ref() const RYML_NOEXCEPT
Forward to Tree::is_val_ref().
Definition: node.hpp:252
bool has_other_siblings() const RYML_NOEXCEPT
Forward to Tree::has_other_siblings().
Definition: node.hpp:321
ConstImpl ancestor_doc() const RYML_NOEXCEPT
Forward to Tree::ancestor_doc().
Definition: node.hpp:384
bool is_val_styled() const RYML_NOEXCEPT
Forward to Tree::is_val_styled().
Definition: node.hpp:285
bool val_is_null() const RYML_NOEXCEPT
Forward to Tree::val_is_null().
Definition: node.hpp:224
auto begin() RYML_NOEXCEPT -> iterator
get a mutable iterator to the first child.
Definition: node.hpp:754
bool has_sibling(id_type node) const RYML_NOEXCEPT
Forward to Tree::has_sibling().
Definition: node.hpp:319
id_type child_pos(ConstImpl const &n) const RYML_NOEXCEPT
O(num_children).
Definition: node.hpp:389
bool is_container_styled() const RYML_NOEXCEPT
Forward to Tree::is_container_styled().
Definition: node.hpp:278
detail::children_view_< ConstImpl > const_children_view
Definition: node.hpp:751
auto first_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::first_sibling().
Definition: node.hpp:367
csubstr val() const RYML_NOEXCEPT
Forward to Tree::val().
Definition: node.hpp:215
bool type_has_all(NodeType_e bits) const RYML_NOEXCEPT
Forward to Tree::type_has_all().
Definition: node.hpp:272
bool is_key_ref() const RYML_NOEXCEPT
Forward to Tree::is_key_ref().
Definition: node.hpp:251
const_iterator end() const RYML_NOEXCEPT
get an iterator to after the last child
Definition: node.hpp:761
ConstImpl parent() const RYML_NOEXCEPT
Forward to Tree::parent().
Definition: node.hpp:340
bool key_is_null() const RYML_NOEXCEPT
Forward to Tree::key_is_null().
Definition: node.hpp:223
NodeType val_style() const RYML_NOEXCEPT
Forward to Tree::val_style().
Definition: node.hpp:276
auto get() RYML_NOEXCEPT -> NodeData *
returns the data or null when the id is NONE
Definition: node.hpp:205
detail::children_view_< Impl > children_view
Definition: node.hpp:750
bool parent_is_seq() const RYML_NOEXCEPT
Forward to Tree::parent_is_seq().
Definition: node.hpp:254
bool is_doc() const RYML_NOEXCEPT
Forward to Tree::is_doc().
Definition: node.hpp:238
auto doc(id_type i) RYML_NOEXCEPT -> Impl
Forward to Tree::doc().
Definition: node.hpp:335
auto visit(Visitor fn, id_type indentation_level=0, bool skip_root=true) RYML_NOEXCEPT -> bool
visit every child node calling fn(node)
Definition: node.hpp:803
bool is_key_dquo() const RYML_NOEXCEPT
Forward to Tree::is_key_dquo().
Definition: node.hpp:292
size_t deserialize_key(fmt::base64_wrapper v) const
decode the base64-encoded key and assign the decoded blob to the given buffer/
Definition: node.hpp:715
id_type num_children() const RYML_NOEXCEPT
O(num_children).
Definition: node.hpp:386
bool is_val_unfiltered() const noexcept
Forward to Tree::is_val_unfiltered().
Definition: node.hpp:227
ConstImpl first_sibling() const RYML_NOEXCEPT
Forward to Tree::first_sibling().
Definition: node.hpp:368
ConstImpl doc(id_type i) const RYML_NOEXCEPT
Forward to Tree::doc().
Definition: node.hpp:336
bool is_flow_sl() const RYML_NOEXCEPT
Forward to Tree::is_flow_sl().
Definition: node.hpp:280
auto at(id_type pos) -> Impl
Find child by position; complexity is O(pos).
Definition: node.hpp:565
bool is_flow() const RYML_NOEXCEPT
Forward to Tree::is_flow().
Definition: node.hpp:282
ConstImpl at(id_type pos) const
Get a child by position, with error checking; complexity is O(pos).
Definition: node.hpp:606
auto child(id_type pos) RYML_NOEXCEPT -> Impl
Forward to Tree::child().
Definition: node.hpp:351
bool is_block() const RYML_NOEXCEPT
Forward to Tree::is_block().
Definition: node.hpp:279
const_iterator cend() const RYML_NOEXCEPT
get an iterator to after the last child
Definition: node.hpp:763
bool is_key_folded() const RYML_NOEXCEPT
Forward to Tree::is_key_folded().
Definition: node.hpp:288
auto ancestor_doc() RYML_NOEXCEPT -> Impl
Forward to Tree::ancestor_doc().
Definition: node.hpp:383
Location location(Parser const &parser) const
Definition: node.hpp:626
bool is_val_plain() const RYML_NOEXCEPT
Forward to Tree::is_val_plain().
Definition: node.hpp:295
bool is_seq() const RYML_NOEXCEPT
Forward to Tree::is_seq().
Definition: node.hpp:241
bool is_val_folded() const RYML_NOEXCEPT
Forward to Tree::is_val_folded().
Definition: node.hpp:289
detail::child_iterator< ConstImpl > const_iterator
Definition: node.hpp:749
bool has_children() const RYML_NOEXCEPT
Forward to Tree::has_children().
Definition: node.hpp:316
bool is_val_quoted() const RYML_NOEXCEPT
Forward to Tree::is_val_quoted().
Definition: node.hpp:297
auto sibling(id_type pos) RYML_NOEXCEPT -> Impl
Forward to Tree::sibling().
Definition: node.hpp:375
bool is_val_literal() const RYML_NOEXCEPT
Forward to Tree::is_val_literal().
Definition: node.hpp:287
bool has_child(id_type node) const RYML_NOEXCEPT
Forward to Tree::has_child().
Definition: node.hpp:314
bool is_key_squo() const RYML_NOEXCEPT
Forward to Tree::is_key_squo().
Definition: node.hpp:290
bool is_val_hanchor() const noexcept
Definition: node.hpp:258
auto operator[](csubstr key) RYML_NOEXCEPT -> Impl
Find child by key; complexity is O(num_children).
Definition: node.hpp:422
bool has_val() const RYML_NOEXCEPT
Forward to Tree::has_val().
Definition: node.hpp:242
ConstImpl first_child() const RYML_NOEXCEPT
Forward to Tree::first_child().
Definition: node.hpp:344
bool has_sibling(ConstImpl const &n) const RYML_NOEXCEPT
Forward to Tree::has_sibling().
Definition: node.hpp:318
bool is_keyval() const RYML_NOEXCEPT
Forward to Tree::is_keyval().
Definition: node.hpp:245
bool has_val_tag() const RYML_NOEXCEPT
Forward to Tree::has_val_tag().
Definition: node.hpp:247
auto prev_sibling() RYML_NOEXCEPT -> Impl
Forward to Tree::prev_sibling().
Definition: node.hpp:359
ConstImpl prev_sibling() const RYML_NOEXCEPT
Forward to Tree::prev_sibling().
Definition: node.hpp:360
id_type num_other_siblings() const RYML_NOEXCEPT
O(num_siblings).
Definition: node.hpp:388
const_iterator begin() const RYML_NOEXCEPT
get an iterator to the first child
Definition: node.hpp:755
bool is_val_dquo() const RYML_NOEXCEPT
Forward to Tree::is_val_dquo().
Definition: node.hpp:293
bool is_ref() const RYML_NOEXCEPT
Forward to Tree::is_ref().
Definition: node.hpp:253