node.hpp (44865B)
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_ */