Reworked RD-Tree to behave more consistently. The construction of the tree did not allow specifying what index to insert a child at under a parent.
Traverser orders were also broken, which is now fixed.
This commit is contained in:
@@ -44,28 +44,26 @@ public:
|
||||
static constexpr size_t root = 0;
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
enum control_ : uint8_t {
|
||||
control_continue = 0,
|
||||
control_jump_over,
|
||||
control_break
|
||||
};
|
||||
|
||||
protected:
|
||||
struct node {
|
||||
optional<TypeT> value;
|
||||
size_t parent, child, prev, next;
|
||||
size_t depth, num_children;
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr node(size_t p, size_t c, size_t v, size_t n, ArgsT&&...args)
|
||||
constexpr node(size_t p, size_t c, size_t v, size_t n, size_t d, ArgsT&&...args)
|
||||
: value(fennec::forward<ArgsT>(args)...)
|
||||
, parent(p), child(c), prev(v), next(n) {
|
||||
, parent(p), child(c), prev(v), next(n)
|
||||
, depth(d), num_children(0) {
|
||||
}
|
||||
|
||||
constexpr ~node() {
|
||||
parent = npos;
|
||||
child = npos;
|
||||
prev = npos;
|
||||
next = npos;
|
||||
parent = npos;
|
||||
child = npos;
|
||||
prev = npos;
|
||||
next = npos;
|
||||
depth = npos;
|
||||
num_children = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,7 +75,7 @@ public:
|
||||
explicit constexpr rdtree(ArgsT&&...args)
|
||||
: _table(), _freed(), _size(1) {
|
||||
_table.callocate(8);
|
||||
fennec::construct(&_table[0], npos, npos, npos, npos, fennec::forward<ArgsT>(args)...);
|
||||
fennec::construct(&_table[0], npos, npos, npos, npos, 0, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
constexpr rdtree(const rdtree& tree)
|
||||
@@ -133,34 +131,74 @@ public:
|
||||
/// \param i The id of the node to check
|
||||
/// \returns The id of the parent node
|
||||
constexpr size_t parent(size_t i) const {
|
||||
if (i >= _table.capacity()) return npos;
|
||||
return i == npos ? npos : _table[i].parent;
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i The id of the node to check
|
||||
/// \returns The id of the child node
|
||||
constexpr size_t child(size_t i) const {
|
||||
return i == npos ? npos : _table[i].child;
|
||||
constexpr size_t child(size_t i, size_t n = 0) const {
|
||||
if (i >= _table.capacity()) return npos;
|
||||
size_t c = i == npos ? npos : _table[i].child;
|
||||
if (n != 0)
|
||||
return next(c, n == npos ? npos : n - 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i The id of the node to check
|
||||
/// \returns The id of the next node
|
||||
constexpr size_t next(size_t i) const {
|
||||
return i == npos ? npos : _table[i].next;
|
||||
constexpr size_t next(size_t i, size_t n = 0) const {
|
||||
if (i >= _table.capacity()) return npos;
|
||||
if (i == npos) {
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t org = i;
|
||||
size_t nxt = _table[i].next;
|
||||
while (nxt != npos) {
|
||||
i = nxt;
|
||||
nxt = _table[i].next;
|
||||
if (n != npos) {
|
||||
if (n-- == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i == org && n != npos ? npos : i;
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i The id of the node to check
|
||||
/// \returns The id of the previous node
|
||||
constexpr size_t prev(size_t i) const {
|
||||
return i == npos ? npos : _table[i].prev;
|
||||
constexpr size_t prev(size_t i, size_t n = 0) const {
|
||||
if (i >= _table.capacity()) return npos;
|
||||
if (i == npos) {
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t org = i;
|
||||
size_t prv = _table[i].prev;
|
||||
while (prv != npos) {
|
||||
i = prv;
|
||||
prv = _table[i].prev;
|
||||
if (n != npos) {
|
||||
if (n-- == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i == org && n != npos ? npos : i;
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i the node to start at
|
||||
/// \returns the left-most child of node `i`
|
||||
constexpr size_t left_most(size_t i) const {
|
||||
if (i >= _table.capacity()) return npos;
|
||||
size_t n = i;
|
||||
if ((n = child(n)) == npos) {
|
||||
return i;
|
||||
@@ -177,6 +215,7 @@ public:
|
||||
/// \param i the node to start at
|
||||
/// \returns the right-most child of node `i`
|
||||
constexpr size_t right_most(size_t i) const {
|
||||
if (i >= _table.capacity()) return npos;
|
||||
if ((i = child(i)) == npos) {
|
||||
return npos;
|
||||
}
|
||||
@@ -192,18 +231,54 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i The id of the node to check
|
||||
/// \returns The depth of the node
|
||||
constexpr size_t depth(size_t i) const {
|
||||
if (i >= _table.capacity()) return npos;
|
||||
return i == npos ? npos : _table[i].depth;
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i The id of the node to check
|
||||
/// \returns The number of children the node has
|
||||
constexpr size_t num_children(size_t i) const {
|
||||
if (i >= _table.capacity()) return 0;
|
||||
return i == npos ? 0 : _table[i].num_children;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The next node id were `insert` or `emplace` to be called
|
||||
constexpr size_t next_free() const {
|
||||
size_t i = _size;
|
||||
if (not _freed.empty()) {
|
||||
i = _freed.front();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i The id of the node to access
|
||||
/// \returns A reference to the value of the node wrapped in an optional
|
||||
constexpr optional<value_t>& operator[](size_t i) {
|
||||
return _table[i].value;
|
||||
constexpr value_t* operator[](size_t i) {
|
||||
auto& it = _table[i].value;
|
||||
if (it) {
|
||||
return &*_table[i].value;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \param i The id of the node to access
|
||||
/// \returns A const-qualified reference to the value of the node wrapped in an optional
|
||||
constexpr const optional<value_t>& operator[](size_t i) const {
|
||||
return _table[i].value;
|
||||
constexpr const value_t* operator[](size_t i) const {
|
||||
const auto& it = _table[i].value;
|
||||
if (it) {
|
||||
return &*_table[i].value;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,21 +287,49 @@ public:
|
||||
///
|
||||
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||
/// \param next the next node, as an index relative to the parent
|
||||
/// \param val the value to insert
|
||||
/// \returns the index of the created node
|
||||
constexpr size_t insert(size_t parent, const value_t& val) {
|
||||
return this->_insert(parent, val);
|
||||
constexpr size_t insert(size_t parent, size_t next, const value_t& val) {
|
||||
return this->_insert(parent, next, val);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||
/// \param next the next node, as an index relative to the parent
|
||||
/// \param val the value to insert
|
||||
/// \returns the index of the created node
|
||||
constexpr size_t insert(size_t parent, value_t&& val) {
|
||||
return this->_insert(parent, fennec::forward<value_t>(val));
|
||||
constexpr size_t insert(size_t parent, size_t next, value_t&& val) {
|
||||
return this->_insert(parent, next, fennec::forward<value_t>(val));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||
/// \param next the next node, as an index relative to the parent
|
||||
/// \param args the args to construct the value to insert
|
||||
/// \returns the index of the created node
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t emplace(size_t parent, size_t next, ArgsT&&...args) {
|
||||
return this->_insert(parent, next, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Swap two nodes
|
||||
/// \param i0 The id of the first node
|
||||
/// \param i1 The id of the second node
|
||||
constexpr void swap(size_t i0, size_t i1) {
|
||||
size_t p0 = parent(i0);
|
||||
size_t p1 = parent(i1);
|
||||
|
||||
fennec::swap(_table[i0], _table[i1]);
|
||||
|
||||
if (child(p0) == i0) _table[p0].child = i1;
|
||||
if (child(p1) == i1) _table[p1].child = i0;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// \brief Erase a node in the tree and all of it's children
|
||||
/// \param i the index of the node
|
||||
@@ -332,7 +435,7 @@ public:
|
||||
OrderT order;
|
||||
i = order(*this, i);
|
||||
while (i != npos) {
|
||||
uint8_t mode = visit(*_table[i].value);
|
||||
uint8_t mode = visit(*_table[i].value, i);
|
||||
if (mode == traversal_control_break) {
|
||||
break;
|
||||
}
|
||||
@@ -353,8 +456,8 @@ protected:
|
||||
size_t _next_free() {
|
||||
size_t next = _size;
|
||||
if (not _freed.empty()) {
|
||||
next = _freed.back();
|
||||
_freed.pop_back();
|
||||
next = _freed.front();
|
||||
_freed.pop_front();
|
||||
}
|
||||
if (_size >= capacity()) {
|
||||
_expand();
|
||||
@@ -364,9 +467,9 @@ protected:
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t _insert(size_t p, ArgsT&&...args) {
|
||||
constexpr size_t _insert(size_t p, size_t n, ArgsT&&...args) {
|
||||
if (_size == 0) {
|
||||
fennec::construct(&_table[root], npos, npos, npos, npos, fennec::forward<ArgsT>(args)...);
|
||||
fennec::construct(&_table[root], npos, npos, npos, npos, 0, fennec::forward<ArgsT>(args)...);
|
||||
_size = 1;
|
||||
return root;
|
||||
}
|
||||
@@ -377,17 +480,34 @@ protected:
|
||||
return root;
|
||||
}
|
||||
|
||||
size_t i = _next_free();
|
||||
size_t n = child(p);
|
||||
_table[p].child = i;
|
||||
if (n != npos) _table[n].prev = i;
|
||||
fennec::construct(&_table[i], p, npos, npos, n, fennec::forward<ArgsT>(args)...);
|
||||
return i;
|
||||
size_t idx = _next_free();
|
||||
size_t nxt = child(p, n);
|
||||
size_t prv = n == npos ? npos : prev(n);
|
||||
|
||||
++_table[p].num_children;
|
||||
if ((nxt == child(p) && n != npos) || nxt == npos) {
|
||||
_table[p].child = idx;
|
||||
}
|
||||
|
||||
if (n == npos) {
|
||||
if (nxt != npos) {
|
||||
_table[nxt].next = idx;
|
||||
}
|
||||
fennec::construct(&_table[idx], p, npos, nxt, npos, depth(p) + 1, fennec::forward<ArgsT>(args)...);
|
||||
} else {
|
||||
if (nxt != npos) {
|
||||
_table[nxt].prev = idx;
|
||||
}
|
||||
if (prv != npos) {
|
||||
_table[prv].next = idx;
|
||||
}
|
||||
fennec::construct(&_table[idx], p, npos, prv, nxt, depth(p) + 1, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
constexpr void _erase(size_t i) {
|
||||
list<size_t> queue;
|
||||
size_t j = 0;
|
||||
queue.push_back(child(i));
|
||||
while (queue.empty() == false) {
|
||||
size_t n = queue.front(); queue.pop_front();
|
||||
@@ -397,7 +517,6 @@ protected:
|
||||
fennec::destruct(&_table[n]);
|
||||
_freed.push_back(n);
|
||||
--_size;
|
||||
++j;
|
||||
}
|
||||
|
||||
fennec::destruct(&_table[i]);
|
||||
|
||||
Reference in New Issue
Block a user