Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/rapidyaml/include/c4/yml/node.hpp
4264 views
1
#ifndef _C4_YML_NODE_HPP_
2
#define _C4_YML_NODE_HPP_
3
4
/** @file node.hpp
5
* @see NodeRef */
6
7
#include <cstddef>
8
9
#include "c4/yml/tree.hpp"
10
#include "c4/base64.hpp"
11
12
#ifdef __clang__
13
# pragma clang diagnostic push
14
# pragma clang diagnostic ignored "-Wtype-limits"
15
# pragma clang diagnostic ignored "-Wold-style-cast"
16
#elif defined(__GNUC__)
17
# pragma GCC diagnostic push
18
# pragma GCC diagnostic ignored "-Wtype-limits"
19
# pragma GCC diagnostic ignored "-Wold-style-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
template<class K> struct Key { K & k; };
30
template<> struct Key<fmt::const_base64_wrapper> { fmt::const_base64_wrapper wrapper; };
31
template<> struct Key<fmt::base64_wrapper> { fmt::base64_wrapper wrapper; };
32
33
template<class K> C4_ALWAYS_INLINE Key<K> key(K & k) { return Key<K>{k}; }
34
C4_ALWAYS_INLINE Key<fmt::const_base64_wrapper> key(fmt::const_base64_wrapper w) { return {w}; }
35
C4_ALWAYS_INLINE Key<fmt::base64_wrapper> key(fmt::base64_wrapper w) { return {w}; }
36
37
template<class T> void write(NodeRef *n, T const& v);
38
39
template<class T>
40
typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type
41
read(NodeRef const& n, T *v);
42
43
template<class T>
44
typename std::enable_if< std::is_floating_point<T>::value, bool>::type
45
read(NodeRef const& n, T *v);
46
47
48
//-----------------------------------------------------------------------------
49
//-----------------------------------------------------------------------------
50
//-----------------------------------------------------------------------------
51
52
// forward decls
53
class NodeRef;
54
class ConstNodeRef;
55
56
//-----------------------------------------------------------------------------
57
//-----------------------------------------------------------------------------
58
//-----------------------------------------------------------------------------
59
60
namespace detail {
61
62
template<class NodeRefType>
63
struct child_iterator
64
{
65
using value_type = NodeRefType;
66
using tree_type = typename NodeRefType::tree_type;
67
68
tree_type * C4_RESTRICT m_tree;
69
size_t m_child_id;
70
71
child_iterator(tree_type * t, size_t id) : m_tree(t), m_child_id(id) {}
72
73
child_iterator& operator++ () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->next_sibling(m_child_id); return *this; }
74
child_iterator& operator-- () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->prev_sibling(m_child_id); return *this; }
75
76
NodeRefType operator* () const { return NodeRefType(m_tree, m_child_id); }
77
NodeRefType operator-> () const { return NodeRefType(m_tree, m_child_id); }
78
79
bool operator!= (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id != that.m_child_id; }
80
bool operator== (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id == that.m_child_id; }
81
};
82
83
template<class NodeRefType>
84
struct children_view_
85
{
86
using n_iterator = child_iterator<NodeRefType>;
87
88
n_iterator b, e;
89
90
inline children_view_(n_iterator const& C4_RESTRICT b_,
91
n_iterator const& C4_RESTRICT e_) : b(b_), e(e_) {}
92
93
inline n_iterator begin() const { return b; }
94
inline n_iterator end () const { return e; }
95
};
96
97
template<class NodeRefType, class Visitor>
98
bool _visit(NodeRefType &node, Visitor fn, size_t indentation_level, bool skip_root=false)
99
{
100
size_t increment = 0;
101
if( ! (node.is_root() && skip_root))
102
{
103
if(fn(node, indentation_level))
104
return true;
105
++increment;
106
}
107
if(node.has_children())
108
{
109
for(auto ch : node.children())
110
{
111
if(_visit(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
112
{
113
return true;
114
}
115
}
116
}
117
return false;
118
}
119
120
template<class NodeRefType, class Visitor>
121
bool _visit_stacked(NodeRefType &node, Visitor fn, size_t indentation_level, bool skip_root=false)
122
{
123
size_t increment = 0;
124
if( ! (node.is_root() && skip_root))
125
{
126
if(fn(node, indentation_level))
127
{
128
return true;
129
}
130
++increment;
131
}
132
if(node.has_children())
133
{
134
fn.push(node, indentation_level);
135
for(auto ch : node.children())
136
{
137
if(_visit_stacked(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root
138
{
139
fn.pop(node, indentation_level);
140
return true;
141
}
142
}
143
fn.pop(node, indentation_level);
144
}
145
return false;
146
}
147
148
149
//-----------------------------------------------------------------------------
150
151
/** a CRTP base for read-only node methods */
152
template<class Impl, class ConstImpl>
153
struct RoNodeMethods
154
{
155
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wcast-align")
156
// helper CRTP macros, undefined at the end
157
#define tree_ ((ConstImpl const* C4_RESTRICT)this)->m_tree
158
#define id_ ((ConstImpl const* C4_RESTRICT)this)->m_id
159
#define tree__ ((Impl const* C4_RESTRICT)this)->m_tree
160
#define id__ ((Impl const* C4_RESTRICT)this)->m_id
161
// require valid
162
#define _C4RV() \
163
RYML_ASSERT(tree_ != nullptr); \
164
_RYML_CB_ASSERT(tree_->m_callbacks, id_ != NONE)
165
#define _C4_IF_MUTABLE(ty) typename std::enable_if<!std::is_same<U, ConstImpl>::value, ty>::type
166
167
public:
168
169
/** @name node property getters */
170
/** @{ */
171
172
/** returns the data or null when the id is NONE */
173
C4_ALWAYS_INLINE C4_PURE NodeData const* get() const noexcept { RYML_ASSERT(tree_ != nullptr); return tree_->get(id_); }
174
/** returns the data or null when the id is NONE */
175
template<class U=Impl>
176
C4_ALWAYS_INLINE C4_PURE auto get() noexcept -> _C4_IF_MUTABLE(NodeData*) { RYML_ASSERT(tree_ != nullptr); return tree__->get(id__); }
177
178
C4_ALWAYS_INLINE C4_PURE NodeType type() const noexcept { _C4RV(); return tree_->type(id_); }
179
C4_ALWAYS_INLINE C4_PURE const char* type_str() const noexcept { return tree_->type_str(id_); }
180
181
C4_ALWAYS_INLINE C4_PURE csubstr key() const noexcept { _C4RV(); return tree_->key(id_); }
182
C4_ALWAYS_INLINE C4_PURE csubstr key_tag() const noexcept { _C4RV(); return tree_->key_tag(id_); }
183
C4_ALWAYS_INLINE C4_PURE csubstr key_ref() const noexcept { _C4RV(); return tree_->key_ref(id_); }
184
C4_ALWAYS_INLINE C4_PURE csubstr key_anchor() const noexcept { _C4RV(); return tree_->key_anchor(id_); }
185
186
C4_ALWAYS_INLINE C4_PURE csubstr val() const noexcept { _C4RV(); return tree_->val(id_); }
187
C4_ALWAYS_INLINE C4_PURE csubstr val_tag() const noexcept { _C4RV(); return tree_->val_tag(id_); }
188
C4_ALWAYS_INLINE C4_PURE csubstr val_ref() const noexcept { _C4RV(); return tree_->val_ref(id_); }
189
C4_ALWAYS_INLINE C4_PURE csubstr val_anchor() const noexcept { _C4RV(); return tree_->val_anchor(id_); }
190
191
C4_ALWAYS_INLINE C4_PURE NodeScalar const& keysc() const noexcept { _C4RV(); return tree_->keysc(id_); }
192
C4_ALWAYS_INLINE C4_PURE NodeScalar const& valsc() const noexcept { _C4RV(); return tree_->valsc(id_); }
193
194
C4_ALWAYS_INLINE C4_PURE bool key_is_null() const noexcept { _C4RV(); return tree_->key_is_null(id_); }
195
C4_ALWAYS_INLINE C4_PURE bool val_is_null() const noexcept { _C4RV(); return tree_->val_is_null(id_); }
196
197
/** @} */
198
199
public:
200
201
/** @name node property predicates */
202
/** @{ */
203
204
C4_ALWAYS_INLINE C4_PURE bool empty() const noexcept { _C4RV(); return tree_->empty(id_); }
205
C4_ALWAYS_INLINE C4_PURE bool is_stream() const noexcept { _C4RV(); return tree_->is_stream(id_); }
206
C4_ALWAYS_INLINE C4_PURE bool is_doc() const noexcept { _C4RV(); return tree_->is_doc(id_); }
207
C4_ALWAYS_INLINE C4_PURE bool is_container() const noexcept { _C4RV(); return tree_->is_container(id_); }
208
C4_ALWAYS_INLINE C4_PURE bool is_map() const noexcept { _C4RV(); return tree_->is_map(id_); }
209
C4_ALWAYS_INLINE C4_PURE bool is_seq() const noexcept { _C4RV(); return tree_->is_seq(id_); }
210
C4_ALWAYS_INLINE C4_PURE bool has_val() const noexcept { _C4RV(); return tree_->has_val(id_); }
211
C4_ALWAYS_INLINE C4_PURE bool has_key() const noexcept { _C4RV(); return tree_->has_key(id_); }
212
C4_ALWAYS_INLINE C4_PURE bool is_val() const noexcept { _C4RV(); return tree_->is_val(id_); }
213
C4_ALWAYS_INLINE C4_PURE bool is_keyval() const noexcept { _C4RV(); return tree_->is_keyval(id_); }
214
C4_ALWAYS_INLINE C4_PURE bool has_key_tag() const noexcept { _C4RV(); return tree_->has_key_tag(id_); }
215
C4_ALWAYS_INLINE C4_PURE bool has_val_tag() const noexcept { _C4RV(); return tree_->has_val_tag(id_); }
216
C4_ALWAYS_INLINE C4_PURE bool has_key_anchor() const noexcept { _C4RV(); return tree_->has_key_anchor(id_); }
217
C4_ALWAYS_INLINE C4_PURE bool is_key_anchor() const noexcept { _C4RV(); return tree_->is_key_anchor(id_); }
218
C4_ALWAYS_INLINE C4_PURE bool has_val_anchor() const noexcept { _C4RV(); return tree_->has_val_anchor(id_); }
219
C4_ALWAYS_INLINE C4_PURE bool is_val_anchor() const noexcept { _C4RV(); return tree_->is_val_anchor(id_); }
220
C4_ALWAYS_INLINE C4_PURE bool has_anchor() const noexcept { _C4RV(); return tree_->has_anchor(id_); }
221
C4_ALWAYS_INLINE C4_PURE bool is_anchor() const noexcept { _C4RV(); return tree_->is_anchor(id_); }
222
C4_ALWAYS_INLINE C4_PURE bool is_key_ref() const noexcept { _C4RV(); return tree_->is_key_ref(id_); }
223
C4_ALWAYS_INLINE C4_PURE bool is_val_ref() const noexcept { _C4RV(); return tree_->is_val_ref(id_); }
224
C4_ALWAYS_INLINE C4_PURE bool is_ref() const noexcept { _C4RV(); return tree_->is_ref(id_); }
225
C4_ALWAYS_INLINE C4_PURE bool is_anchor_or_ref() const noexcept { _C4RV(); return tree_->is_anchor_or_ref(id_); }
226
C4_ALWAYS_INLINE C4_PURE bool is_key_quoted() const noexcept { _C4RV(); return tree_->is_key_quoted(id_); }
227
C4_ALWAYS_INLINE C4_PURE bool is_val_quoted() const noexcept { _C4RV(); return tree_->is_val_quoted(id_); }
228
C4_ALWAYS_INLINE C4_PURE bool is_quoted() const noexcept { _C4RV(); return tree_->is_quoted(id_); }
229
C4_ALWAYS_INLINE C4_PURE bool parent_is_seq() const noexcept { _C4RV(); return tree_->parent_is_seq(id_); }
230
C4_ALWAYS_INLINE C4_PURE bool parent_is_map() const noexcept { _C4RV(); return tree_->parent_is_map(id_); }
231
232
/** @} */
233
234
public:
235
236
/** @name hierarchy predicates */
237
/** @{ */
238
239
C4_ALWAYS_INLINE C4_PURE bool is_root() const noexcept { _C4RV(); return tree_->is_root(id_); }
240
C4_ALWAYS_INLINE C4_PURE bool has_parent() const noexcept { _C4RV(); return tree_->has_parent(id_); }
241
242
C4_ALWAYS_INLINE C4_PURE bool has_child(ConstImpl const& ch) const noexcept { _C4RV(); return tree_->has_child(id_, ch.m_id); }
243
C4_ALWAYS_INLINE C4_PURE bool has_child(csubstr name) const noexcept { _C4RV(); return tree_->has_child(id_, name); }
244
C4_ALWAYS_INLINE C4_PURE bool has_children() const noexcept { _C4RV(); return tree_->has_children(id_); }
245
246
C4_ALWAYS_INLINE C4_PURE bool has_sibling(ConstImpl const& n) const noexcept { _C4RV(); return tree_->has_sibling(id_, n.m_id); }
247
C4_ALWAYS_INLINE C4_PURE bool has_sibling(csubstr name) const noexcept { _C4RV(); return tree_->has_sibling(id_, name); }
248
/** counts with this */
249
C4_ALWAYS_INLINE C4_PURE bool has_siblings() const noexcept { _C4RV(); return tree_->has_siblings(id_); }
250
/** does not count with this */
251
C4_ALWAYS_INLINE C4_PURE bool has_other_siblings() const noexcept { _C4RV(); return tree_->has_other_siblings(id_); }
252
253
/** @} */
254
255
public:
256
257
/** @name hierarchy getters */
258
/** @{ */
259
260
261
template<class U=Impl>
262
C4_ALWAYS_INLINE C4_PURE auto doc(size_t num) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->doc(num)}; }
263
C4_ALWAYS_INLINE C4_PURE ConstImpl doc(size_t num) const noexcept { _C4RV(); return {tree_, tree_->doc(num)}; }
264
265
266
template<class U=Impl>
267
C4_ALWAYS_INLINE C4_PURE auto parent() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->parent(id__)}; }
268
C4_ALWAYS_INLINE C4_PURE ConstImpl parent() const noexcept { _C4RV(); return {tree_, tree_->parent(id_)}; }
269
270
271
/** O(#num_children) */
272
C4_ALWAYS_INLINE C4_PURE size_t child_pos(ConstImpl const& n) const noexcept { _C4RV(); return tree_->child_pos(id_, n.m_id); }
273
C4_ALWAYS_INLINE C4_PURE size_t num_children() const noexcept { _C4RV(); return tree_->num_children(id_); }
274
275
template<class U=Impl>
276
C4_ALWAYS_INLINE C4_PURE auto first_child() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->first_child(id__)}; }
277
C4_ALWAYS_INLINE C4_PURE ConstImpl first_child() const noexcept { _C4RV(); return {tree_, tree_->first_child(id_)}; }
278
279
template<class U=Impl>
280
C4_ALWAYS_INLINE C4_PURE auto last_child() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->last_child(id__)}; }
281
C4_ALWAYS_INLINE C4_PURE ConstImpl last_child () const noexcept { _C4RV(); return {tree_, tree_->last_child (id_)}; }
282
283
template<class U=Impl>
284
C4_ALWAYS_INLINE C4_PURE auto child(size_t pos) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->child(id__, pos)}; }
285
C4_ALWAYS_INLINE C4_PURE ConstImpl child(size_t pos) const noexcept { _C4RV(); return {tree_, tree_->child(id_, pos)}; }
286
287
template<class U=Impl>
288
C4_ALWAYS_INLINE C4_PURE auto find_child(csubstr name) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->find_child(id__, name)}; }
289
C4_ALWAYS_INLINE C4_PURE ConstImpl find_child(csubstr name) const noexcept { _C4RV(); return {tree_, tree_->find_child(id_, name)}; }
290
291
292
/** O(#num_siblings) */
293
C4_ALWAYS_INLINE C4_PURE size_t num_siblings() const noexcept { _C4RV(); return tree_->num_siblings(id_); }
294
C4_ALWAYS_INLINE C4_PURE size_t num_other_siblings() const noexcept { _C4RV(); return tree_->num_other_siblings(id_); }
295
C4_ALWAYS_INLINE C4_PURE size_t sibling_pos(ConstImpl const& n) const noexcept { _C4RV(); return tree_->child_pos(tree_->parent(id_), n.m_id); }
296
297
template<class U=Impl>
298
C4_ALWAYS_INLINE C4_PURE auto prev_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->prev_sibling(id__)}; }
299
C4_ALWAYS_INLINE C4_PURE ConstImpl prev_sibling() const noexcept { _C4RV(); return {tree_, tree_->prev_sibling(id_)}; }
300
301
template<class U=Impl>
302
C4_ALWAYS_INLINE C4_PURE auto next_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->next_sibling(id__)}; }
303
C4_ALWAYS_INLINE C4_PURE ConstImpl next_sibling() const noexcept { _C4RV(); return {tree_, tree_->next_sibling(id_)}; }
304
305
template<class U=Impl>
306
C4_ALWAYS_INLINE C4_PURE auto first_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->first_sibling(id__)}; }
307
C4_ALWAYS_INLINE C4_PURE ConstImpl first_sibling() const noexcept { _C4RV(); return {tree_, tree_->first_sibling(id_)}; }
308
309
template<class U=Impl>
310
C4_ALWAYS_INLINE C4_PURE auto last_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->last_sibling(id__)}; }
311
C4_ALWAYS_INLINE C4_PURE ConstImpl last_sibling () const noexcept { _C4RV(); return {tree_, tree_->last_sibling(id_)}; }
312
313
template<class U=Impl>
314
C4_ALWAYS_INLINE C4_PURE auto sibling(size_t pos) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->sibling(id__, pos)}; }
315
C4_ALWAYS_INLINE C4_PURE ConstImpl sibling(size_t pos) const noexcept { _C4RV(); return {tree_, tree_->sibling(id_, pos)}; }
316
317
template<class U=Impl>
318
C4_ALWAYS_INLINE C4_PURE auto find_sibling(csubstr name) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->find_sibling(id__, name)}; }
319
C4_ALWAYS_INLINE C4_PURE ConstImpl find_sibling(csubstr name) const noexcept { _C4RV(); return {tree_, tree_->find_sibling(id_, name)}; }
320
321
322
/** O(num_children) */
323
C4_ALWAYS_INLINE C4_PURE ConstImpl operator[] (csubstr k) const noexcept
324
{
325
_C4RV();
326
size_t ch = tree_->find_child(id_, k);
327
_RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE);
328
return {tree_, ch};
329
}
330
/** Find child by key. O(num_children). returns a seed node if no such child is found. */
331
template<class U=Impl>
332
C4_ALWAYS_INLINE C4_PURE auto operator[] (csubstr k) noexcept -> _C4_IF_MUTABLE(Impl)
333
{
334
_C4RV();
335
size_t ch = tree__->find_child(id__, k);
336
return ch != NONE ? Impl(tree__, ch) : NodeRef(tree__, id__, k);
337
}
338
339
/** O(num_children) */
340
C4_ALWAYS_INLINE C4_PURE ConstImpl operator[] (size_t pos) const noexcept
341
{
342
_C4RV();
343
size_t ch = tree_->child(id_, pos);
344
_RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE);
345
return {tree_, ch};
346
}
347
348
/** Find child by position. O(pos). returns a seed node if no such child is found. */
349
template<class U=Impl>
350
C4_ALWAYS_INLINE C4_PURE auto operator[] (size_t pos) noexcept -> _C4_IF_MUTABLE(Impl)
351
{
352
_C4RV();
353
size_t ch = tree__->child(id__, pos);
354
return ch != NONE ? Impl(tree__, ch) : NodeRef(tree__, id__, pos);
355
}
356
357
/** @} */
358
359
public:
360
361
/** deserialization */
362
/** @{ */
363
364
template<class T>
365
ConstImpl const& operator>> (T &v) const
366
{
367
_C4RV();
368
if( ! read((ConstImpl const&)*this, &v))
369
_RYML_CB_ERR(tree_->m_callbacks, "could not deserialize value");
370
return *((ConstImpl const*)this);
371
}
372
373
/** deserialize the node's key to the given variable */
374
template<class T>
375
ConstImpl const& operator>> (Key<T> v) const
376
{
377
_C4RV();
378
if( ! from_chars(key(), &v.k))
379
_RYML_CB_ERR(tree_->m_callbacks, "could not deserialize key");
380
return *((ConstImpl const*)this);
381
}
382
383
/** deserialize the node's key as base64 */
384
ConstImpl const& operator>> (Key<fmt::base64_wrapper> w) const
385
{
386
deserialize_key(w.wrapper);
387
return *((ConstImpl const*)this);
388
}
389
390
/** deserialize the node's val as base64 */
391
ConstImpl const& operator>> (fmt::base64_wrapper w) const
392
{
393
deserialize_val(w);
394
return *((ConstImpl const*)this);
395
}
396
397
/** decode the base64-encoded key and assign the
398
* decoded blob to the given buffer/
399
* @return the size of base64-decoded blob */
400
size_t deserialize_key(fmt::base64_wrapper v) const
401
{
402
_C4RV();
403
return from_chars(key(), &v);
404
}
405
/** decode the base64-encoded key and assign the
406
* decoded blob to the given buffer/
407
* @return the size of base64-decoded blob */
408
size_t deserialize_val(fmt::base64_wrapper v) const
409
{
410
_C4RV();
411
return from_chars(val(), &v);
412
};
413
414
template<class T>
415
bool get_if(csubstr name, T *var) const
416
{
417
auto ch = find_child(name);
418
if(!ch.valid())
419
return false;
420
ch >> *var;
421
return true;
422
}
423
424
template<class T>
425
bool get_if(csubstr name, T *var, T const& fallback) const
426
{
427
auto ch = find_child(name);
428
if(ch.valid())
429
{
430
ch >> *var;
431
return true;
432
}
433
else
434
{
435
*var = fallback;
436
return false;
437
}
438
}
439
440
/** @} */
441
442
public:
443
444
#if defined(__clang__)
445
# pragma clang diagnostic push
446
# pragma clang diagnostic ignored "-Wnull-dereference"
447
#elif defined(__GNUC__)
448
# pragma GCC diagnostic push
449
# if __GNUC__ >= 6
450
# pragma GCC diagnostic ignored "-Wnull-dereference"
451
# endif
452
#endif
453
454
/** @name iteration */
455
/** @{ */
456
457
using iterator = detail::child_iterator<Impl>;
458
using const_iterator = detail::child_iterator<ConstImpl>;
459
using children_view = detail::children_view_<Impl>;
460
using const_children_view = detail::children_view_<ConstImpl>;
461
462
template<class U=Impl>
463
C4_ALWAYS_INLINE C4_PURE auto begin() noexcept -> _C4_IF_MUTABLE(iterator) { _C4RV(); return iterator(tree__, tree__->first_child(id__)); }
464
C4_ALWAYS_INLINE C4_PURE const_iterator begin() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }
465
C4_ALWAYS_INLINE C4_PURE const_iterator cbegin() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }
466
467
template<class U=Impl>
468
C4_ALWAYS_INLINE C4_PURE auto end() noexcept -> _C4_IF_MUTABLE(iterator) { _C4RV(); return iterator(tree__, NONE); }
469
C4_ALWAYS_INLINE C4_PURE const_iterator end() const noexcept { _C4RV(); return const_iterator(tree_, NONE); }
470
C4_ALWAYS_INLINE C4_PURE const_iterator cend() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }
471
472
/** get an iterable view over children */
473
template<class U=Impl>
474
C4_ALWAYS_INLINE C4_PURE auto children() noexcept -> _C4_IF_MUTABLE(children_view) { _C4RV(); return children_view(begin(), end()); }
475
/** get an iterable view over children */
476
C4_ALWAYS_INLINE C4_PURE const_children_view children() const noexcept { _C4RV(); return const_children_view(begin(), end()); }
477
/** get an iterable view over children */
478
C4_ALWAYS_INLINE C4_PURE const_children_view cchildren() const noexcept { _C4RV(); return const_children_view(begin(), end()); }
479
480
/** get an iterable view over all siblings (including the calling node) */
481
template<class U=Impl>
482
C4_ALWAYS_INLINE C4_PURE auto siblings() noexcept -> _C4_IF_MUTABLE(children_view)
483
{
484
_C4RV();
485
NodeData const *nd = tree__->get(id__);
486
return (nd->m_parent != NONE) ? // does it have a parent?
487
children_view(iterator(tree__, tree_->get(nd->m_parent)->m_first_child), iterator(tree__, NONE))
488
:
489
children_view(end(), end());
490
}
491
/** get an iterable view over all siblings (including the calling node) */
492
C4_ALWAYS_INLINE C4_PURE const_children_view siblings() const noexcept
493
{
494
_C4RV();
495
NodeData const *nd = tree_->get(id_);
496
return (nd->m_parent != NONE) ? // does it have a parent?
497
const_children_view(const_iterator(tree_, tree_->get(nd->m_parent)->m_first_child), const_iterator(tree_, NONE))
498
:
499
const_children_view(end(), end());
500
}
501
/** get an iterable view over all siblings (including the calling node) */
502
C4_ALWAYS_INLINE C4_PURE const_children_view csiblings() const noexcept { return siblings(); }
503
504
/** visit every child node calling fn(node) */
505
template<class Visitor>
506
C4_ALWAYS_INLINE bool visit(Visitor fn, size_t indentation_level=0, bool skip_root=true) const noexcept
507
{
508
return detail::_visit(*(ConstImpl const*)this, fn, indentation_level, skip_root);
509
}
510
/** visit every child node calling fn(node) */
511
template<class Visitor, class U=Impl>
512
auto visit(Visitor fn, size_t indentation_level=0, bool skip_root=true) noexcept
513
-> _C4_IF_MUTABLE(bool)
514
{
515
return detail::_visit(*(Impl*)this, fn, indentation_level, skip_root);
516
}
517
518
/** visit every child node calling fn(node, level) */
519
template<class Visitor>
520
C4_ALWAYS_INLINE bool visit_stacked(Visitor fn, size_t indentation_level=0, bool skip_root=true) const noexcept
521
{
522
return detail::_visit_stacked(*(ConstImpl const*)this, fn, indentation_level, skip_root);
523
}
524
/** visit every child node calling fn(node, level) */
525
template<class Visitor, class U=Impl>
526
auto visit_stacked(Visitor fn, size_t indentation_level=0, bool skip_root=true) noexcept
527
-> _C4_IF_MUTABLE(bool)
528
{
529
return detail::_visit_stacked(*(Impl*)this, fn, indentation_level, skip_root);
530
}
531
532
/** @} */
533
534
#if defined(__clang__)
535
# pragma clang diagnostic pop
536
#elif defined(__GNUC__)
537
# pragma GCC diagnostic pop
538
#endif
539
540
#undef _C4_IF_MUTABLE
541
#undef _C4RV
542
#undef tree_
543
#undef tree__
544
#undef id_
545
#undef id__
546
547
C4_SUPPRESS_WARNING_GCC_CLANG_POP
548
};
549
550
} // namespace detail
551
552
553
//-----------------------------------------------------------------------------
554
//-----------------------------------------------------------------------------
555
//-----------------------------------------------------------------------------
556
class RYML_EXPORT ConstNodeRef : public detail::RoNodeMethods<ConstNodeRef, ConstNodeRef>
557
{
558
public:
559
560
using tree_type = Tree const;
561
562
public:
563
564
Tree const* C4_RESTRICT m_tree;
565
size_t m_id;
566
567
friend NodeRef;
568
friend struct detail::RoNodeMethods<ConstNodeRef, ConstNodeRef>;
569
570
public:
571
572
/** @name construction */
573
/** @{ */
574
575
ConstNodeRef() : m_tree(nullptr), m_id(NONE) {}
576
ConstNodeRef(Tree const &t) : m_tree(&t), m_id(t .root_id()) {}
577
ConstNodeRef(Tree const *t) : m_tree(t ), m_id(t->root_id()) {}
578
ConstNodeRef(Tree const *t, size_t id) : m_tree(t), m_id(id) {}
579
ConstNodeRef(std::nullptr_t) : m_tree(nullptr), m_id(NONE) {}
580
581
ConstNodeRef(ConstNodeRef const&) = default;
582
ConstNodeRef(ConstNodeRef &&) = default;
583
584
ConstNodeRef(NodeRef const&);
585
ConstNodeRef(NodeRef &&);
586
587
/** @} */
588
589
public:
590
591
/** @name assignment */
592
/** @{ */
593
594
ConstNodeRef& operator= (std::nullptr_t) { m_tree = nullptr; m_id = NONE; return *this; }
595
596
ConstNodeRef& operator= (ConstNodeRef const&) = default;
597
ConstNodeRef& operator= (ConstNodeRef &&) = default;
598
599
ConstNodeRef& operator= (NodeRef const&);
600
ConstNodeRef& operator= (NodeRef &&);
601
602
603
/** @} */
604
605
public:
606
607
/** @name state queries */
608
/** @{ */
609
610
C4_ALWAYS_INLINE C4_PURE bool valid() const noexcept { return m_tree != nullptr && m_id != NONE; }
611
612
/** @} */
613
614
public:
615
616
/** @name member getters */
617
/** @{ */
618
619
C4_ALWAYS_INLINE C4_PURE Tree const* tree() const noexcept { return m_tree; }
620
C4_ALWAYS_INLINE C4_PURE size_t id() const noexcept { return m_id; }
621
622
/** @} */
623
624
public:
625
626
/** @name comparisons */
627
/** @{ */
628
629
C4_ALWAYS_INLINE C4_PURE bool operator== (ConstNodeRef const& that) const noexcept { RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }
630
C4_ALWAYS_INLINE C4_PURE bool operator!= (ConstNodeRef const& that) const noexcept { RYML_ASSERT(that.m_tree == m_tree); return ! this->operator==(that); }
631
632
C4_ALWAYS_INLINE C4_PURE bool operator== (std::nullptr_t) const noexcept { return m_tree == nullptr || m_id == NONE; }
633
C4_ALWAYS_INLINE C4_PURE bool operator!= (std::nullptr_t) const noexcept { return ! this->operator== (nullptr); }
634
635
C4_ALWAYS_INLINE C4_PURE bool operator== (csubstr val) const noexcept { RYML_ASSERT(has_val()); return m_tree->val(m_id) == val; }
636
C4_ALWAYS_INLINE C4_PURE bool operator!= (csubstr val) const noexcept { RYML_ASSERT(has_val()); return m_tree->val(m_id) != val; }
637
638
/** @} */
639
640
};
641
642
643
//-----------------------------------------------------------------------------
644
//-----------------------------------------------------------------------------
645
//-----------------------------------------------------------------------------
646
647
/** a reference to a node in an existing yaml tree, offering a more
648
* convenient API than the index-based API used in the tree. */
649
class RYML_EXPORT NodeRef : public detail::RoNodeMethods<NodeRef, ConstNodeRef>
650
{
651
public:
652
653
using tree_type = Tree;
654
using base_type = detail::RoNodeMethods<NodeRef, ConstNodeRef>;
655
656
private:
657
658
Tree *C4_RESTRICT m_tree;
659
size_t m_id;
660
661
/** This member is used to enable lazy operator[] writing. When a child
662
* with a key or index is not found, m_id is set to the id of the parent
663
* and the asked-for key or index are stored in this member until a write
664
* does happen. Then it is given as key or index for creating the child.
665
* When a key is used, the csubstr stores it (so the csubstr's string is
666
* non-null and the csubstr's size is different from NONE). When an index is
667
* used instead, the csubstr's string is set to null, and only the csubstr's
668
* size is set to a value different from NONE. Otherwise, when operator[]
669
* does find the child then this member is empty: the string is null and
670
* the size is NONE. */
671
csubstr m_seed;
672
673
friend ConstNodeRef;
674
friend struct detail::RoNodeMethods<NodeRef, ConstNodeRef>;
675
676
// require valid: a helper macro, undefined at the end
677
#define _C4RV() \
678
RYML_ASSERT(m_tree != nullptr); \
679
_RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE && !is_seed())
680
681
public:
682
683
/** @name construction */
684
/** @{ */
685
686
NodeRef() : m_tree(nullptr), m_id(NONE), m_seed() { _clear_seed(); }
687
NodeRef(Tree &t) : m_tree(&t), m_id(t .root_id()), m_seed() { _clear_seed(); }
688
NodeRef(Tree *t) : m_tree(t ), m_id(t->root_id()), m_seed() { _clear_seed(); }
689
NodeRef(Tree *t, size_t id) : m_tree(t), m_id(id), m_seed() { _clear_seed(); }
690
NodeRef(Tree *t, size_t id, size_t seed_pos) : m_tree(t), m_id(id), m_seed() { m_seed.str = nullptr; m_seed.len = seed_pos; }
691
NodeRef(Tree *t, size_t id, csubstr seed_key) : m_tree(t), m_id(id), m_seed(seed_key) {}
692
NodeRef(std::nullptr_t) : m_tree(nullptr), m_id(NONE), m_seed() {}
693
694
/** @} */
695
696
public:
697
698
/** @name assignment */
699
/** @{ */
700
701
NodeRef(NodeRef const&) = default;
702
NodeRef(NodeRef &&) = default;
703
704
NodeRef& operator= (NodeRef const&) = default;
705
NodeRef& operator= (NodeRef &&) = default;
706
707
/** @} */
708
709
public:
710
711
/** @name state queries */
712
/** @{ */
713
714
inline bool valid() const { return m_tree != nullptr && m_id != NONE; }
715
inline bool is_seed() const { return m_seed.str != nullptr || m_seed.len != NONE; }
716
717
inline void _clear_seed() { /*do this manually or an assert is triggered*/ m_seed.str = nullptr; m_seed.len = NONE; }
718
719
/** @} */
720
721
public:
722
723
/** @name comparisons */
724
/** @{ */
725
726
inline bool operator== (NodeRef const& that) const { _C4RV(); RYML_ASSERT(that.valid() && !that.is_seed()); RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }
727
inline bool operator!= (NodeRef const& that) const { return ! this->operator==(that); }
728
729
inline bool operator== (ConstNodeRef const& that) const { _C4RV(); RYML_ASSERT(that.valid()); RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }
730
inline bool operator!= (ConstNodeRef const& that) const { return ! this->operator==(that); }
731
732
inline bool operator== (std::nullptr_t) const { return m_tree == nullptr || m_id == NONE || is_seed(); }
733
inline bool operator!= (std::nullptr_t) const { return m_tree != nullptr && m_id != NONE && !is_seed(); }
734
735
inline bool operator== (csubstr val) const { _C4RV(); RYML_ASSERT(has_val()); return m_tree->val(m_id) == val; }
736
inline bool operator!= (csubstr val) const { _C4RV(); RYML_ASSERT(has_val()); return m_tree->val(m_id) != val; }
737
738
//inline operator bool () const { return m_tree == nullptr || m_id == NONE || is_seed(); }
739
740
/** @} */
741
742
public:
743
744
/** @name node property getters */
745
/** @{ */
746
747
C4_ALWAYS_INLINE C4_PURE Tree * tree() noexcept { return m_tree; }
748
C4_ALWAYS_INLINE C4_PURE Tree const* tree() const noexcept { return m_tree; }
749
750
C4_ALWAYS_INLINE C4_PURE size_t id() const noexcept { return m_id; }
751
752
/** @} */
753
754
public:
755
756
/** @name node modifiers */
757
/** @{ */
758
759
void change_type(NodeType t) { _C4RV(); m_tree->change_type(m_id, t); }
760
761
void set_type(NodeType t) { _C4RV(); m_tree->_set_flags(m_id, t); }
762
void set_key(csubstr key) { _C4RV(); m_tree->_set_key(m_id, key); }
763
void set_val(csubstr val) { _C4RV(); m_tree->_set_val(m_id, val); }
764
void set_key_tag(csubstr key_tag) { _C4RV(); m_tree->set_key_tag(m_id, key_tag); }
765
void set_val_tag(csubstr val_tag) { _C4RV(); m_tree->set_val_tag(m_id, val_tag); }
766
void set_key_anchor(csubstr key_anchor) { _C4RV(); m_tree->set_key_anchor(m_id, key_anchor); }
767
void set_val_anchor(csubstr val_anchor) { _C4RV(); m_tree->set_val_anchor(m_id, val_anchor); }
768
void set_key_ref(csubstr key_ref) { _C4RV(); m_tree->set_key_ref(m_id, key_ref); }
769
void set_val_ref(csubstr val_ref) { _C4RV(); m_tree->set_val_ref(m_id, val_ref); }
770
771
template<class T>
772
size_t set_key_serialized(T const& C4_RESTRICT k)
773
{
774
_C4RV();
775
csubstr s = m_tree->to_arena(k);
776
m_tree->_set_key(m_id, s);
777
return s.len;
778
}
779
template<class T>
780
size_t set_val_serialized(T const& C4_RESTRICT v)
781
{
782
_C4RV();
783
csubstr s = m_tree->to_arena(v);
784
m_tree->_set_val(m_id, s);
785
return s.len;
786
}
787
size_t set_val_serialized(std::nullptr_t)
788
{
789
_C4RV();
790
m_tree->_set_val(m_id, csubstr{});
791
return 0;
792
}
793
794
/** encode a blob as base64, then assign the result to the node's key
795
* @return the size of base64-encoded blob */
796
size_t set_key_serialized(fmt::const_base64_wrapper w);
797
/** encode a blob as base64, then assign the result to the node's val
798
* @return the size of base64-encoded blob */
799
size_t set_val_serialized(fmt::const_base64_wrapper w);
800
801
public:
802
803
inline void clear()
804
{
805
if(is_seed())
806
return;
807
m_tree->remove_children(m_id);
808
m_tree->_clear(m_id);
809
}
810
811
inline void clear_key()
812
{
813
if(is_seed())
814
return;
815
m_tree->_clear_key(m_id);
816
}
817
818
inline void clear_val()
819
{
820
if(is_seed())
821
return;
822
m_tree->_clear_val(m_id);
823
}
824
825
inline void clear_children()
826
{
827
if(is_seed())
828
return;
829
m_tree->remove_children(m_id);
830
}
831
832
void create() { _apply_seed(); }
833
834
inline void operator= (NodeType_e t)
835
{
836
_apply_seed();
837
m_tree->_add_flags(m_id, t);
838
}
839
840
inline void operator|= (NodeType_e t)
841
{
842
_apply_seed();
843
m_tree->_add_flags(m_id, t);
844
}
845
846
inline void operator= (NodeInit const& v)
847
{
848
_apply_seed();
849
_apply(v);
850
}
851
852
inline void operator= (NodeScalar const& v)
853
{
854
_apply_seed();
855
_apply(v);
856
}
857
858
inline void operator= (std::nullptr_t)
859
{
860
_apply_seed();
861
_apply(csubstr{});
862
}
863
864
inline void operator= (csubstr v)
865
{
866
_apply_seed();
867
_apply(v);
868
}
869
870
template<size_t N>
871
inline void operator= (const char (&v)[N])
872
{
873
_apply_seed();
874
csubstr sv;
875
sv.assign<N>(v);
876
_apply(sv);
877
}
878
879
/** @} */
880
881
public:
882
883
/** @name serialization */
884
/** @{ */
885
886
/** serialize a variable to the arena */
887
template<class T>
888
inline csubstr to_arena(T const& C4_RESTRICT s)
889
{
890
_C4RV();
891
return m_tree->to_arena(s);
892
}
893
894
/** serialize a variable, then assign the result to the node's val */
895
inline NodeRef& operator<< (csubstr s)
896
{
897
// this overload is needed to prevent ambiguity (there's also
898
// operator<< for writing a substr to a stream)
899
_apply_seed();
900
write(this, s);
901
RYML_ASSERT(val() == s);
902
return *this;
903
}
904
905
template<class T>
906
inline NodeRef& operator<< (T const& C4_RESTRICT v)
907
{
908
_apply_seed();
909
write(this, v);
910
return *this;
911
}
912
913
/** serialize a variable, then assign the result to the node's key */
914
template<class T>
915
inline NodeRef& operator<< (Key<const T> const& C4_RESTRICT v)
916
{
917
_apply_seed();
918
set_key_serialized(v.k);
919
return *this;
920
}
921
922
/** serialize a variable, then assign the result to the node's key */
923
template<class T>
924
inline NodeRef& operator<< (Key<T> const& C4_RESTRICT v)
925
{
926
_apply_seed();
927
set_key_serialized(v.k);
928
return *this;
929
}
930
931
NodeRef& operator<< (Key<fmt::const_base64_wrapper> w)
932
{
933
set_key_serialized(w.wrapper);
934
return *this;
935
}
936
937
NodeRef& operator<< (fmt::const_base64_wrapper w)
938
{
939
set_val_serialized(w);
940
return *this;
941
}
942
943
/** @} */
944
945
private:
946
947
void _apply_seed()
948
{
949
if(m_seed.str) // we have a seed key: use it to create the new child
950
{
951
//RYML_ASSERT(i.key.scalar.empty() || m_key == i.key.scalar || m_key.empty());
952
m_id = m_tree->append_child(m_id);
953
m_tree->_set_key(m_id, m_seed);
954
m_seed.str = nullptr;
955
m_seed.len = NONE;
956
}
957
else if(m_seed.len != NONE) // we have a seed index: create a child at that position
958
{
959
RYML_ASSERT(m_tree->num_children(m_id) == m_seed.len);
960
m_id = m_tree->append_child(m_id);
961
m_seed.str = nullptr;
962
m_seed.len = NONE;
963
}
964
else
965
{
966
RYML_ASSERT(valid());
967
}
968
}
969
970
inline void _apply(csubstr v)
971
{
972
m_tree->_set_val(m_id, v);
973
}
974
975
inline void _apply(NodeScalar const& v)
976
{
977
m_tree->_set_val(m_id, v);
978
}
979
980
inline void _apply(NodeInit const& i)
981
{
982
m_tree->_set(m_id, i);
983
}
984
985
public:
986
987
/** @name modification of hierarchy */
988
/** @{ */
989
990
inline NodeRef insert_child(NodeRef after)
991
{
992
_C4RV();
993
RYML_ASSERT(after.m_tree == m_tree);
994
NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
995
return r;
996
}
997
998
inline NodeRef insert_child(NodeInit const& i, NodeRef after)
999
{
1000
_C4RV();
1001
RYML_ASSERT(after.m_tree == m_tree);
1002
NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));
1003
r._apply(i);
1004
return r;
1005
}
1006
1007
inline NodeRef prepend_child()
1008
{
1009
_C4RV();
1010
NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
1011
return r;
1012
}
1013
1014
inline NodeRef prepend_child(NodeInit const& i)
1015
{
1016
_C4RV();
1017
NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));
1018
r._apply(i);
1019
return r;
1020
}
1021
1022
inline NodeRef append_child()
1023
{
1024
_C4RV();
1025
NodeRef r(m_tree, m_tree->append_child(m_id));
1026
return r;
1027
}
1028
1029
inline NodeRef append_child(NodeInit const& i)
1030
{
1031
_C4RV();
1032
NodeRef r(m_tree, m_tree->append_child(m_id));
1033
r._apply(i);
1034
return r;
1035
}
1036
1037
public:
1038
1039
inline NodeRef insert_sibling(ConstNodeRef const& after)
1040
{
1041
_C4RV();
1042
RYML_ASSERT(after.m_tree == m_tree);
1043
NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
1044
return r;
1045
}
1046
1047
inline NodeRef insert_sibling(NodeInit const& i, ConstNodeRef const& after)
1048
{
1049
_C4RV();
1050
RYML_ASSERT(after.m_tree == m_tree);
1051
NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));
1052
r._apply(i);
1053
return r;
1054
}
1055
1056
inline NodeRef prepend_sibling()
1057
{
1058
_C4RV();
1059
NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
1060
return r;
1061
}
1062
1063
inline NodeRef prepend_sibling(NodeInit const& i)
1064
{
1065
_C4RV();
1066
NodeRef r(m_tree, m_tree->prepend_sibling(m_id));
1067
r._apply(i);
1068
return r;
1069
}
1070
1071
inline NodeRef append_sibling()
1072
{
1073
_C4RV();
1074
NodeRef r(m_tree, m_tree->append_sibling(m_id));
1075
return r;
1076
}
1077
1078
inline NodeRef append_sibling(NodeInit const& i)
1079
{
1080
_C4RV();
1081
NodeRef r(m_tree, m_tree->append_sibling(m_id));
1082
r._apply(i);
1083
return r;
1084
}
1085
1086
public:
1087
1088
inline void remove_child(NodeRef & child)
1089
{
1090
_C4RV();
1091
RYML_ASSERT(has_child(child));
1092
RYML_ASSERT(child.parent().id() == id());
1093
m_tree->remove(child.id());
1094
child.clear();
1095
}
1096
1097
//! remove the nth child of this node
1098
inline void remove_child(size_t pos)
1099
{
1100
_C4RV();
1101
RYML_ASSERT(pos >= 0 && pos < num_children());
1102
size_t child = m_tree->child(m_id, pos);
1103
RYML_ASSERT(child != NONE);
1104
m_tree->remove(child);
1105
}
1106
1107
//! remove a child by name
1108
inline void remove_child(csubstr key)
1109
{
1110
_C4RV();
1111
size_t child = m_tree->find_child(m_id, key);
1112
RYML_ASSERT(child != NONE);
1113
m_tree->remove(child);
1114
}
1115
1116
public:
1117
1118
/** change the node's position within its parent, placing it after
1119
* @p after. To move to the first position in the parent, simply
1120
* pass an empty or default-constructed reference like this:
1121
* `n.move({})`. */
1122
inline void move(ConstNodeRef const& after)
1123
{
1124
_C4RV();
1125
m_tree->move(m_id, after.m_id);
1126
}
1127
1128
/** move the node to a different @p parent (which may belong to a
1129
* different tree), placing it after @p after. When the
1130
* destination parent is in a new tree, then this node's tree
1131
* pointer is reset to the tree of the parent node. */
1132
inline void move(NodeRef const& parent, ConstNodeRef const& after)
1133
{
1134
_C4RV();
1135
if(parent.m_tree == m_tree)
1136
{
1137
m_tree->move(m_id, parent.m_id, after.m_id);
1138
}
1139
else
1140
{
1141
parent.m_tree->move(m_tree, m_id, parent.m_id, after.m_id);
1142
m_tree = parent.m_tree;
1143
}
1144
}
1145
1146
/** duplicate the current node somewhere within its parent, and
1147
* place it after the node @p after. To place into the first
1148
* position of the parent, simply pass an empty or
1149
* default-constructed reference like this: `n.move({})`. */
1150
inline NodeRef duplicate(ConstNodeRef const& after) const
1151
{
1152
_C4RV();
1153
RYML_ASSERT(m_tree == after.m_tree || after.m_id == NONE);
1154
size_t dup = m_tree->duplicate(m_id, m_tree->parent(m_id), after.m_id);
1155
NodeRef r(m_tree, dup);
1156
return r;
1157
}
1158
1159
/** duplicate the current node somewhere into a different @p parent
1160
* (possibly from a different tree), and place it after the node
1161
* @p after. To place into the first position of the parent,
1162
* simply pass an empty or default-constructed reference like
1163
* this: `n.move({})`. */
1164
inline NodeRef duplicate(NodeRef const& parent, ConstNodeRef const& after) const
1165
{
1166
_C4RV();
1167
RYML_ASSERT(parent.m_tree == after.m_tree || after.m_id == NONE);
1168
if(parent.m_tree == m_tree)
1169
{
1170
size_t dup = m_tree->duplicate(m_id, parent.m_id, after.m_id);
1171
NodeRef r(m_tree, dup);
1172
return r;
1173
}
1174
else
1175
{
1176
size_t dup = parent.m_tree->duplicate(m_tree, m_id, parent.m_id, after.m_id);
1177
NodeRef r(parent.m_tree, dup);
1178
return r;
1179
}
1180
}
1181
1182
inline void duplicate_children(NodeRef const& parent, ConstNodeRef const& after) const
1183
{
1184
_C4RV();
1185
RYML_ASSERT(parent.m_tree == after.m_tree);
1186
if(parent.m_tree == m_tree)
1187
{
1188
m_tree->duplicate_children(m_id, parent.m_id, after.m_id);
1189
}
1190
else
1191
{
1192
parent.m_tree->duplicate_children(m_tree, m_id, parent.m_id, after.m_id);
1193
}
1194
}
1195
1196
/** @} */
1197
1198
#undef _C4RV
1199
};
1200
1201
1202
//-----------------------------------------------------------------------------
1203
1204
inline ConstNodeRef::ConstNodeRef(NodeRef const& that)
1205
: m_tree(that.m_tree)
1206
, m_id(!that.is_seed() ? that.id() : NONE)
1207
{
1208
}
1209
1210
inline ConstNodeRef::ConstNodeRef(NodeRef && that)
1211
: m_tree(that.m_tree)
1212
, m_id(!that.is_seed() ? that.id() : NONE)
1213
{
1214
}
1215
1216
1217
inline ConstNodeRef& ConstNodeRef::operator= (NodeRef const& that)
1218
{
1219
m_tree = (that.m_tree);
1220
m_id = (!that.is_seed() ? that.id() : NONE);
1221
return *this;
1222
}
1223
1224
inline ConstNodeRef& ConstNodeRef::operator= (NodeRef && that)
1225
{
1226
m_tree = (that.m_tree);
1227
m_id = (!that.is_seed() ? that.id() : NONE);
1228
return *this;
1229
}
1230
1231
1232
//-----------------------------------------------------------------------------
1233
1234
template<class T>
1235
inline void write(NodeRef *n, T const& v)
1236
{
1237
n->set_val_serialized(v);
1238
}
1239
1240
template<class T>
1241
typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type
1242
inline read(NodeRef const& n, T *v)
1243
{
1244
return from_chars(n.val(), v);
1245
}
1246
template<class T>
1247
typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type
1248
inline read(ConstNodeRef const& n, T *v)
1249
{
1250
return from_chars(n.val(), v);
1251
}
1252
1253
template<class T>
1254
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
1255
inline read(NodeRef const& n, T *v)
1256
{
1257
return from_chars_float(n.val(), v);
1258
}
1259
template<class T>
1260
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
1261
inline read(ConstNodeRef const& n, T *v)
1262
{
1263
return from_chars_float(n.val(), v);
1264
}
1265
1266
1267
} // namespace yml
1268
} // namespace c4
1269
1270
1271
1272
#ifdef __clang__
1273
# pragma clang diagnostic pop
1274
#elif defined(__GNUC__)
1275
# pragma GCC diagnostic pop
1276
#elif defined(_MSC_VER)
1277
# pragma warning(pop)
1278
#endif
1279
1280
#endif /* _C4_YML_NODE_HPP_ */
1281
1282