feat(util/rb_tree): add check_invariant for red black trees
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
1ab12eb105
commit
54d5088c98
1 changed files with 55 additions and 4 deletions
|
@ -9,6 +9,7 @@ Author: Leonardo de Moura
|
||||||
#include "util/rc.h"
|
#include "util/rc.h"
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
#include "util/buffer.h"
|
#include "util/buffer.h"
|
||||||
|
#include "util/optional.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
/**
|
/**
|
||||||
|
@ -245,13 +246,58 @@ class rb_tree : public CMP {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool check_invariant(node_cell const * n, unsigned curr_black, optional<unsigned> & num_black) const {
|
||||||
|
// We check:
|
||||||
|
// 1) the nodes are really ordered, that is, left->value < n->value < right->value
|
||||||
|
// 2) there are no two consecutive red nodes
|
||||||
|
// 3) every path has the same number of black nodes
|
||||||
|
if (n) {
|
||||||
|
if (!n->m_red)
|
||||||
|
curr_black++;
|
||||||
|
if (n->m_left) {
|
||||||
|
lean_assert(!n->m_red || !n->m_left.is_red());
|
||||||
|
check_invariant(n->m_left.m_ptr, curr_black, num_black);
|
||||||
|
lean_assert(cmp(n->m_left->m_value, n->m_value) < 0);
|
||||||
|
}
|
||||||
|
if (n->m_right) {
|
||||||
|
lean_assert(!n->m_red || !n->m_right.is_red());
|
||||||
|
check_invariant(n->m_right.m_ptr, curr_black, num_black);
|
||||||
|
lean_assert(cmp(n->m_value, n->m_right->m_value) < 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// end of a path
|
||||||
|
if (num_black) {
|
||||||
|
lean_assert(curr_black == *num_black);
|
||||||
|
} else {
|
||||||
|
num_black = curr_black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
node m_root;
|
node m_root;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void insert(T const & v) { m_root = set_black(insert(m_root.steal(), v)); }
|
void insert(T const & v) {
|
||||||
void erase_min(T const & v) { m_root = set_black(erase_min(m_root.steal())); }
|
m_root = set_black(insert(m_root.steal(), v));
|
||||||
void erase_core(T const & v) { lean_assert(contains(v)); m_root = set_black(erase(m_root.steal(), v)); }
|
lean_assert(check_invariant());
|
||||||
void erase(T const & v) { if (contains(v)) erase_core(v); }
|
}
|
||||||
|
|
||||||
|
void erase_min(T const & v) {
|
||||||
|
m_root = set_black(erase_min(m_root.steal()));
|
||||||
|
lean_assert(check_invariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase_core(T const & v) {
|
||||||
|
lean_assert(contains(v));
|
||||||
|
m_root = set_black(erase(m_root.steal(), v));
|
||||||
|
lean_assert(check_invariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(T const & v) {
|
||||||
|
if (contains(v))
|
||||||
|
erase_core(v);
|
||||||
|
}
|
||||||
|
|
||||||
T const * find(T const & v) const {
|
T const * find(T const & v) const {
|
||||||
node_cell const * h = m_root.m_ptr;
|
node_cell const * h = m_root.m_ptr;
|
||||||
|
@ -293,6 +339,11 @@ public:
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool check_invariant() const {
|
||||||
|
optional<unsigned> num_black;
|
||||||
|
return check_invariant(m_root.m_ptr, 0, num_black);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Copy the contents of this tree to the given buffer.
|
\brief Copy the contents of this tree to the given buffer.
|
||||||
The elements will be stored in increasing order.
|
The elements will be stored in increasing order.
|
||||||
|
|
Loading…
Reference in a new issue