mirror of
https://github.com/boostorg/intrusive.git
synced 2025-08-01 21:44:38 +02:00
implemented container integrity checkers
This commit is contained in:
@@ -49,6 +49,45 @@ struct avltree_node_cloner
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct avltree_node_checker
|
||||
: public bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> base_checker_t;
|
||||
typedef ValueTraits value_traits;
|
||||
typedef typename value_traits::node_traits node_traits;
|
||||
typedef typename node_traits::node_ptr node_ptr;
|
||||
|
||||
struct return_type
|
||||
: public base_checker_t::return_type
|
||||
{
|
||||
return_type() : height(0) {}
|
||||
int height;
|
||||
};
|
||||
|
||||
avltree_node_checker(const NodePtrCompare& comp, ExtraChecker extra_checker)
|
||||
: base_checker_t(comp, extra_checker)
|
||||
{}
|
||||
|
||||
void operator () (const node_ptr& p,
|
||||
const return_type& check_return_left, const return_type& check_return_right,
|
||||
return_type& check_return)
|
||||
{
|
||||
int height_diff = check_return_right.height - check_return_left.height;
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(
|
||||
(height_diff == -1 && node_traits::get_balance(p) == node_traits::negative()) ||
|
||||
(height_diff == 0 && node_traits::get_balance(p) == node_traits::zero()) ||
|
||||
(height_diff == 1 && node_traits::get_balance(p) == node_traits::positive())
|
||||
);
|
||||
check_return.height = 1 + std::max(check_return_left.height, check_return_right.height);
|
||||
base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// @endcond
|
||||
|
||||
//! avltree_algorithms is configured with a NodeTraits class, which encapsulates the
|
||||
@@ -628,6 +667,12 @@ struct get_algo<AvlTreeAlgorithms, NodeTraits>
|
||||
typedef avltree_algorithms<NodeTraits> type;
|
||||
};
|
||||
|
||||
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct get_node_checker<AvlTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef detail::avltree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} //namespace intrusive
|
||||
|
@@ -1853,6 +1853,23 @@ class bstree_impl
|
||||
node_algorithms::init(to_remove);
|
||||
}
|
||||
|
||||
template <class ExtraChecker>
|
||||
void check(ExtraChecker extra_checker)
|
||||
{
|
||||
typedef detail::key_nodeptr_comp<value_compare, value_traits> nodeptr_comp_t;
|
||||
nodeptr_comp_t nodeptr_comp(this->comp(), &this->get_value_traits());
|
||||
typedef typename get_node_checker<AlgoType, ValueTraits, nodeptr_comp_t, ExtraChecker>::type node_checker_t;
|
||||
typename node_checker_t::return_type checker_return;
|
||||
node_algorithms::check(this->header_ptr(), node_checker_t(nodeptr_comp, extra_checker), checker_return);
|
||||
if (constant_time_size)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(this->sz_traits().get_size() == checker_return.node_count);
|
||||
}
|
||||
|
||||
void check()
|
||||
{
|
||||
check(detail::empty_node_checker<ValueTraits>());
|
||||
}
|
||||
|
||||
/// @cond
|
||||
private:
|
||||
template<class Disposer>
|
||||
|
@@ -45,6 +45,50 @@ struct data_for_rebalance_t
|
||||
NodePtr y;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct bstree_node_checker
|
||||
: public ExtraChecker
|
||||
{
|
||||
typedef ExtraChecker base_checker_t;
|
||||
typedef ValueTraits value_traits;
|
||||
typedef typename value_traits::node_traits node_traits;
|
||||
typedef typename node_traits::node_ptr node_ptr;
|
||||
|
||||
struct return_type
|
||||
: public base_checker_t::return_type
|
||||
{
|
||||
return_type() : min_key_node_ptr(node_ptr()), max_key_node_ptr(node_ptr()), node_count(0) {}
|
||||
|
||||
node_ptr min_key_node_ptr;
|
||||
node_ptr max_key_node_ptr;
|
||||
size_t node_count;
|
||||
};
|
||||
|
||||
bstree_node_checker(const NodePtrCompare& comp, ExtraChecker extra_checker)
|
||||
: base_checker_t(extra_checker), comp_(comp)
|
||||
{}
|
||||
|
||||
void operator () (const node_ptr& p,
|
||||
const return_type& check_return_left, const return_type& check_return_right,
|
||||
return_type& check_return)
|
||||
{
|
||||
if (check_return_left.max_key_node_ptr)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(!comp_(p, check_return_left.max_key_node_ptr));
|
||||
if (check_return_right.min_key_node_ptr)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(!comp_(check_return_right.min_key_node_ptr, p));
|
||||
check_return.min_key_node_ptr = node_traits::get_left(p)? check_return_left.min_key_node_ptr : p;
|
||||
check_return.max_key_node_ptr = node_traits::get_right(p)? check_return_right.max_key_node_ptr : p;
|
||||
check_return.node_count = check_return_left.node_count + check_return_right.node_count + 1;
|
||||
base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
|
||||
}
|
||||
|
||||
const NodePtrCompare comp_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// @endcond
|
||||
|
||||
|
||||
@@ -1442,6 +1486,32 @@ class bstree_algorithms
|
||||
return new_root;
|
||||
}
|
||||
|
||||
template<class Checker>
|
||||
static void check(const node_ptr & header, Checker checker, typename Checker::return_type& checker_return)
|
||||
{
|
||||
node_ptr root_node_ptr = NodeTraits::get_parent(header);
|
||||
if (!root_node_ptr)
|
||||
{
|
||||
// check left&right header pointers
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(header) == header);
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(header) == header);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check parent pointer of root node
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(root_node_ptr) == header);
|
||||
// check subtree from root
|
||||
check_subtree(root_node_ptr, checker, checker_return);
|
||||
// check left&right header pointers
|
||||
node_ptr p = root_node_ptr;
|
||||
while (NodeTraits::get_left(p)) { p = NodeTraits::get_left(p); }
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(header) == p);
|
||||
p = root_node_ptr;
|
||||
while (NodeTraits::get_right(p)) { p = NodeTraits::get_right(p); }
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(header) == p);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
static void erase(const node_ptr & header, const node_ptr & z, data_for_rebalance &info)
|
||||
{
|
||||
@@ -1997,6 +2067,26 @@ class bstree_algorithms
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
template<class Checker>
|
||||
static void check_subtree(const node_ptr& node, Checker checker, typename Checker::return_type& check_return)
|
||||
{
|
||||
node_ptr left = NodeTraits::get_left(node);
|
||||
node_ptr right = NodeTraits::get_right(node);
|
||||
typename Checker::return_type check_return_left;
|
||||
typename Checker::return_type check_return_right;
|
||||
if (left)
|
||||
{
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(left) == node);
|
||||
check_subtree(left, checker, check_return_left);
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(right) == node);
|
||||
check_subtree(right, checker, check_return_right);
|
||||
}
|
||||
checker(node, check_return_left, check_return_right, check_return);
|
||||
}
|
||||
};
|
||||
|
||||
/// @cond
|
||||
@@ -2007,6 +2097,12 @@ struct get_algo<BsTreeAlgorithms, NodeTraits>
|
||||
typedef bstree_algorithms<NodeTraits> type;
|
||||
};
|
||||
|
||||
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct get_node_checker<BsTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} //namespace intrusive
|
||||
|
@@ -52,6 +52,9 @@ enum algo_types
|
||||
template<algo_types AlgoType, class NodeTraits>
|
||||
struct get_algo;
|
||||
|
||||
template<algo_types AlgoType, class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct get_node_checker;
|
||||
|
||||
template <link_mode_type link_mode>
|
||||
struct is_safe_autounlink
|
||||
{
|
||||
@@ -299,6 +302,18 @@ struct node_disposer
|
||||
const ValueTraits * const traits_;
|
||||
};
|
||||
|
||||
template<class ValueTraits>
|
||||
struct empty_node_checker
|
||||
{
|
||||
typedef ValueTraits value_traits;
|
||||
typedef typename value_traits::node_traits node_traits;
|
||||
typedef typename node_traits::node_ptr node_ptr;
|
||||
|
||||
struct return_type {};
|
||||
|
||||
void operator () (const node_ptr&, const return_type&, const return_type&, return_type&) {}
|
||||
};
|
||||
|
||||
template<class VoidPointer>
|
||||
struct dummy_constptr
|
||||
{
|
||||
|
@@ -2659,6 +2659,7 @@ class hashtable_impl
|
||||
return size_type(*bound);
|
||||
}
|
||||
/// @cond
|
||||
void check() {}
|
||||
private:
|
||||
size_traits &priv_size_traits()
|
||||
{ return static_cast<size_traits&>(static_cast<data_type&>(*this)); }
|
||||
|
@@ -1253,6 +1253,41 @@ class list_impl
|
||||
return const_iterator(this->priv_value_traits().to_node_ptr(r), this->priv_value_traits_ptr());
|
||||
}
|
||||
|
||||
//! <b>Effects</b>: Asserts the integrity of the container.
|
||||
//!
|
||||
//! <b>Complexity</b>: Linear time.
|
||||
//!
|
||||
//! <b>Note</b>: The method has no effect when asserts are turned off (e.g., with NDEBUG).
|
||||
void check() const
|
||||
{
|
||||
const_node_ptr header_ptr = get_root_node();
|
||||
// header's next and prev are never null
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(node_traits::get_next(header_ptr));
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(node_traits::get_previous(header_ptr));
|
||||
// header's next and prev either both point to header (empty list) or neither does
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT((node_traits::get_next(header_ptr) == header_ptr)
|
||||
== (node_traits::get_previous(header_ptr) == header_ptr));
|
||||
if (node_traits::get_next(header_ptr) == header_ptr)
|
||||
{
|
||||
if (constant_time_size)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(this->priv_size_traits().get_size() == 0);
|
||||
return;
|
||||
}
|
||||
size_t node_count = 0;
|
||||
const_node_ptr p = header_ptr;
|
||||
while (true)
|
||||
{
|
||||
const_node_ptr next_p = node_traits::get_next(p);
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(next_p);
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(node_traits::get_previous(next_p) == p);
|
||||
p = next_p;
|
||||
if (p == header_ptr) break;
|
||||
++node_count;
|
||||
}
|
||||
if (constant_time_size)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(this->priv_size_traits().get_size() == node_count);
|
||||
}
|
||||
|
||||
/// @cond
|
||||
|
||||
private:
|
||||
|
@@ -57,6 +57,44 @@ struct rbtree_node_cloner
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct rbtree_node_checker
|
||||
: public bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> base_checker_t;
|
||||
typedef ValueTraits value_traits;
|
||||
typedef typename value_traits::node_traits node_traits;
|
||||
typedef typename node_traits::node_ptr node_ptr;
|
||||
|
||||
struct return_type
|
||||
: public base_checker_t::return_type
|
||||
{
|
||||
return_type() : is_red(false) {}
|
||||
bool is_red;
|
||||
};
|
||||
|
||||
rbtree_node_checker(const NodePtrCompare& comp, ExtraChecker extra_checker)
|
||||
: base_checker_t(comp, extra_checker)
|
||||
{}
|
||||
|
||||
void operator () (const node_ptr& p,
|
||||
const return_type& check_return_left, const return_type& check_return_right,
|
||||
return_type& check_return)
|
||||
{
|
||||
check_return.is_red = (node_traits::get_color(p) == node_traits::red());
|
||||
if (check_return.is_red)
|
||||
{
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(!check_return_left.is_red);
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(!check_return_right.is_red);
|
||||
}
|
||||
base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
||||
|
||||
//! rbtree_algorithms provides basic algorithms to manipulate
|
||||
@@ -519,6 +557,12 @@ struct get_algo<RbTreeAlgorithms, NodeTraits>
|
||||
typedef rbtree_algorithms<NodeTraits> type;
|
||||
};
|
||||
|
||||
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct get_node_checker<RbTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef detail::rbtree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} //namespace intrusive
|
||||
|
@@ -359,6 +359,12 @@ struct get_algo<SgTreeAlgorithms, NodeTraits>
|
||||
typedef sgtree_algorithms<NodeTraits> type;
|
||||
};
|
||||
|
||||
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct get_node_checker<SgTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} //namespace intrusive
|
||||
|
@@ -1826,6 +1826,48 @@ class slist_impl
|
||||
|
||||
///@endcond
|
||||
|
||||
//! <b>Effects</b>: Asserts the integrity of the container.
|
||||
//!
|
||||
//! <b>Complexity</b>: Linear time.
|
||||
//!
|
||||
//! <b>Note</b>: The method has no effect when asserts are turned off (e.g., with NDEBUG).
|
||||
void check() const
|
||||
{
|
||||
const_node_ptr header_ptr = get_root_node();
|
||||
// header's next is never null
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(node_traits::get_next(header_ptr));
|
||||
if (node_traits::get_next(header_ptr) == header_ptr)
|
||||
{
|
||||
if (constant_time_size)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(this->priv_size_traits().get_size() == 0);
|
||||
return;
|
||||
}
|
||||
size_t node_count = 0;
|
||||
const_node_ptr p = header_ptr;
|
||||
while (true)
|
||||
{
|
||||
const_node_ptr next_p = node_traits::get_next(p);
|
||||
if (!linear)
|
||||
{
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(next_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(next_p != header_ptr);
|
||||
}
|
||||
if ((!linear && next_p == header_ptr) || (linear && !next_p))
|
||||
{
|
||||
if (cache_last)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(get_last_node() == p);
|
||||
break;
|
||||
}
|
||||
p = next_p;
|
||||
++node_count;
|
||||
}
|
||||
if (constant_time_size)
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(this->priv_size_traits().get_size() == node_count);
|
||||
}
|
||||
|
||||
private:
|
||||
void priv_splice_after(const node_ptr & prev_pos_n, slist_impl &x, const node_ptr & before_f_n, const node_ptr & before_l_n)
|
||||
{
|
||||
|
@@ -706,6 +706,12 @@ struct get_algo<SplayTreeAlgorithms, NodeTraits>
|
||||
typedef splaytree_algorithms<NodeTraits> type;
|
||||
};
|
||||
|
||||
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct get_node_checker<SplayTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} //namespace intrusive
|
||||
|
@@ -904,6 +904,19 @@ class treap_impl
|
||||
this->tree_type::sz_traits().set_size(0);
|
||||
}
|
||||
|
||||
template <class ExtraChecker>
|
||||
void check(ExtraChecker extra_checker)
|
||||
{
|
||||
typedef detail::key_nodeptr_comp<priority_compare, value_traits> nodeptr_prio_comp_t;
|
||||
nodeptr_prio_comp_t nodeptr_prio_comp(priv_pcomp(), &this->get_value_traits());
|
||||
tree_type::check(detail::treap_node_extra_checker<ValueTraits, nodeptr_prio_comp_t, ExtraChecker>(nodeptr_prio_comp, extra_checker));
|
||||
}
|
||||
|
||||
void check()
|
||||
{
|
||||
check(detail::empty_node_checker<ValueTraits>());
|
||||
}
|
||||
|
||||
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
||||
//! @copydoc ::boost::intrusive::bstree::count(const_reference)const
|
||||
size_type count(const_reference value) const;
|
||||
|
@@ -28,6 +28,44 @@
|
||||
namespace boost {
|
||||
namespace intrusive {
|
||||
|
||||
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class ValueTraits, class NodePtrPrioCompare, class ExtraChecker>
|
||||
struct treap_node_extra_checker
|
||||
: public ExtraChecker
|
||||
{
|
||||
typedef ExtraChecker base_checker_t;
|
||||
typedef ValueTraits value_traits;
|
||||
typedef typename value_traits::node_traits node_traits;
|
||||
typedef typename node_traits::node_ptr node_ptr;
|
||||
|
||||
typedef typename base_checker_t::return_type return_type;
|
||||
|
||||
treap_node_extra_checker(const NodePtrPrioCompare& prio_comp, ExtraChecker extra_checker)
|
||||
: base_checker_t(extra_checker), prio_comp_(prio_comp)
|
||||
{}
|
||||
|
||||
void operator () (const node_ptr& p,
|
||||
const return_type& check_return_left, const return_type& check_return_right,
|
||||
return_type& check_return)
|
||||
{
|
||||
if (node_traits::get_left(p))
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(!prio_comp_(node_traits::get_left(p), p));
|
||||
if (node_traits::get_right(p))
|
||||
BOOST_INTRUSIVE_INVARIANT_ASSERT(!prio_comp_(node_traits::get_right(p), p));
|
||||
base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
|
||||
}
|
||||
|
||||
const NodePtrPrioCompare prio_comp_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
||||
|
||||
//! treap_algorithms provides basic algorithms to manipulate
|
||||
//! nodes forming a treap.
|
||||
//!
|
||||
@@ -616,6 +654,12 @@ struct get_algo<TreapAlgorithms, NodeTraits>
|
||||
typedef treap_algorithms<NodeTraits> type;
|
||||
};
|
||||
|
||||
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
||||
struct get_node_checker<TreapAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
|
||||
{
|
||||
typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} //namespace intrusive
|
||||
|
@@ -73,6 +73,7 @@ void test_container( Container & c )
|
||||
BOOST_TEST( it == itend );
|
||||
BOOST_TEST( c.size() == i );
|
||||
}
|
||||
c.check();
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user