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