Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions src/c4/yml/tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,101 @@ void Tree::merge_with(Tree const *src, size_t src_node, size_t dst_node)
}


//-----------------------------------------------------------------------------

bool Tree::has_all(Tree const* reftree, size_t refnode, size_t subject_node) const
{
_RYML_CB_ASSERT(m_callbacks, reftree != nullptr);
if (subject_node == NONE)
subject_node = root_id();
if (refnode == NONE)
refnode = reftree->root_id();

return _has_all_recursive(reftree, refnode, subject_node);
}

bool Tree::_has_all_recursive(Tree const* reftree, size_t refnode, size_t subject_node) const
{
if (is_val(subject_node))
{
if( ! reftree->is_val(refnode))
return false;
// skip value comparison
return true;
}
else if (is_keyval(subject_node))
{
if( ! reftree->is_keyval(refnode))
return false;
if (key(subject_node) == reftree->key(refnode))
return true;
return false;
}
else if (is_map(subject_node))
{
if( ! reftree->is_map(refnode))
return false;

if (num_children(subject_node) > reftree->num_children(refnode))
return false;

for (size_t sch = first_child(subject_node); sch != NONE; sch = next_sibling(sch))
{
size_t rch = reftree->find_child(refnode, key(sch));
if (rch == NONE)
return false;
if ( ! _has_all_recursive(reftree, rch, sch))
return false;
}
return true;
}
else if (is_seq(subject_node))
{
if( ! reftree->is_seq(refnode))
return false;

if (num_children(subject_node) > reftree->num_children(refnode))
return false;

size_t rch = reftree->first_child(refnode);
for (size_t sch = first_child(subject_node); sch != NONE; sch = next_sibling(sch))
{
if ( ! _has_all_recursive(reftree, rch, sch))
return false;
rch = reftree->next_sibling(rch);
}
return true;
}
else if (is_stream(subject_node))
{
if( ! reftree->is_stream(refnode))
return false;

if (num_children(subject_node) > reftree->num_children(refnode))
return false;

size_t rch = reftree->first_child(refnode);
for (size_t sch = first_child(subject_node); sch != NONE;sch = next_sibling(sch))
{
if ( ! _has_all_recursive(reftree, rch, sch))
return false;
rch = reftree->next_sibling(rch);
}
return true;
}
else if(type(subject_node) == NOTYPE)
{
if(reftree->type(refnode) != NOTYPE)
return false;
return true;
}
else
{
C4_NEVER_REACH();
}
}


//-----------------------------------------------------------------------------

namespace detail {
Expand Down
14 changes: 14 additions & 0 deletions src/c4/yml/tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,20 @@ class RYML_EXPORT Tree

void merge_with(Tree const* src, size_t src_node=NONE, size_t dst_root=NONE);

public:

/** non-recursive predicates: */

/** return true if subject_node has all the keys or indices in refnode from a reftree
* @note does not check values, only keys (for maps) or indices (for seqs) */
bool has_all(Tree const* reftree, size_t refnode = NONE, size_t subject_node = NONE ) const;

private:

/** and helper functions to drive the recursive descent: */

bool _has_all_recursive(Tree const* reftree, size_t refnode, size_t subject_node) const;

/** @} */

public:
Expand Down