implemented container integrity checkers

This commit is contained in:
Matei David
2014-08-14 12:28:24 -04:00
parent 911cb4a2b8
commit 3ebd69f44e
13 changed files with 365 additions and 0 deletions

View File

@@ -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 /// @endcond
//! avltree_algorithms is configured with a NodeTraits class, which encapsulates the //! 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; 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 /// @endcond
} //namespace intrusive } //namespace intrusive

View File

@@ -1853,6 +1853,23 @@ class bstree_impl
node_algorithms::init(to_remove); 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 /// @cond
private: private:
template<class Disposer> template<class Disposer>

View File

@@ -45,6 +45,50 @@ struct data_for_rebalance_t
NodePtr y; 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 /// @endcond
@@ -1442,6 +1486,32 @@ class bstree_algorithms
return new_root; 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: protected:
static void erase(const node_ptr & header, const node_ptr & z, data_for_rebalance &info) static void erase(const node_ptr & header, const node_ptr & z, data_for_rebalance &info)
{ {
@@ -1997,6 +2067,26 @@ class bstree_algorithms
} }
return y; 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 /// @cond
@@ -2007,6 +2097,12 @@ struct get_algo<BsTreeAlgorithms, NodeTraits>
typedef bstree_algorithms<NodeTraits> type; 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 /// @endcond
} //namespace intrusive } //namespace intrusive

View File

@@ -52,6 +52,9 @@ enum algo_types
template<algo_types AlgoType, class NodeTraits> template<algo_types AlgoType, class NodeTraits>
struct get_algo; struct get_algo;
template<algo_types AlgoType, class ValueTraits, class NodePtrCompare, class ExtraChecker>
struct get_node_checker;
template <link_mode_type link_mode> template <link_mode_type link_mode>
struct is_safe_autounlink struct is_safe_autounlink
{ {
@@ -299,6 +302,18 @@ struct node_disposer
const ValueTraits * const traits_; 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> template<class VoidPointer>
struct dummy_constptr struct dummy_constptr
{ {

View File

@@ -2659,6 +2659,7 @@ class hashtable_impl
return size_type(*bound); return size_type(*bound);
} }
/// @cond /// @cond
void check() {}
private: private:
size_traits &priv_size_traits() size_traits &priv_size_traits()
{ return static_cast<size_traits&>(static_cast<data_type&>(*this)); } { return static_cast<size_traits&>(static_cast<data_type&>(*this)); }

View File

@@ -1253,6 +1253,41 @@ class list_impl
return const_iterator(this->priv_value_traits().to_node_ptr(r), this->priv_value_traits_ptr()); 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 /// @cond
private: private:

View File

@@ -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 #endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! rbtree_algorithms provides basic algorithms to manipulate //! rbtree_algorithms provides basic algorithms to manipulate
@@ -519,6 +557,12 @@ struct get_algo<RbTreeAlgorithms, NodeTraits>
typedef rbtree_algorithms<NodeTraits> type; 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 /// @endcond
} //namespace intrusive } //namespace intrusive

View File

@@ -359,6 +359,12 @@ struct get_algo<SgTreeAlgorithms, NodeTraits>
typedef sgtree_algorithms<NodeTraits> type; 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 /// @endcond
} //namespace intrusive } //namespace intrusive

View File

@@ -1826,6 +1826,48 @@ class slist_impl
///@endcond ///@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: 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) 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)
{ {

View File

@@ -706,6 +706,12 @@ struct get_algo<SplayTreeAlgorithms, NodeTraits>
typedef splaytree_algorithms<NodeTraits> type; 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 /// @endcond
} //namespace intrusive } //namespace intrusive

View File

@@ -904,6 +904,19 @@ class treap_impl
this->tree_type::sz_traits().set_size(0); 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 #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree::count(const_reference)const //! @copydoc ::boost::intrusive::bstree::count(const_reference)const
size_type count(const_reference value) const; size_type count(const_reference value) const;

View File

@@ -28,6 +28,44 @@
namespace boost { namespace boost {
namespace intrusive { 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 //! treap_algorithms provides basic algorithms to manipulate
//! nodes forming a treap. //! nodes forming a treap.
//! //!
@@ -616,6 +654,12 @@ struct get_algo<TreapAlgorithms, NodeTraits>
typedef treap_algorithms<NodeTraits> type; 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 /// @endcond
} //namespace intrusive } //namespace intrusive

View File

@@ -73,6 +73,7 @@ void test_container( Container & c )
BOOST_TEST( it == itend ); BOOST_TEST( it == itend );
BOOST_TEST( c.size() == i ); BOOST_TEST( c.size() == i );
} }
c.check();
} }