Path: blob/master/dep/rapidyaml/include/c4/yml/node.hpp
4264 views
#ifndef _C4_YML_NODE_HPP_1#define _C4_YML_NODE_HPP_23/** @file node.hpp4* @see NodeRef */56#include <cstddef>78#include "c4/yml/tree.hpp"9#include "c4/base64.hpp"1011#ifdef __clang__12# pragma clang diagnostic push13# pragma clang diagnostic ignored "-Wtype-limits"14# pragma clang diagnostic ignored "-Wold-style-cast"15#elif defined(__GNUC__)16# pragma GCC diagnostic push17# pragma GCC diagnostic ignored "-Wtype-limits"18# pragma GCC diagnostic ignored "-Wold-style-cast"19#elif defined(_MSC_VER)20# pragma warning(push)21# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)22# pragma warning(disable: 4296/*expression is always 'boolean_value'*/)23#endif2425namespace c4 {26namespace yml {2728template<class K> struct Key { K & k; };29template<> struct Key<fmt::const_base64_wrapper> { fmt::const_base64_wrapper wrapper; };30template<> struct Key<fmt::base64_wrapper> { fmt::base64_wrapper wrapper; };3132template<class K> C4_ALWAYS_INLINE Key<K> key(K & k) { return Key<K>{k}; }33C4_ALWAYS_INLINE Key<fmt::const_base64_wrapper> key(fmt::const_base64_wrapper w) { return {w}; }34C4_ALWAYS_INLINE Key<fmt::base64_wrapper> key(fmt::base64_wrapper w) { return {w}; }3536template<class T> void write(NodeRef *n, T const& v);3738template<class T>39typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type40read(NodeRef const& n, T *v);4142template<class T>43typename std::enable_if< std::is_floating_point<T>::value, bool>::type44read(NodeRef const& n, T *v);454647//-----------------------------------------------------------------------------48//-----------------------------------------------------------------------------49//-----------------------------------------------------------------------------5051// forward decls52class NodeRef;53class ConstNodeRef;5455//-----------------------------------------------------------------------------56//-----------------------------------------------------------------------------57//-----------------------------------------------------------------------------5859namespace detail {6061template<class NodeRefType>62struct child_iterator63{64using value_type = NodeRefType;65using tree_type = typename NodeRefType::tree_type;6667tree_type * C4_RESTRICT m_tree;68size_t m_child_id;6970child_iterator(tree_type * t, size_t id) : m_tree(t), m_child_id(id) {}7172child_iterator& operator++ () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->next_sibling(m_child_id); return *this; }73child_iterator& operator-- () { RYML_ASSERT(m_child_id != NONE); m_child_id = m_tree->prev_sibling(m_child_id); return *this; }7475NodeRefType operator* () const { return NodeRefType(m_tree, m_child_id); }76NodeRefType operator-> () const { return NodeRefType(m_tree, m_child_id); }7778bool operator!= (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id != that.m_child_id; }79bool operator== (child_iterator that) const { RYML_ASSERT(m_tree == that.m_tree); return m_child_id == that.m_child_id; }80};8182template<class NodeRefType>83struct children_view_84{85using n_iterator = child_iterator<NodeRefType>;8687n_iterator b, e;8889inline children_view_(n_iterator const& C4_RESTRICT b_,90n_iterator const& C4_RESTRICT e_) : b(b_), e(e_) {}9192inline n_iterator begin() const { return b; }93inline n_iterator end () const { return e; }94};9596template<class NodeRefType, class Visitor>97bool _visit(NodeRefType &node, Visitor fn, size_t indentation_level, bool skip_root=false)98{99size_t increment = 0;100if( ! (node.is_root() && skip_root))101{102if(fn(node, indentation_level))103return true;104++increment;105}106if(node.has_children())107{108for(auto ch : node.children())109{110if(_visit(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root111{112return true;113}114}115}116return false;117}118119template<class NodeRefType, class Visitor>120bool _visit_stacked(NodeRefType &node, Visitor fn, size_t indentation_level, bool skip_root=false)121{122size_t increment = 0;123if( ! (node.is_root() && skip_root))124{125if(fn(node, indentation_level))126{127return true;128}129++increment;130}131if(node.has_children())132{133fn.push(node, indentation_level);134for(auto ch : node.children())135{136if(_visit_stacked(ch, fn, indentation_level + increment, false)) // no need to forward skip_root as it won't be root137{138fn.pop(node, indentation_level);139return true;140}141}142fn.pop(node, indentation_level);143}144return false;145}146147148//-----------------------------------------------------------------------------149150/** a CRTP base for read-only node methods */151template<class Impl, class ConstImpl>152struct RoNodeMethods153{154C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wcast-align")155// helper CRTP macros, undefined at the end156#define tree_ ((ConstImpl const* C4_RESTRICT)this)->m_tree157#define id_ ((ConstImpl const* C4_RESTRICT)this)->m_id158#define tree__ ((Impl const* C4_RESTRICT)this)->m_tree159#define id__ ((Impl const* C4_RESTRICT)this)->m_id160// require valid161#define _C4RV() \162RYML_ASSERT(tree_ != nullptr); \163_RYML_CB_ASSERT(tree_->m_callbacks, id_ != NONE)164#define _C4_IF_MUTABLE(ty) typename std::enable_if<!std::is_same<U, ConstImpl>::value, ty>::type165166public:167168/** @name node property getters */169/** @{ */170171/** returns the data or null when the id is NONE */172C4_ALWAYS_INLINE C4_PURE NodeData const* get() const noexcept { RYML_ASSERT(tree_ != nullptr); return tree_->get(id_); }173/** returns the data or null when the id is NONE */174template<class U=Impl>175C4_ALWAYS_INLINE C4_PURE auto get() noexcept -> _C4_IF_MUTABLE(NodeData*) { RYML_ASSERT(tree_ != nullptr); return tree__->get(id__); }176177C4_ALWAYS_INLINE C4_PURE NodeType type() const noexcept { _C4RV(); return tree_->type(id_); }178C4_ALWAYS_INLINE C4_PURE const char* type_str() const noexcept { return tree_->type_str(id_); }179180C4_ALWAYS_INLINE C4_PURE csubstr key() const noexcept { _C4RV(); return tree_->key(id_); }181C4_ALWAYS_INLINE C4_PURE csubstr key_tag() const noexcept { _C4RV(); return tree_->key_tag(id_); }182C4_ALWAYS_INLINE C4_PURE csubstr key_ref() const noexcept { _C4RV(); return tree_->key_ref(id_); }183C4_ALWAYS_INLINE C4_PURE csubstr key_anchor() const noexcept { _C4RV(); return tree_->key_anchor(id_); }184185C4_ALWAYS_INLINE C4_PURE csubstr val() const noexcept { _C4RV(); return tree_->val(id_); }186C4_ALWAYS_INLINE C4_PURE csubstr val_tag() const noexcept { _C4RV(); return tree_->val_tag(id_); }187C4_ALWAYS_INLINE C4_PURE csubstr val_ref() const noexcept { _C4RV(); return tree_->val_ref(id_); }188C4_ALWAYS_INLINE C4_PURE csubstr val_anchor() const noexcept { _C4RV(); return tree_->val_anchor(id_); }189190C4_ALWAYS_INLINE C4_PURE NodeScalar const& keysc() const noexcept { _C4RV(); return tree_->keysc(id_); }191C4_ALWAYS_INLINE C4_PURE NodeScalar const& valsc() const noexcept { _C4RV(); return tree_->valsc(id_); }192193C4_ALWAYS_INLINE C4_PURE bool key_is_null() const noexcept { _C4RV(); return tree_->key_is_null(id_); }194C4_ALWAYS_INLINE C4_PURE bool val_is_null() const noexcept { _C4RV(); return tree_->val_is_null(id_); }195196/** @} */197198public:199200/** @name node property predicates */201/** @{ */202203C4_ALWAYS_INLINE C4_PURE bool empty() const noexcept { _C4RV(); return tree_->empty(id_); }204C4_ALWAYS_INLINE C4_PURE bool is_stream() const noexcept { _C4RV(); return tree_->is_stream(id_); }205C4_ALWAYS_INLINE C4_PURE bool is_doc() const noexcept { _C4RV(); return tree_->is_doc(id_); }206C4_ALWAYS_INLINE C4_PURE bool is_container() const noexcept { _C4RV(); return tree_->is_container(id_); }207C4_ALWAYS_INLINE C4_PURE bool is_map() const noexcept { _C4RV(); return tree_->is_map(id_); }208C4_ALWAYS_INLINE C4_PURE bool is_seq() const noexcept { _C4RV(); return tree_->is_seq(id_); }209C4_ALWAYS_INLINE C4_PURE bool has_val() const noexcept { _C4RV(); return tree_->has_val(id_); }210C4_ALWAYS_INLINE C4_PURE bool has_key() const noexcept { _C4RV(); return tree_->has_key(id_); }211C4_ALWAYS_INLINE C4_PURE bool is_val() const noexcept { _C4RV(); return tree_->is_val(id_); }212C4_ALWAYS_INLINE C4_PURE bool is_keyval() const noexcept { _C4RV(); return tree_->is_keyval(id_); }213C4_ALWAYS_INLINE C4_PURE bool has_key_tag() const noexcept { _C4RV(); return tree_->has_key_tag(id_); }214C4_ALWAYS_INLINE C4_PURE bool has_val_tag() const noexcept { _C4RV(); return tree_->has_val_tag(id_); }215C4_ALWAYS_INLINE C4_PURE bool has_key_anchor() const noexcept { _C4RV(); return tree_->has_key_anchor(id_); }216C4_ALWAYS_INLINE C4_PURE bool is_key_anchor() const noexcept { _C4RV(); return tree_->is_key_anchor(id_); }217C4_ALWAYS_INLINE C4_PURE bool has_val_anchor() const noexcept { _C4RV(); return tree_->has_val_anchor(id_); }218C4_ALWAYS_INLINE C4_PURE bool is_val_anchor() const noexcept { _C4RV(); return tree_->is_val_anchor(id_); }219C4_ALWAYS_INLINE C4_PURE bool has_anchor() const noexcept { _C4RV(); return tree_->has_anchor(id_); }220C4_ALWAYS_INLINE C4_PURE bool is_anchor() const noexcept { _C4RV(); return tree_->is_anchor(id_); }221C4_ALWAYS_INLINE C4_PURE bool is_key_ref() const noexcept { _C4RV(); return tree_->is_key_ref(id_); }222C4_ALWAYS_INLINE C4_PURE bool is_val_ref() const noexcept { _C4RV(); return tree_->is_val_ref(id_); }223C4_ALWAYS_INLINE C4_PURE bool is_ref() const noexcept { _C4RV(); return tree_->is_ref(id_); }224C4_ALWAYS_INLINE C4_PURE bool is_anchor_or_ref() const noexcept { _C4RV(); return tree_->is_anchor_or_ref(id_); }225C4_ALWAYS_INLINE C4_PURE bool is_key_quoted() const noexcept { _C4RV(); return tree_->is_key_quoted(id_); }226C4_ALWAYS_INLINE C4_PURE bool is_val_quoted() const noexcept { _C4RV(); return tree_->is_val_quoted(id_); }227C4_ALWAYS_INLINE C4_PURE bool is_quoted() const noexcept { _C4RV(); return tree_->is_quoted(id_); }228C4_ALWAYS_INLINE C4_PURE bool parent_is_seq() const noexcept { _C4RV(); return tree_->parent_is_seq(id_); }229C4_ALWAYS_INLINE C4_PURE bool parent_is_map() const noexcept { _C4RV(); return tree_->parent_is_map(id_); }230231/** @} */232233public:234235/** @name hierarchy predicates */236/** @{ */237238C4_ALWAYS_INLINE C4_PURE bool is_root() const noexcept { _C4RV(); return tree_->is_root(id_); }239C4_ALWAYS_INLINE C4_PURE bool has_parent() const noexcept { _C4RV(); return tree_->has_parent(id_); }240241C4_ALWAYS_INLINE C4_PURE bool has_child(ConstImpl const& ch) const noexcept { _C4RV(); return tree_->has_child(id_, ch.m_id); }242C4_ALWAYS_INLINE C4_PURE bool has_child(csubstr name) const noexcept { _C4RV(); return tree_->has_child(id_, name); }243C4_ALWAYS_INLINE C4_PURE bool has_children() const noexcept { _C4RV(); return tree_->has_children(id_); }244245C4_ALWAYS_INLINE C4_PURE bool has_sibling(ConstImpl const& n) const noexcept { _C4RV(); return tree_->has_sibling(id_, n.m_id); }246C4_ALWAYS_INLINE C4_PURE bool has_sibling(csubstr name) const noexcept { _C4RV(); return tree_->has_sibling(id_, name); }247/** counts with this */248C4_ALWAYS_INLINE C4_PURE bool has_siblings() const noexcept { _C4RV(); return tree_->has_siblings(id_); }249/** does not count with this */250C4_ALWAYS_INLINE C4_PURE bool has_other_siblings() const noexcept { _C4RV(); return tree_->has_other_siblings(id_); }251252/** @} */253254public:255256/** @name hierarchy getters */257/** @{ */258259260template<class U=Impl>261C4_ALWAYS_INLINE C4_PURE auto doc(size_t num) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->doc(num)}; }262C4_ALWAYS_INLINE C4_PURE ConstImpl doc(size_t num) const noexcept { _C4RV(); return {tree_, tree_->doc(num)}; }263264265template<class U=Impl>266C4_ALWAYS_INLINE C4_PURE auto parent() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->parent(id__)}; }267C4_ALWAYS_INLINE C4_PURE ConstImpl parent() const noexcept { _C4RV(); return {tree_, tree_->parent(id_)}; }268269270/** O(#num_children) */271C4_ALWAYS_INLINE C4_PURE size_t child_pos(ConstImpl const& n) const noexcept { _C4RV(); return tree_->child_pos(id_, n.m_id); }272C4_ALWAYS_INLINE C4_PURE size_t num_children() const noexcept { _C4RV(); return tree_->num_children(id_); }273274template<class U=Impl>275C4_ALWAYS_INLINE C4_PURE auto first_child() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->first_child(id__)}; }276C4_ALWAYS_INLINE C4_PURE ConstImpl first_child() const noexcept { _C4RV(); return {tree_, tree_->first_child(id_)}; }277278template<class U=Impl>279C4_ALWAYS_INLINE C4_PURE auto last_child() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->last_child(id__)}; }280C4_ALWAYS_INLINE C4_PURE ConstImpl last_child () const noexcept { _C4RV(); return {tree_, tree_->last_child (id_)}; }281282template<class U=Impl>283C4_ALWAYS_INLINE C4_PURE auto child(size_t pos) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->child(id__, pos)}; }284C4_ALWAYS_INLINE C4_PURE ConstImpl child(size_t pos) const noexcept { _C4RV(); return {tree_, tree_->child(id_, pos)}; }285286template<class U=Impl>287C4_ALWAYS_INLINE C4_PURE auto find_child(csubstr name) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->find_child(id__, name)}; }288C4_ALWAYS_INLINE C4_PURE ConstImpl find_child(csubstr name) const noexcept { _C4RV(); return {tree_, tree_->find_child(id_, name)}; }289290291/** O(#num_siblings) */292C4_ALWAYS_INLINE C4_PURE size_t num_siblings() const noexcept { _C4RV(); return tree_->num_siblings(id_); }293C4_ALWAYS_INLINE C4_PURE size_t num_other_siblings() const noexcept { _C4RV(); return tree_->num_other_siblings(id_); }294C4_ALWAYS_INLINE C4_PURE size_t sibling_pos(ConstImpl const& n) const noexcept { _C4RV(); return tree_->child_pos(tree_->parent(id_), n.m_id); }295296template<class U=Impl>297C4_ALWAYS_INLINE C4_PURE auto prev_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->prev_sibling(id__)}; }298C4_ALWAYS_INLINE C4_PURE ConstImpl prev_sibling() const noexcept { _C4RV(); return {tree_, tree_->prev_sibling(id_)}; }299300template<class U=Impl>301C4_ALWAYS_INLINE C4_PURE auto next_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->next_sibling(id__)}; }302C4_ALWAYS_INLINE C4_PURE ConstImpl next_sibling() const noexcept { _C4RV(); return {tree_, tree_->next_sibling(id_)}; }303304template<class U=Impl>305C4_ALWAYS_INLINE C4_PURE auto first_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->first_sibling(id__)}; }306C4_ALWAYS_INLINE C4_PURE ConstImpl first_sibling() const noexcept { _C4RV(); return {tree_, tree_->first_sibling(id_)}; }307308template<class U=Impl>309C4_ALWAYS_INLINE C4_PURE auto last_sibling() noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->last_sibling(id__)}; }310C4_ALWAYS_INLINE C4_PURE ConstImpl last_sibling () const noexcept { _C4RV(); return {tree_, tree_->last_sibling(id_)}; }311312template<class U=Impl>313C4_ALWAYS_INLINE C4_PURE auto sibling(size_t pos) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->sibling(id__, pos)}; }314C4_ALWAYS_INLINE C4_PURE ConstImpl sibling(size_t pos) const noexcept { _C4RV(); return {tree_, tree_->sibling(id_, pos)}; }315316template<class U=Impl>317C4_ALWAYS_INLINE C4_PURE auto find_sibling(csubstr name) noexcept -> _C4_IF_MUTABLE(Impl) { _C4RV(); return {tree__, tree__->find_sibling(id__, name)}; }318C4_ALWAYS_INLINE C4_PURE ConstImpl find_sibling(csubstr name) const noexcept { _C4RV(); return {tree_, tree_->find_sibling(id_, name)}; }319320321/** O(num_children) */322C4_ALWAYS_INLINE C4_PURE ConstImpl operator[] (csubstr k) const noexcept323{324_C4RV();325size_t ch = tree_->find_child(id_, k);326_RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE);327return {tree_, ch};328}329/** Find child by key. O(num_children). returns a seed node if no such child is found. */330template<class U=Impl>331C4_ALWAYS_INLINE C4_PURE auto operator[] (csubstr k) noexcept -> _C4_IF_MUTABLE(Impl)332{333_C4RV();334size_t ch = tree__->find_child(id__, k);335return ch != NONE ? Impl(tree__, ch) : NodeRef(tree__, id__, k);336}337338/** O(num_children) */339C4_ALWAYS_INLINE C4_PURE ConstImpl operator[] (size_t pos) const noexcept340{341_C4RV();342size_t ch = tree_->child(id_, pos);343_RYML_CB_ASSERT(tree_->m_callbacks, ch != NONE);344return {tree_, ch};345}346347/** Find child by position. O(pos). returns a seed node if no such child is found. */348template<class U=Impl>349C4_ALWAYS_INLINE C4_PURE auto operator[] (size_t pos) noexcept -> _C4_IF_MUTABLE(Impl)350{351_C4RV();352size_t ch = tree__->child(id__, pos);353return ch != NONE ? Impl(tree__, ch) : NodeRef(tree__, id__, pos);354}355356/** @} */357358public:359360/** deserialization */361/** @{ */362363template<class T>364ConstImpl const& operator>> (T &v) const365{366_C4RV();367if( ! read((ConstImpl const&)*this, &v))368_RYML_CB_ERR(tree_->m_callbacks, "could not deserialize value");369return *((ConstImpl const*)this);370}371372/** deserialize the node's key to the given variable */373template<class T>374ConstImpl const& operator>> (Key<T> v) const375{376_C4RV();377if( ! from_chars(key(), &v.k))378_RYML_CB_ERR(tree_->m_callbacks, "could not deserialize key");379return *((ConstImpl const*)this);380}381382/** deserialize the node's key as base64 */383ConstImpl const& operator>> (Key<fmt::base64_wrapper> w) const384{385deserialize_key(w.wrapper);386return *((ConstImpl const*)this);387}388389/** deserialize the node's val as base64 */390ConstImpl const& operator>> (fmt::base64_wrapper w) const391{392deserialize_val(w);393return *((ConstImpl const*)this);394}395396/** decode the base64-encoded key and assign the397* decoded blob to the given buffer/398* @return the size of base64-decoded blob */399size_t deserialize_key(fmt::base64_wrapper v) const400{401_C4RV();402return from_chars(key(), &v);403}404/** decode the base64-encoded key and assign the405* decoded blob to the given buffer/406* @return the size of base64-decoded blob */407size_t deserialize_val(fmt::base64_wrapper v) const408{409_C4RV();410return from_chars(val(), &v);411};412413template<class T>414bool get_if(csubstr name, T *var) const415{416auto ch = find_child(name);417if(!ch.valid())418return false;419ch >> *var;420return true;421}422423template<class T>424bool get_if(csubstr name, T *var, T const& fallback) const425{426auto ch = find_child(name);427if(ch.valid())428{429ch >> *var;430return true;431}432else433{434*var = fallback;435return false;436}437}438439/** @} */440441public:442443#if defined(__clang__)444# pragma clang diagnostic push445# pragma clang diagnostic ignored "-Wnull-dereference"446#elif defined(__GNUC__)447# pragma GCC diagnostic push448# if __GNUC__ >= 6449# pragma GCC diagnostic ignored "-Wnull-dereference"450# endif451#endif452453/** @name iteration */454/** @{ */455456using iterator = detail::child_iterator<Impl>;457using const_iterator = detail::child_iterator<ConstImpl>;458using children_view = detail::children_view_<Impl>;459using const_children_view = detail::children_view_<ConstImpl>;460461template<class U=Impl>462C4_ALWAYS_INLINE C4_PURE auto begin() noexcept -> _C4_IF_MUTABLE(iterator) { _C4RV(); return iterator(tree__, tree__->first_child(id__)); }463C4_ALWAYS_INLINE C4_PURE const_iterator begin() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }464C4_ALWAYS_INLINE C4_PURE const_iterator cbegin() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }465466template<class U=Impl>467C4_ALWAYS_INLINE C4_PURE auto end() noexcept -> _C4_IF_MUTABLE(iterator) { _C4RV(); return iterator(tree__, NONE); }468C4_ALWAYS_INLINE C4_PURE const_iterator end() const noexcept { _C4RV(); return const_iterator(tree_, NONE); }469C4_ALWAYS_INLINE C4_PURE const_iterator cend() const noexcept { _C4RV(); return const_iterator(tree_, tree_->first_child(id_)); }470471/** get an iterable view over children */472template<class U=Impl>473C4_ALWAYS_INLINE C4_PURE auto children() noexcept -> _C4_IF_MUTABLE(children_view) { _C4RV(); return children_view(begin(), end()); }474/** get an iterable view over children */475C4_ALWAYS_INLINE C4_PURE const_children_view children() const noexcept { _C4RV(); return const_children_view(begin(), end()); }476/** get an iterable view over children */477C4_ALWAYS_INLINE C4_PURE const_children_view cchildren() const noexcept { _C4RV(); return const_children_view(begin(), end()); }478479/** get an iterable view over all siblings (including the calling node) */480template<class U=Impl>481C4_ALWAYS_INLINE C4_PURE auto siblings() noexcept -> _C4_IF_MUTABLE(children_view)482{483_C4RV();484NodeData const *nd = tree__->get(id__);485return (nd->m_parent != NONE) ? // does it have a parent?486children_view(iterator(tree__, tree_->get(nd->m_parent)->m_first_child), iterator(tree__, NONE))487:488children_view(end(), end());489}490/** get an iterable view over all siblings (including the calling node) */491C4_ALWAYS_INLINE C4_PURE const_children_view siblings() const noexcept492{493_C4RV();494NodeData const *nd = tree_->get(id_);495return (nd->m_parent != NONE) ? // does it have a parent?496const_children_view(const_iterator(tree_, tree_->get(nd->m_parent)->m_first_child), const_iterator(tree_, NONE))497:498const_children_view(end(), end());499}500/** get an iterable view over all siblings (including the calling node) */501C4_ALWAYS_INLINE C4_PURE const_children_view csiblings() const noexcept { return siblings(); }502503/** visit every child node calling fn(node) */504template<class Visitor>505C4_ALWAYS_INLINE bool visit(Visitor fn, size_t indentation_level=0, bool skip_root=true) const noexcept506{507return detail::_visit(*(ConstImpl const*)this, fn, indentation_level, skip_root);508}509/** visit every child node calling fn(node) */510template<class Visitor, class U=Impl>511auto visit(Visitor fn, size_t indentation_level=0, bool skip_root=true) noexcept512-> _C4_IF_MUTABLE(bool)513{514return detail::_visit(*(Impl*)this, fn, indentation_level, skip_root);515}516517/** visit every child node calling fn(node, level) */518template<class Visitor>519C4_ALWAYS_INLINE bool visit_stacked(Visitor fn, size_t indentation_level=0, bool skip_root=true) const noexcept520{521return detail::_visit_stacked(*(ConstImpl const*)this, fn, indentation_level, skip_root);522}523/** visit every child node calling fn(node, level) */524template<class Visitor, class U=Impl>525auto visit_stacked(Visitor fn, size_t indentation_level=0, bool skip_root=true) noexcept526-> _C4_IF_MUTABLE(bool)527{528return detail::_visit_stacked(*(Impl*)this, fn, indentation_level, skip_root);529}530531/** @} */532533#if defined(__clang__)534# pragma clang diagnostic pop535#elif defined(__GNUC__)536# pragma GCC diagnostic pop537#endif538539#undef _C4_IF_MUTABLE540#undef _C4RV541#undef tree_542#undef tree__543#undef id_544#undef id__545546C4_SUPPRESS_WARNING_GCC_CLANG_POP547};548549} // namespace detail550551552//-----------------------------------------------------------------------------553//-----------------------------------------------------------------------------554//-----------------------------------------------------------------------------555class RYML_EXPORT ConstNodeRef : public detail::RoNodeMethods<ConstNodeRef, ConstNodeRef>556{557public:558559using tree_type = Tree const;560561public:562563Tree const* C4_RESTRICT m_tree;564size_t m_id;565566friend NodeRef;567friend struct detail::RoNodeMethods<ConstNodeRef, ConstNodeRef>;568569public:570571/** @name construction */572/** @{ */573574ConstNodeRef() : m_tree(nullptr), m_id(NONE) {}575ConstNodeRef(Tree const &t) : m_tree(&t), m_id(t .root_id()) {}576ConstNodeRef(Tree const *t) : m_tree(t ), m_id(t->root_id()) {}577ConstNodeRef(Tree const *t, size_t id) : m_tree(t), m_id(id) {}578ConstNodeRef(std::nullptr_t) : m_tree(nullptr), m_id(NONE) {}579580ConstNodeRef(ConstNodeRef const&) = default;581ConstNodeRef(ConstNodeRef &&) = default;582583ConstNodeRef(NodeRef const&);584ConstNodeRef(NodeRef &&);585586/** @} */587588public:589590/** @name assignment */591/** @{ */592593ConstNodeRef& operator= (std::nullptr_t) { m_tree = nullptr; m_id = NONE; return *this; }594595ConstNodeRef& operator= (ConstNodeRef const&) = default;596ConstNodeRef& operator= (ConstNodeRef &&) = default;597598ConstNodeRef& operator= (NodeRef const&);599ConstNodeRef& operator= (NodeRef &&);600601602/** @} */603604public:605606/** @name state queries */607/** @{ */608609C4_ALWAYS_INLINE C4_PURE bool valid() const noexcept { return m_tree != nullptr && m_id != NONE; }610611/** @} */612613public:614615/** @name member getters */616/** @{ */617618C4_ALWAYS_INLINE C4_PURE Tree const* tree() const noexcept { return m_tree; }619C4_ALWAYS_INLINE C4_PURE size_t id() const noexcept { return m_id; }620621/** @} */622623public:624625/** @name comparisons */626/** @{ */627628C4_ALWAYS_INLINE C4_PURE bool operator== (ConstNodeRef const& that) const noexcept { RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }629C4_ALWAYS_INLINE C4_PURE bool operator!= (ConstNodeRef const& that) const noexcept { RYML_ASSERT(that.m_tree == m_tree); return ! this->operator==(that); }630631C4_ALWAYS_INLINE C4_PURE bool operator== (std::nullptr_t) const noexcept { return m_tree == nullptr || m_id == NONE; }632C4_ALWAYS_INLINE C4_PURE bool operator!= (std::nullptr_t) const noexcept { return ! this->operator== (nullptr); }633634C4_ALWAYS_INLINE C4_PURE bool operator== (csubstr val) const noexcept { RYML_ASSERT(has_val()); return m_tree->val(m_id) == val; }635C4_ALWAYS_INLINE C4_PURE bool operator!= (csubstr val) const noexcept { RYML_ASSERT(has_val()); return m_tree->val(m_id) != val; }636637/** @} */638639};640641642//-----------------------------------------------------------------------------643//-----------------------------------------------------------------------------644//-----------------------------------------------------------------------------645646/** a reference to a node in an existing yaml tree, offering a more647* convenient API than the index-based API used in the tree. */648class RYML_EXPORT NodeRef : public detail::RoNodeMethods<NodeRef, ConstNodeRef>649{650public:651652using tree_type = Tree;653using base_type = detail::RoNodeMethods<NodeRef, ConstNodeRef>;654655private:656657Tree *C4_RESTRICT m_tree;658size_t m_id;659660/** This member is used to enable lazy operator[] writing. When a child661* with a key or index is not found, m_id is set to the id of the parent662* and the asked-for key or index are stored in this member until a write663* does happen. Then it is given as key or index for creating the child.664* When a key is used, the csubstr stores it (so the csubstr's string is665* non-null and the csubstr's size is different from NONE). When an index is666* used instead, the csubstr's string is set to null, and only the csubstr's667* size is set to a value different from NONE. Otherwise, when operator[]668* does find the child then this member is empty: the string is null and669* the size is NONE. */670csubstr m_seed;671672friend ConstNodeRef;673friend struct detail::RoNodeMethods<NodeRef, ConstNodeRef>;674675// require valid: a helper macro, undefined at the end676#define _C4RV() \677RYML_ASSERT(m_tree != nullptr); \678_RYML_CB_ASSERT(m_tree->m_callbacks, m_id != NONE && !is_seed())679680public:681682/** @name construction */683/** @{ */684685NodeRef() : m_tree(nullptr), m_id(NONE), m_seed() { _clear_seed(); }686NodeRef(Tree &t) : m_tree(&t), m_id(t .root_id()), m_seed() { _clear_seed(); }687NodeRef(Tree *t) : m_tree(t ), m_id(t->root_id()), m_seed() { _clear_seed(); }688NodeRef(Tree *t, size_t id) : m_tree(t), m_id(id), m_seed() { _clear_seed(); }689NodeRef(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; }690NodeRef(Tree *t, size_t id, csubstr seed_key) : m_tree(t), m_id(id), m_seed(seed_key) {}691NodeRef(std::nullptr_t) : m_tree(nullptr), m_id(NONE), m_seed() {}692693/** @} */694695public:696697/** @name assignment */698/** @{ */699700NodeRef(NodeRef const&) = default;701NodeRef(NodeRef &&) = default;702703NodeRef& operator= (NodeRef const&) = default;704NodeRef& operator= (NodeRef &&) = default;705706/** @} */707708public:709710/** @name state queries */711/** @{ */712713inline bool valid() const { return m_tree != nullptr && m_id != NONE; }714inline bool is_seed() const { return m_seed.str != nullptr || m_seed.len != NONE; }715716inline void _clear_seed() { /*do this manually or an assert is triggered*/ m_seed.str = nullptr; m_seed.len = NONE; }717718/** @} */719720public:721722/** @name comparisons */723/** @{ */724725inline 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; }726inline bool operator!= (NodeRef const& that) const { return ! this->operator==(that); }727728inline bool operator== (ConstNodeRef const& that) const { _C4RV(); RYML_ASSERT(that.valid()); RYML_ASSERT(that.m_tree == m_tree); return m_id == that.m_id; }729inline bool operator!= (ConstNodeRef const& that) const { return ! this->operator==(that); }730731inline bool operator== (std::nullptr_t) const { return m_tree == nullptr || m_id == NONE || is_seed(); }732inline bool operator!= (std::nullptr_t) const { return m_tree != nullptr && m_id != NONE && !is_seed(); }733734inline bool operator== (csubstr val) const { _C4RV(); RYML_ASSERT(has_val()); return m_tree->val(m_id) == val; }735inline bool operator!= (csubstr val) const { _C4RV(); RYML_ASSERT(has_val()); return m_tree->val(m_id) != val; }736737//inline operator bool () const { return m_tree == nullptr || m_id == NONE || is_seed(); }738739/** @} */740741public:742743/** @name node property getters */744/** @{ */745746C4_ALWAYS_INLINE C4_PURE Tree * tree() noexcept { return m_tree; }747C4_ALWAYS_INLINE C4_PURE Tree const* tree() const noexcept { return m_tree; }748749C4_ALWAYS_INLINE C4_PURE size_t id() const noexcept { return m_id; }750751/** @} */752753public:754755/** @name node modifiers */756/** @{ */757758void change_type(NodeType t) { _C4RV(); m_tree->change_type(m_id, t); }759760void set_type(NodeType t) { _C4RV(); m_tree->_set_flags(m_id, t); }761void set_key(csubstr key) { _C4RV(); m_tree->_set_key(m_id, key); }762void set_val(csubstr val) { _C4RV(); m_tree->_set_val(m_id, val); }763void set_key_tag(csubstr key_tag) { _C4RV(); m_tree->set_key_tag(m_id, key_tag); }764void set_val_tag(csubstr val_tag) { _C4RV(); m_tree->set_val_tag(m_id, val_tag); }765void set_key_anchor(csubstr key_anchor) { _C4RV(); m_tree->set_key_anchor(m_id, key_anchor); }766void set_val_anchor(csubstr val_anchor) { _C4RV(); m_tree->set_val_anchor(m_id, val_anchor); }767void set_key_ref(csubstr key_ref) { _C4RV(); m_tree->set_key_ref(m_id, key_ref); }768void set_val_ref(csubstr val_ref) { _C4RV(); m_tree->set_val_ref(m_id, val_ref); }769770template<class T>771size_t set_key_serialized(T const& C4_RESTRICT k)772{773_C4RV();774csubstr s = m_tree->to_arena(k);775m_tree->_set_key(m_id, s);776return s.len;777}778template<class T>779size_t set_val_serialized(T const& C4_RESTRICT v)780{781_C4RV();782csubstr s = m_tree->to_arena(v);783m_tree->_set_val(m_id, s);784return s.len;785}786size_t set_val_serialized(std::nullptr_t)787{788_C4RV();789m_tree->_set_val(m_id, csubstr{});790return 0;791}792793/** encode a blob as base64, then assign the result to the node's key794* @return the size of base64-encoded blob */795size_t set_key_serialized(fmt::const_base64_wrapper w);796/** encode a blob as base64, then assign the result to the node's val797* @return the size of base64-encoded blob */798size_t set_val_serialized(fmt::const_base64_wrapper w);799800public:801802inline void clear()803{804if(is_seed())805return;806m_tree->remove_children(m_id);807m_tree->_clear(m_id);808}809810inline void clear_key()811{812if(is_seed())813return;814m_tree->_clear_key(m_id);815}816817inline void clear_val()818{819if(is_seed())820return;821m_tree->_clear_val(m_id);822}823824inline void clear_children()825{826if(is_seed())827return;828m_tree->remove_children(m_id);829}830831void create() { _apply_seed(); }832833inline void operator= (NodeType_e t)834{835_apply_seed();836m_tree->_add_flags(m_id, t);837}838839inline void operator|= (NodeType_e t)840{841_apply_seed();842m_tree->_add_flags(m_id, t);843}844845inline void operator= (NodeInit const& v)846{847_apply_seed();848_apply(v);849}850851inline void operator= (NodeScalar const& v)852{853_apply_seed();854_apply(v);855}856857inline void operator= (std::nullptr_t)858{859_apply_seed();860_apply(csubstr{});861}862863inline void operator= (csubstr v)864{865_apply_seed();866_apply(v);867}868869template<size_t N>870inline void operator= (const char (&v)[N])871{872_apply_seed();873csubstr sv;874sv.assign<N>(v);875_apply(sv);876}877878/** @} */879880public:881882/** @name serialization */883/** @{ */884885/** serialize a variable to the arena */886template<class T>887inline csubstr to_arena(T const& C4_RESTRICT s)888{889_C4RV();890return m_tree->to_arena(s);891}892893/** serialize a variable, then assign the result to the node's val */894inline NodeRef& operator<< (csubstr s)895{896// this overload is needed to prevent ambiguity (there's also897// operator<< for writing a substr to a stream)898_apply_seed();899write(this, s);900RYML_ASSERT(val() == s);901return *this;902}903904template<class T>905inline NodeRef& operator<< (T const& C4_RESTRICT v)906{907_apply_seed();908write(this, v);909return *this;910}911912/** serialize a variable, then assign the result to the node's key */913template<class T>914inline NodeRef& operator<< (Key<const T> const& C4_RESTRICT v)915{916_apply_seed();917set_key_serialized(v.k);918return *this;919}920921/** serialize a variable, then assign the result to the node's key */922template<class T>923inline NodeRef& operator<< (Key<T> const& C4_RESTRICT v)924{925_apply_seed();926set_key_serialized(v.k);927return *this;928}929930NodeRef& operator<< (Key<fmt::const_base64_wrapper> w)931{932set_key_serialized(w.wrapper);933return *this;934}935936NodeRef& operator<< (fmt::const_base64_wrapper w)937{938set_val_serialized(w);939return *this;940}941942/** @} */943944private:945946void _apply_seed()947{948if(m_seed.str) // we have a seed key: use it to create the new child949{950//RYML_ASSERT(i.key.scalar.empty() || m_key == i.key.scalar || m_key.empty());951m_id = m_tree->append_child(m_id);952m_tree->_set_key(m_id, m_seed);953m_seed.str = nullptr;954m_seed.len = NONE;955}956else if(m_seed.len != NONE) // we have a seed index: create a child at that position957{958RYML_ASSERT(m_tree->num_children(m_id) == m_seed.len);959m_id = m_tree->append_child(m_id);960m_seed.str = nullptr;961m_seed.len = NONE;962}963else964{965RYML_ASSERT(valid());966}967}968969inline void _apply(csubstr v)970{971m_tree->_set_val(m_id, v);972}973974inline void _apply(NodeScalar const& v)975{976m_tree->_set_val(m_id, v);977}978979inline void _apply(NodeInit const& i)980{981m_tree->_set(m_id, i);982}983984public:985986/** @name modification of hierarchy */987/** @{ */988989inline NodeRef insert_child(NodeRef after)990{991_C4RV();992RYML_ASSERT(after.m_tree == m_tree);993NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));994return r;995}996997inline NodeRef insert_child(NodeInit const& i, NodeRef after)998{999_C4RV();1000RYML_ASSERT(after.m_tree == m_tree);1001NodeRef r(m_tree, m_tree->insert_child(m_id, after.m_id));1002r._apply(i);1003return r;1004}10051006inline NodeRef prepend_child()1007{1008_C4RV();1009NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));1010return r;1011}10121013inline NodeRef prepend_child(NodeInit const& i)1014{1015_C4RV();1016NodeRef r(m_tree, m_tree->insert_child(m_id, NONE));1017r._apply(i);1018return r;1019}10201021inline NodeRef append_child()1022{1023_C4RV();1024NodeRef r(m_tree, m_tree->append_child(m_id));1025return r;1026}10271028inline NodeRef append_child(NodeInit const& i)1029{1030_C4RV();1031NodeRef r(m_tree, m_tree->append_child(m_id));1032r._apply(i);1033return r;1034}10351036public:10371038inline NodeRef insert_sibling(ConstNodeRef const& after)1039{1040_C4RV();1041RYML_ASSERT(after.m_tree == m_tree);1042NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));1043return r;1044}10451046inline NodeRef insert_sibling(NodeInit const& i, ConstNodeRef const& after)1047{1048_C4RV();1049RYML_ASSERT(after.m_tree == m_tree);1050NodeRef r(m_tree, m_tree->insert_sibling(m_id, after.m_id));1051r._apply(i);1052return r;1053}10541055inline NodeRef prepend_sibling()1056{1057_C4RV();1058NodeRef r(m_tree, m_tree->prepend_sibling(m_id));1059return r;1060}10611062inline NodeRef prepend_sibling(NodeInit const& i)1063{1064_C4RV();1065NodeRef r(m_tree, m_tree->prepend_sibling(m_id));1066r._apply(i);1067return r;1068}10691070inline NodeRef append_sibling()1071{1072_C4RV();1073NodeRef r(m_tree, m_tree->append_sibling(m_id));1074return r;1075}10761077inline NodeRef append_sibling(NodeInit const& i)1078{1079_C4RV();1080NodeRef r(m_tree, m_tree->append_sibling(m_id));1081r._apply(i);1082return r;1083}10841085public:10861087inline void remove_child(NodeRef & child)1088{1089_C4RV();1090RYML_ASSERT(has_child(child));1091RYML_ASSERT(child.parent().id() == id());1092m_tree->remove(child.id());1093child.clear();1094}10951096//! remove the nth child of this node1097inline void remove_child(size_t pos)1098{1099_C4RV();1100RYML_ASSERT(pos >= 0 && pos < num_children());1101size_t child = m_tree->child(m_id, pos);1102RYML_ASSERT(child != NONE);1103m_tree->remove(child);1104}11051106//! remove a child by name1107inline void remove_child(csubstr key)1108{1109_C4RV();1110size_t child = m_tree->find_child(m_id, key);1111RYML_ASSERT(child != NONE);1112m_tree->remove(child);1113}11141115public:11161117/** change the node's position within its parent, placing it after1118* @p after. To move to the first position in the parent, simply1119* pass an empty or default-constructed reference like this:1120* `n.move({})`. */1121inline void move(ConstNodeRef const& after)1122{1123_C4RV();1124m_tree->move(m_id, after.m_id);1125}11261127/** move the node to a different @p parent (which may belong to a1128* different tree), placing it after @p after. When the1129* destination parent is in a new tree, then this node's tree1130* pointer is reset to the tree of the parent node. */1131inline void move(NodeRef const& parent, ConstNodeRef const& after)1132{1133_C4RV();1134if(parent.m_tree == m_tree)1135{1136m_tree->move(m_id, parent.m_id, after.m_id);1137}1138else1139{1140parent.m_tree->move(m_tree, m_id, parent.m_id, after.m_id);1141m_tree = parent.m_tree;1142}1143}11441145/** duplicate the current node somewhere within its parent, and1146* place it after the node @p after. To place into the first1147* position of the parent, simply pass an empty or1148* default-constructed reference like this: `n.move({})`. */1149inline NodeRef duplicate(ConstNodeRef const& after) const1150{1151_C4RV();1152RYML_ASSERT(m_tree == after.m_tree || after.m_id == NONE);1153size_t dup = m_tree->duplicate(m_id, m_tree->parent(m_id), after.m_id);1154NodeRef r(m_tree, dup);1155return r;1156}11571158/** duplicate the current node somewhere into a different @p parent1159* (possibly from a different tree), and place it after the node1160* @p after. To place into the first position of the parent,1161* simply pass an empty or default-constructed reference like1162* this: `n.move({})`. */1163inline NodeRef duplicate(NodeRef const& parent, ConstNodeRef const& after) const1164{1165_C4RV();1166RYML_ASSERT(parent.m_tree == after.m_tree || after.m_id == NONE);1167if(parent.m_tree == m_tree)1168{1169size_t dup = m_tree->duplicate(m_id, parent.m_id, after.m_id);1170NodeRef r(m_tree, dup);1171return r;1172}1173else1174{1175size_t dup = parent.m_tree->duplicate(m_tree, m_id, parent.m_id, after.m_id);1176NodeRef r(parent.m_tree, dup);1177return r;1178}1179}11801181inline void duplicate_children(NodeRef const& parent, ConstNodeRef const& after) const1182{1183_C4RV();1184RYML_ASSERT(parent.m_tree == after.m_tree);1185if(parent.m_tree == m_tree)1186{1187m_tree->duplicate_children(m_id, parent.m_id, after.m_id);1188}1189else1190{1191parent.m_tree->duplicate_children(m_tree, m_id, parent.m_id, after.m_id);1192}1193}11941195/** @} */11961197#undef _C4RV1198};119912001201//-----------------------------------------------------------------------------12021203inline ConstNodeRef::ConstNodeRef(NodeRef const& that)1204: m_tree(that.m_tree)1205, m_id(!that.is_seed() ? that.id() : NONE)1206{1207}12081209inline ConstNodeRef::ConstNodeRef(NodeRef && that)1210: m_tree(that.m_tree)1211, m_id(!that.is_seed() ? that.id() : NONE)1212{1213}121412151216inline ConstNodeRef& ConstNodeRef::operator= (NodeRef const& that)1217{1218m_tree = (that.m_tree);1219m_id = (!that.is_seed() ? that.id() : NONE);1220return *this;1221}12221223inline ConstNodeRef& ConstNodeRef::operator= (NodeRef && that)1224{1225m_tree = (that.m_tree);1226m_id = (!that.is_seed() ? that.id() : NONE);1227return *this;1228}122912301231//-----------------------------------------------------------------------------12321233template<class T>1234inline void write(NodeRef *n, T const& v)1235{1236n->set_val_serialized(v);1237}12381239template<class T>1240typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type1241inline read(NodeRef const& n, T *v)1242{1243return from_chars(n.val(), v);1244}1245template<class T>1246typename std::enable_if< ! std::is_floating_point<T>::value, bool>::type1247inline read(ConstNodeRef const& n, T *v)1248{1249return from_chars(n.val(), v);1250}12511252template<class T>1253typename std::enable_if<std::is_floating_point<T>::value, bool>::type1254inline read(NodeRef const& n, T *v)1255{1256return from_chars_float(n.val(), v);1257}1258template<class T>1259typename std::enable_if<std::is_floating_point<T>::value, bool>::type1260inline read(ConstNodeRef const& n, T *v)1261{1262return from_chars_float(n.val(), v);1263}126412651266} // namespace yml1267} // namespace c41268126912701271#ifdef __clang__1272# pragma clang diagnostic pop1273#elif defined(__GNUC__)1274# pragma GCC diagnostic pop1275#elif defined(_MSC_VER)1276# pragma warning(pop)1277#endif12781279#endif /* _C4_YML_NODE_HPP_ */128012811282