node: swap_children and swap_children_at functions

This commit is contained in:
BlackMATov
2020-04-22 10:25:02 +07:00
parent db99cd71d3
commit 3f8bb69955
6 changed files with 137 additions and 22 deletions

View File

@@ -108,6 +108,17 @@ namespace e2d
bool remove_child(
const node_iptr& child) noexcept;
node_iptr remove_child_at(
std::size_t index) noexcept;
bool swap_children(
const node_iptr& child_l,
const node_iptr& child_r) noexcept;
bool swap_children_at(
std::size_t child_l,
std::size_t child_r) noexcept;
bool send_backward() noexcept;
bool bring_to_back() noexcept;
@@ -131,8 +142,6 @@ namespace e2d
std::pair<std::size_t, bool> child_index(
const const_node_iptr& child) const noexcept;
node_iptr remove_child_at(std::size_t index) noexcept;
protected:
node() = default;
node(gobject owner);

View File

@@ -273,6 +273,8 @@ namespace e2d
static iterator iterator_to(T& v) noexcept;
static const_iterator iterator_to(const T& v) noexcept;
static void iterator_swap(iterator l, iterator r) noexcept;
private:
using node_t = intrusive_list_hook<Tag>;
using node_ptr = typename node_t::node_ptr;
@@ -496,4 +498,10 @@ namespace e2d
E2D_ASSERT(node.is_linked());
return const_iterator(&node);
}
template < typename T, typename Tag >
void intrusive_list<T,Tag>::iterator_swap(iterator l, iterator r) noexcept {
E2D_ASSERT(l.node()->is_linked() && r.node()->is_linked());
intrusive_list_hook<Tag>::swap_nodes(l.node(), r.node());
}
}

View File

@@ -124,6 +124,23 @@ function node.add_sibling_after(self, sibling) end
---@return boolean
function node.remove_child(self, child) end
---@param self node
---@param index integer
---@return node
function node.remove_child_at(self, index) end
---@param self node
---@param child_l node
---@param child_r node
---@return boolean
function node.swap_children(self, child_l, child_r) end
---@param self node
---@param child_l integer
---@param child_r integer
---@return boolean
function node.swap_children_at(self, child_l, child_r) end
---@param self node
---@return boolean
function node.send_backward(self) end
@@ -150,10 +167,5 @@ function node.child_at(self, index) end
---@return integer, boolean
function node.child_index(self, child) end
---@param self node
---@param index integer
---@return node
function node.remove_child_at(self, index) end
---@type node
_G.node = _G.node or node

View File

@@ -115,6 +115,22 @@ namespace e2d::bindings::high
return n.remove_child(c);
},
"remove_child_at", [](node& n, i32 index) -> node_iptr {
return index >= 0
? n.remove_child_at(math::numeric_cast<std::size_t>(index))
: node_iptr();
},
"swap_children", [](node& n, const node_iptr& cl, const node_iptr& cr) -> bool {
return n.swap_children(cl, cr);
},
"swap_children_at", [](node& n, i32 cl, i32 cr) -> bool {
return cl >= 0 && cr >= 0
? n.swap_children_at(math::numeric_cast<std::size_t>(cl), math::numeric_cast<std::size_t>(cr))
: false;
},
"send_backward", [](node& n) -> bool {
return n.send_backward();
},
@@ -151,12 +167,6 @@ namespace e2d::bindings::high
"child_index", [](node& n, const node_iptr& c) -> std::pair<std::size_t, bool> {
return n.child_index(c);
},
"remove_child_at", [](node& n, i32 index) -> node_iptr {
return index >= 0
? n.remove_child_at(math::numeric_cast<std::size_t>(index))
: node_iptr();
}
);
}

View File

@@ -214,7 +214,7 @@ namespace e2d
bool node::add_child_to_back(
const node_iptr& child) noexcept
{
if ( !child ) {
if ( !child || child == this ) {
return false;
}
@@ -233,7 +233,7 @@ namespace e2d
bool node::add_child_to_front(
const node_iptr& child) noexcept
{
if ( !child ) {
if ( !child || child == this ) {
return false;
}
@@ -319,6 +319,41 @@ namespace e2d
return true;
}
node_iptr node::remove_child_at(std::size_t index) noexcept {
node_iptr child = child_at(index);
return remove_child(child)
? child
: node_iptr();
}
bool node::swap_children(
const node_iptr& child_l,
const node_iptr& child_r) noexcept
{
if ( !child_l || !child_r ) {
return false;
}
if ( child_l->parent_ != this || child_r->parent_ != this ) {
return false;
}
node_children::iterator_swap(
node_children::iterator_to(*child_l),
node_children::iterator_to(*child_r));
return true;
}
bool node::swap_children_at(
std::size_t child_l,
std::size_t child_r) noexcept
{
return swap_children(
child_at(child_l),
child_at(child_r));
}
bool node::send_backward() noexcept {
node_iptr prev = prev_sibling();
return prev
@@ -444,13 +479,6 @@ namespace e2d
return {math::numeric_cast<std::size_t>(distance), true};
}
node_iptr node::remove_child_at(std::size_t index) noexcept {
node_iptr child = child_at(index);
return remove_child(child)
? child
: node_iptr();
}
}
namespace e2d

View File

@@ -317,6 +317,33 @@ TEST_CASE("node") {
REQUIRE_FALSE(n->bring_to_back());
}
}
SECTION("swap_children") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
auto p2 = node::create();
auto n4 = node::create(p2);
auto n5 = node::create();
REQUIRE_FALSE(p->swap_children(n1, node_iptr()));
REQUIRE_FALSE(p->swap_children(node_iptr(), n1));
REQUIRE_FALSE(p->swap_children(n1, p2));
REQUIRE_FALSE(p->swap_children(n1, n4));
REQUIRE_FALSE(p->swap_children(n1, n5));
REQUIRE(p->swap_children(n1, n1)); // n1 n2 n3
REQUIRE(p->swap_children(n1, n2)); // n2 n1 n3
REQUIRE(p->swap_children(n2, n3)); // n3 n1 n2
REQUIRE(p->swap_children(n2, n1)); // n3 n2 n1
REQUIRE(p->child_at(0u) == n3);
REQUIRE(p->child_at(1u) == n2);
REQUIRE(p->child_at(2u) == n1);
}
SECTION("send_forward/bring_to_front") {
{
auto p = node::create();
@@ -513,6 +540,25 @@ TEST_CASE("node") {
REQUIRE_FALSE(n3->has_parent());
REQUIRE(p->child_count() == 0u);
}
SECTION("swap_children_at") {
auto p = node::create();
auto n1 = node::create(p);
auto n2 = node::create(p);
auto n3 = node::create(p);
REQUIRE_FALSE(p->swap_children_at(0u, 3u));
REQUIRE_FALSE(p->swap_children_at(3u, 0u));
REQUIRE(p->swap_children_at(0, 0)); // n1 n2 n3
REQUIRE(p->swap_children_at(0, 1)); // n2 n1 n3
REQUIRE(p->swap_children_at(0, 2)); // n3 n1 n2
REQUIRE(p->swap_children_at(2, 1)); // n3 n2 n1
REQUIRE(p->child_at(0u) == n3);
REQUIRE(p->child_at(1u) == n2);
REQUIRE(p->child_at(2u) == n1);
}
SECTION("add_child_to_back/add_child_to_front") {
auto p = node::create();
auto n1 = node::create();
@@ -523,6 +569,7 @@ TEST_CASE("node") {
REQUIRE(p->add_child_to_back(n1));
REQUIRE(p->add_child_to_back(n2));
REQUIRE(p->add_child_to_back(n3)); // n3 n2 n1
REQUIRE_FALSE(p->add_child_to_back(p));
REQUIRE_FALSE(p->add_child_to_back(nullptr));
REQUIRE(n1->prev_sibling() == n2);
@@ -558,6 +605,7 @@ TEST_CASE("node") {
REQUIRE(p->add_child_to_front(n1));
REQUIRE(p->add_child_to_front(n2));
REQUIRE(p->add_child_to_front(n3)); // n1 n2 n3
REQUIRE_FALSE(p->add_child_to_front(p));
REQUIRE_FALSE(p->add_child_to_front(nullptr));
REQUIRE(n1->next_sibling() == n2);