duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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_ */