Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
biojppm committed May 19, 2024
1 parent e99c8e8 commit 392d00f
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 14 deletions.
3 changes: 3 additions & 0 deletions src/c4/yml/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,9 @@ struct RoNodeMethods
/** O(num_siblings). Forward to Tree::sibling_pos(). */
C4_ALWAYS_INLINE id_type sibling_pos(ConstImpl const& n) const RYML_NOEXCEPT { _C4RR(); _RYML_CB_ASSERT(tree_->callbacks(), n.readable()); return tree_->child_pos(tree_->parent(id_), n.m_id); }

C4_ALWAYS_INLINE id_type depth_asc() const RYML_NOEXCEPT { _C4RR(); return tree_->depth_asc(id_); } /** O(log(num_nodes)). Forward to Tree::depth_asc(). Node must be readable. */
C4_ALWAYS_INLINE id_type depth_desc() const RYML_NOEXCEPT { _C4RR(); return tree_->depth_desc(id_); } /** O(num_nodes). Forward to Tree::depth_desc(). Node must be readable. */

/** @} */

public:
Expand Down
31 changes: 31 additions & 0 deletions src/c4/yml/tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,37 @@ id_type Tree::find_child(id_type node, csubstr const& name) const
# pragma GCC diagnostic pop
#endif

namespace {
id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0)
{
maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
{
const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
maxdepth = d > maxdepth ? d : maxdepth;
}
return maxdepth;
}
}

id_type Tree::depth_desc(id_type node) const
{
_RYML_CB_ASSERT(m_callbacks, node != NONE);
return depth_desc_(*this, node);
}

id_type Tree::depth_asc(id_type node) const
{
_RYML_CB_ASSERT(m_callbacks, node != NONE);
id_type depth = 0;
while(!is_root(node))
{
++depth;
node = parent(node);
}
return depth;
}


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

Expand Down
3 changes: 3 additions & 0 deletions src/c4/yml/tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,9 @@ class RYML_EXPORT Tree

id_type doc(id_type i) const { id_type rid = root_id(); _RYML_CB_ASSERT(m_callbacks, is_stream(rid)); return child(rid, i); } //!< gets the @p i document node index. requires that the root node is a stream.

id_type depth_asc(id_type node) const; /**< O(log(num_tree_nodes)) get the ascending depth of the node: number of levels between root and node */
id_type depth_desc(id_type node) const; /**< O(num_tree_nodes) get the descending depth of the node: number of levels between node and deepest child */

/** @} */

public:
Expand Down
91 changes: 77 additions & 14 deletions test/test_emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,55 @@ std::string emitrs_append(csubstr first_part, Emit &&fn)
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

TEST(as_yaml, basic)
{
Tree et;
{
as_yaml j(et);
EXPECT_EQ(j.tree, &et);
}
Tree t = parse_in_arena("[foo, bar]");
{
as_yaml j(t);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, t.root_id());
EXPECT_EQ(j.options, EmitOptions{});
}
{
EmitOptions opts = EmitOptions{}.max_depth(10);
as_yaml j(t, opts);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, t.root_id());
EXPECT_EQ(j.options, opts);
}
{
as_yaml j(t, 2u);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 2u);
EXPECT_EQ(j.options, EmitOptions{});
}
{
EmitOptions opts = EmitOptions{}.max_depth(10);
as_yaml j(t, 2u, opts);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 2u);
EXPECT_EQ(j.options, opts);
}
{
as_yaml j(t[0]);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 1u);
EXPECT_EQ(j.options, EmitOptions{});
}
{
EmitOptions opts = EmitOptions{}.max_depth(10);
as_yaml j(t[0], opts);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 1u);
EXPECT_EQ(j.options, opts);
}
}

TEST(as_json, basic)
{
Tree et;
Expand All @@ -79,16 +128,40 @@ TEST(as_json, basic)
as_json j(t);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, t.root_id());
EXPECT_EQ(j.options, EmitOptions{});
}
{
EmitOptions opts = EmitOptions{}.max_depth(10);
as_json j(t, opts);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, t.root_id());
EXPECT_EQ(j.options, opts);
}
{
as_json j(t, 2u);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 2u);
EXPECT_EQ(j.options, EmitOptions{});
}
{
EmitOptions opts = EmitOptions{}.max_depth(10);
as_json j(t, 2u, opts);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 2u);
EXPECT_EQ(j.options, opts);
}
{
as_json j(t[0]);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 1u);
EXPECT_EQ(j.options, EmitOptions{});
}
{
EmitOptions opts = EmitOptions{}.max_depth(10);
as_json j(t[0], opts);
EXPECT_EQ(j.tree, &t);
EXPECT_EQ(j.node, 1u);
EXPECT_EQ(j.options, opts);
}
}

Expand All @@ -98,21 +171,11 @@ TEST(as_json, basic)
//-----------------------------------------------------------------------------


id_type getdepth(Tree const& t, id_type id, id_type currdepth=0, id_type maxdepth=0)
{
maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
{
const id_type d = getdepth(t, child, currdepth+1, maxdepth);
maxdepth = d > maxdepth ? d : maxdepth;
}
return maxdepth;
}

void test_emits(Tree const& t, id_type id, std::string const& expected, std::string const& expected_json)
{
EXPECT_EQ(emit2buf([&](substr buf){ return emit_yaml(t, id, buf); }), expected);
EXPECT_EQ(emit2buf([&](substr buf){ return emit_yaml(t, id, EmitOptions{}, buf); }), expected);
EXPECT_EQ(emit2buf([&](substr buf){ return emit_yaml(t, id, EmitOptions{}, buf); }), expected);
EXPECT_EQ(emit2buf([&](substr buf){ return emit_json(t, id, buf); }), expected_json);
EXPECT_EQ(emit2buf([&](substr buf){ return emit_json(t, id, EmitOptions{}, buf); }), expected_json);
EXPECT_EQ(emit2file([&](FILE *f){ return emit_yaml(t, id, f); }), expected);
Expand All @@ -139,7 +202,7 @@ void test_emits(Tree const& t, id_type id, std::string const& expected, std::str
// error on max depth
if(id == NONE)
return;
id_type max_depth = getdepth(t, id);
id_type max_depth = t.depth_desc(id);
if(max_depth > 1)
{
EmitOptions opts = EmitOptions{}.max_depth(0);
Expand Down Expand Up @@ -182,7 +245,7 @@ void test_emits(Tree const& t, std::string const& expected, std::string const& e
EXPECT_EQ(emitrs_append(to_csubstr(append_prefix), [&](std::string *s) { emitrs_json(t, s, /*append*/true); } ), append_prefix + expected_json);
EXPECT_EQ(emitrs_append(to_csubstr(append_prefix), [&](std::string *s) { emitrs_json(t, EmitOptions{}, s, /*append*/true); } ), append_prefix + expected_json);
// error on max depth
id_type max_depth = t.empty() ? 0 : getdepth(t, t.root_id());
id_type max_depth = t.empty() ? 0 : t.depth_desc(t.root_id());
if(max_depth > 1)
{
EmitOptions opts = EmitOptions{}.max_depth(0);
Expand Down Expand Up @@ -222,7 +285,7 @@ void test_emits(ConstNodeRef n, std::string const& expected, std::string const&
EXPECT_EQ(emitrs_append(to_csubstr(append_prefix), [&](std::string *s) { emitrs_json(n, s, /*append*/true); } ), append_prefix + expected_json);
EXPECT_EQ(emitrs_append(to_csubstr(append_prefix), [&](std::string *s) { emitrs_json(n, EmitOptions{}, s, /*append*/true); } ), append_prefix + expected_json);
// error on max depth
id_type max_depth = getdepth(*n.tree(), n.id());
id_type max_depth = n.depth_desc();
if(max_depth > 1)
{
EmitOptions opts = EmitOptions{}.max_depth(0);
Expand Down
78 changes: 78 additions & 0 deletions test/test_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3395,6 +3395,84 @@ seq: &seq [*valref, bar]
verify_assertion(t, [&](Tree const&){ return t.find_sibling(NONE, "foo"); });
}

TEST(Tree, depth_asc_desc)
{
Tree t = parse_in_arena(R"(---
map: {foo: *keyvalref, notag: none}
seq: &seq [*valref, bar]
...)");
const size_t stream_id = t.root_id();
const size_t doc_id = t.first_child(stream_id);
const size_t map_id = t.first_child(doc_id);
const size_t seq_id = t.last_child(doc_id);
const size_t map_child_id = t.first_child(map_id);
const size_t seq_child_id = t.first_child(seq_id);
ConstNodeRef stream = t.cref(stream_id);
ConstNodeRef doc = t.cref(doc_id);
ConstNodeRef map = t.cref(map_id);
ConstNodeRef seq = t.cref(seq_id);
ConstNodeRef map_child = t.cref(map_child_id);
ConstNodeRef seq_child = t.cref(seq_child_id);
NodeRef mstream = t.ref(stream_id);
NodeRef mdoc = t.ref(doc_id);
NodeRef mmap = t.ref(map_id);
NodeRef mseq = t.ref(seq_id);
NodeRef mmap_child = t.ref(map_child_id);
NodeRef mseq_child = t.ref(seq_child_id);
//
EXPECT_EQ(t.depth_asc(stream_id), id_type(0));
EXPECT_EQ(t.depth_asc(doc_id), id_type(1));
EXPECT_EQ(t.depth_asc(map_id), id_type(2));
EXPECT_EQ(t.depth_asc(seq_id), id_type(2));
EXPECT_EQ(t.depth_asc(map_child_id), id_type(3));
EXPECT_EQ(t.depth_asc(seq_child_id), id_type(3));
//
EXPECT_EQ(stream.depth_asc(), id_type(0));
EXPECT_EQ(doc.depth_asc(), id_type(1));
EXPECT_EQ(map.depth_asc(), id_type(2));
EXPECT_EQ(seq.depth_asc(), id_type(2));
EXPECT_EQ(map_child.depth_asc(), id_type(3));
EXPECT_EQ(seq_child.depth_asc(), id_type(3));
//
EXPECT_EQ(mstream.depth_asc(), id_type(0));
EXPECT_EQ(mdoc.depth_asc(), id_type(1));
EXPECT_EQ(mmap.depth_asc(), id_type(2));
EXPECT_EQ(mseq.depth_asc(), id_type(2));
EXPECT_EQ(mmap_child.depth_asc(), id_type(3));
EXPECT_EQ(mseq_child.depth_asc(), id_type(3));
//
verify_assertion(t, [&](Tree const&){ return t.docref(0)["none"].depth_asc(); });
verify_assertion(t, [&](Tree const&){ return t.docref(2).depth_asc(); });
verify_assertion(t, [&](Tree const&){ return t.depth_asc(t.capacity()); });
verify_assertion(t, [&](Tree const&){ return t.depth_asc(NONE); });
//
EXPECT_EQ(t.depth_desc(stream_id), id_type(3));
EXPECT_EQ(t.depth_desc(doc_id), id_type(2));
EXPECT_EQ(t.depth_desc(map_id), id_type(1));
EXPECT_EQ(t.depth_desc(seq_id), id_type(1));
EXPECT_EQ(t.depth_desc(map_child_id), id_type(0));
EXPECT_EQ(t.depth_desc(seq_child_id), id_type(0));
//
EXPECT_EQ(stream.depth_desc(), id_type(3));
EXPECT_EQ(doc.depth_desc(), id_type(2));
EXPECT_EQ(map.depth_desc(), id_type(1));
EXPECT_EQ(seq.depth_desc(), id_type(1));
EXPECT_EQ(map_child.depth_desc(), id_type(0));
EXPECT_EQ(seq_child.depth_desc(), id_type(0));
//
EXPECT_EQ(mstream.depth_desc(), id_type(3));
EXPECT_EQ(mdoc.depth_desc(), id_type(2));
EXPECT_EQ(mmap.depth_desc(), id_type(1));
EXPECT_EQ(mseq.depth_desc(), id_type(1));
EXPECT_EQ(mmap_child.depth_desc(), id_type(0));
EXPECT_EQ(mseq_child.depth_desc(), id_type(0));
//
verify_assertion(t, [&](Tree const&){ return t.docref(0)["none"].depth_desc(); });
verify_assertion(t, [&](Tree const&){ return t.docref(2).depth_desc(); });
verify_assertion(t, [&](Tree const&){ return t.depth_desc(t.capacity()); });
verify_assertion(t, [&](Tree const&){ return t.depth_desc(NONE); });
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
Expand Down

0 comments on commit 392d00f

Please sign in to comment.