Added support for configurable tree-based associative containers. In addition to RB trees, AVL, Scapegoat and Splay trees are experimentally supported.

This commit is contained in:
Ion Gaztañaga
2014-01-03 13:26:57 +01:00
parent 2489010881
commit 01486761a6
21 changed files with 1193 additions and 155 deletions
+88 -19
View File
@@ -171,14 +171,15 @@ class map_propagate_test_wrapper
< T, T, std::less<T>
, typename boost::container::allocator_traits<A>::template
portable_rebind_alloc< std::pair<const T, T> >::type
, red_black_tree>
//tree_assoc_defaults
>
{
BOOST_COPYABLE_AND_MOVABLE(map_propagate_test_wrapper)
typedef boost::container::map
< T, T, std::less<T>
, typename boost::container::allocator_traits<A>::template
portable_rebind_alloc< std::pair<const T, T> >::type
, red_black_tree> Base;
> Base;
public:
map_propagate_test_wrapper()
: Base()
@@ -203,7 +204,7 @@ class map_propagate_test_wrapper
};
template<class VoidAllocator>
template<class VoidAllocator, boost::container::tree_type_enum tree_type_value>
struct GetAllocatorMap
{
template<class ValueType>
@@ -214,6 +215,9 @@ struct GetAllocatorMap
, std::less<ValueType>
, typename allocator_traits<VoidAllocator>
::template portable_rebind_alloc< std::pair<const ValueType, ValueType> >::type
, typename boost::container::tree_assoc_options
< boost::container::tree_type<tree_type_value>
>::type
> map_type;
typedef multimap< ValueType
@@ -221,22 +225,25 @@ struct GetAllocatorMap
, std::less<ValueType>
, typename allocator_traits<VoidAllocator>
::template portable_rebind_alloc< std::pair<const ValueType, ValueType> >::type
, typename boost::container::tree_assoc_options
< boost::container::tree_type<tree_type_value>
>::type
> multimap_type;
};
};
template<class VoidAllocator>
template<class VoidAllocator, boost::container::tree_type_enum tree_type_value>
int test_map_variants()
{
typedef typename GetAllocatorMap<VoidAllocator>::template apply<int>::map_type MyMap;
typedef typename GetAllocatorMap<VoidAllocator>::template apply<test::movable_int>::map_type MyMoveMap;
typedef typename GetAllocatorMap<VoidAllocator>::template apply<test::movable_and_copyable_int>::map_type MyCopyMoveMap;
typedef typename GetAllocatorMap<VoidAllocator>::template apply<test::copyable_int>::map_type MyCopyMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<int>::map_type MyMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<test::movable_int>::map_type MyMoveMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<test::movable_and_copyable_int>::map_type MyCopyMoveMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<test::copyable_int>::map_type MyCopyMap;
typedef typename GetAllocatorMap<VoidAllocator>::template apply<int>::multimap_type MyMultiMap;
typedef typename GetAllocatorMap<VoidAllocator>::template apply<test::movable_int>::multimap_type MyMoveMultiMap;
typedef typename GetAllocatorMap<VoidAllocator>::template apply<test::movable_and_copyable_int>::multimap_type MyCopyMoveMultiMap;
typedef typename GetAllocatorMap<VoidAllocator>::template apply<test::copyable_int>::multimap_type MyCopyMultiMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<int>::multimap_type MyMultiMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<test::movable_int>::multimap_type MyMoveMultiMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<test::movable_and_copyable_int>::multimap_type MyCopyMoveMultiMap;
typedef typename GetAllocatorMap<VoidAllocator, tree_type_value>::template apply<test::copyable_int>::multimap_type MyCopyMultiMap;
typedef std::map<int, int> MyStdMap;
typedef std::multimap<int, int> MyStdMultiMap;
@@ -298,34 +305,96 @@ int main ()
test_move<multimap<recursive_multimap, recursive_multimap> >();
}
if(test_map_variants< std::allocator<void> >()){
////////////////////////////////////
// Testing allocator implementations
////////////////////////////////////
// std:allocator
if(test_map_variants< std::allocator<void>, red_black_tree >()){
std::cerr << "test_map_variants< std::allocator<void> > failed" << std::endl;
return 1;
}
if(test_map_variants< allocator<void> >()){
// boost::container::allocator
if(test_map_variants< allocator<void>, red_black_tree >()){
std::cerr << "test_map_variants< allocator<void> > failed" << std::endl;
return 1;
}
if(test_map_variants< node_allocator<void> >()){
// boost::container::node_allocator
if(test_map_variants< node_allocator<void>, red_black_tree >()){
std::cerr << "test_map_variants< node_allocator<void> > failed" << std::endl;
return 1;
}
if(test_map_variants< adaptive_pool<void> >()){
// boost::container::adaptive_pool
if(test_map_variants< adaptive_pool<void>, red_black_tree >()){
std::cerr << "test_map_variants< adaptive_pool<void> > failed" << std::endl;
return 1;
}
////////////////////////////////////
// Tree implementations
////////////////////////////////////
// AVL
if(test_map_variants< std::allocator<void>, avl_tree >()){
std::cerr << "test_map_variants< std::allocator<void>, avl_tree > failed" << std::endl;
return 1;
}
// SCAPEGOAT TREE
if(test_map_variants< std::allocator<void>, scapegoat_tree >()){
std::cerr << "test_map_variants< std::allocator<void>, scapegoat_tree > failed" << std::endl;
return 1;
}
// SPLAY TREE
if(test_map_variants< std::allocator<void>, splay_tree >()){
std::cerr << "test_map_variants< std::allocator<void>, splay_tree > failed" << std::endl;
return 1;
}
////////////////////////////////////
// Emplace testing
////////////////////////////////////
const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR);
if(!boost::container::test::test_emplace<map<test::EmplaceInt, test::EmplaceInt>, MapOptions>())
return 1;
if(!boost::container::test::test_emplace<multimap<test::EmplaceInt, test::EmplaceInt>, MapOptions>())
return 1;
////////////////////////////////////
// Allocator propagation testing
////////////////////////////////////
if(!boost::container::test::test_propagate_allocator<map_propagate_test_wrapper>())
return 1;
////////////////////////////////////
// Test optimize_size option
////////////////////////////////////
//
// map
//
typedef map< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<false>, tree_type<red_black_tree> >::type > rbmap_size_optimized_no;
typedef map< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<true>, tree_type<red_black_tree> >::type > rbmap_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(rbmap_size_optimized_yes) < sizeof(rbmap_size_optimized_no));
typedef map< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<false>, tree_type<avl_tree> >::type > avlmap_size_optimized_no;
typedef map< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<true>, tree_type<avl_tree> >::type > avlmap_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(avlmap_size_optimized_yes) < sizeof(avlmap_size_optimized_no));
//
// multimap
//
typedef multimap< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<false>, tree_type<red_black_tree> >::type > rbmmap_size_optimized_no;
typedef multimap< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<true>, tree_type<red_black_tree> >::type > rbmmap_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(rbmmap_size_optimized_yes) < sizeof(rbmmap_size_optimized_no));
typedef multimap< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<false>, tree_type<avl_tree> >::type > avlmmap_size_optimized_no;
typedef multimap< int*, int*, std::less<int*>, std::allocator< std::pair<int const*, int*> >
, tree_assoc_options< optimize_size<true>, tree_type<avl_tree> >::type > avlmmap_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(avlmmap_size_optimized_yes) < sizeof(avlmmap_size_optimized_no));
return 0;
}
+30
View File
@@ -23,6 +23,13 @@
#include <boost/move/utility.hpp>
#include <string>
#include <boost/intrusive/detail/has_member_function_callable_with.hpp>
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME rebalance
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace test {
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 0, <boost/intrusive/detail/has_member_function_callable_with.hpp>))
#include BOOST_PP_ITERATE()
template<class T1, class T2, class T3, class T4>
bool operator ==(std::pair<T1, T2> &p1, std::pair<T1, T2> &p2)
{
@@ -33,6 +40,16 @@ namespace boost{
namespace container {
namespace test{
template<class C>
void map_test_rebalanceable(C &, boost::container::container_detail::false_type)
{}
template<class C>
void map_test_rebalanceable(C &c, boost::container::container_detail::true_type)
{
c.rebalance();
}
template<class MyBoostMap
,class MyStdMap
,class MyBoostMultiMap
@@ -501,6 +518,19 @@ int map_test()
return 1;
if(!CheckEqualPairContainers(boostmultimap, stdmultimap))
return 1;
map_test_rebalanceable(*boostmap
, container_detail::bool_<has_member_function_callable_with_rebalance<MyBoostMap>::value>());
if(!CheckEqualContainers(boostmap, stdmap)){
std::cout << "Error in boostmap->rebalance()" << std::endl;
return 1;
}
map_test_rebalanceable(*boostmultimap
, container_detail::bool_<has_member_function_callable_with_rebalance<MyBoostMultiMap>::value>());
if(!CheckEqualContainers(boostmultimap, stdmultimap)){
std::cout << "Error in boostmultimap->rebalance()" << std::endl;
return 1;
}
}
//Compare count with std containers
+88 -19
View File
@@ -145,10 +145,12 @@ void test_move()
template<class T, class A>
class set_propagate_test_wrapper
: public boost::container::set<T, std::less<T>, A, red_black_tree>
: public boost::container::set<T, std::less<T>, A
//tree_assoc_defaults
>
{
BOOST_COPYABLE_AND_MOVABLE(set_propagate_test_wrapper)
typedef boost::container::set<T, std::less<T>, A, red_black_tree> Base;
typedef boost::container::set<T, std::less<T>, A > Base;
public:
set_propagate_test_wrapper()
: Base()
@@ -172,7 +174,7 @@ class set_propagate_test_wrapper
{ this->Base::swap(x); }
};
template<class VoidAllocator>
template<class VoidAllocator, boost::container::tree_type_enum tree_type_value>
struct GetAllocatorSet
{
template<class ValueType>
@@ -182,28 +184,34 @@ struct GetAllocatorSet
, std::less<ValueType>
, typename allocator_traits<VoidAllocator>
::template portable_rebind_alloc<ValueType>::type
, typename boost::container::tree_assoc_options
< boost::container::tree_type<tree_type_value>
>::type
> set_type;
typedef multiset < ValueType
, std::less<ValueType>
, typename allocator_traits<VoidAllocator>
::template portable_rebind_alloc<ValueType>::type
, typename boost::container::tree_assoc_options
< boost::container::tree_type<tree_type_value>
>::type
> multiset_type;
};
};
template<class VoidAllocator>
template<class VoidAllocator, boost::container::tree_type_enum tree_type_value>
int test_set_variants()
{
typedef typename GetAllocatorSet<VoidAllocator>::template apply<int>::set_type MySet;
typedef typename GetAllocatorSet<VoidAllocator>::template apply<test::movable_int>::set_type MyMoveSet;
typedef typename GetAllocatorSet<VoidAllocator>::template apply<test::movable_and_copyable_int>::set_type MyCopyMoveSet;
typedef typename GetAllocatorSet<VoidAllocator>::template apply<test::copyable_int>::set_type MyCopySet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<int>::set_type MySet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<test::movable_int>::set_type MyMoveSet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<test::movable_and_copyable_int>::set_type MyCopyMoveSet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<test::copyable_int>::set_type MyCopySet;
typedef typename GetAllocatorSet<VoidAllocator>::template apply<int>::multiset_type MyMultiSet;
typedef typename GetAllocatorSet<VoidAllocator>::template apply<test::movable_int>::multiset_type MyMoveMultiSet;
typedef typename GetAllocatorSet<VoidAllocator>::template apply<test::movable_and_copyable_int>::multiset_type MyCopyMoveMultiSet;
typedef typename GetAllocatorSet<VoidAllocator>::template apply<test::copyable_int>::multiset_type MyCopyMultiSet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<int>::multiset_type MyMultiSet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<test::movable_int>::multiset_type MyMoveMultiSet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<test::movable_and_copyable_int>::multiset_type MyCopyMoveMultiSet;
typedef typename GetAllocatorSet<VoidAllocator, tree_type_value>::template apply<test::copyable_int>::multiset_type MyCopyMultiSet;
typedef std::set<int> MyStdSet;
typedef std::multiset<int> MyStdMultiSet;
@@ -266,34 +274,95 @@ int main ()
test_move<multiset<recursive_multiset> >();
}
if(test_set_variants< std::allocator<void> >()){
////////////////////////////////////
// Testing allocator implementations
////////////////////////////////////
// std:allocator
if(test_set_variants< std::allocator<void>, red_black_tree >()){
std::cerr << "test_set_variants< std::allocator<void> > failed" << std::endl;
return 1;
}
if(test_set_variants< allocator<void> >()){
// boost::container::allocator
if(test_set_variants< allocator<void>, red_black_tree>()){
std::cerr << "test_set_variants< allocator<void> > failed" << std::endl;
return 1;
}
if(test_set_variants< node_allocator<void> >()){
// boost::container::node_allocator
if(test_set_variants< node_allocator<void>, red_black_tree>()){
std::cerr << "test_set_variants< node_allocator<void> > failed" << std::endl;
return 1;
}
if(test_set_variants< adaptive_pool<void> >()){
// boost::container::adaptive_pool
if(test_set_variants< adaptive_pool<void>, red_black_tree>()){
std::cerr << "test_set_variants< adaptive_pool<void> > failed" << std::endl;
return 1;
}
////////////////////////////////////
// Tree implementations
////////////////////////////////////
// AVL
if(test_set_variants< std::allocator<void>, avl_tree >()){
std::cerr << "test_set_variants< std::allocator<void>, avl_tree > failed" << std::endl;
return 1;
}
// SCAPEGOAT TREE
if(test_set_variants< std::allocator<void>, scapegoat_tree >()){
std::cerr << "test_set_variants< std::allocator<void>, scapegoat_tree > failed" << std::endl;
return 1;
}
// SPLAY TREE
if(test_set_variants< std::allocator<void>, splay_tree >()){
std::cerr << "test_set_variants< std::allocator<void>, splay_tree > failed" << std::endl;
return 1;
}
////////////////////////////////////
// Emplace testing
////////////////////////////////////
const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC);
if(!boost::container::test::test_emplace<set<test::EmplaceInt>, SetOptions>())
return 1;
if(!boost::container::test::test_emplace<multiset<test::EmplaceInt>, SetOptions>())
return 1;
////////////////////////////////////
// Allocator propagation testing
////////////////////////////////////
if(!boost::container::test::test_propagate_allocator<set_propagate_test_wrapper>())
return 1;
////////////////////////////////////
// Test optimize_size option
////////////////////////////////////
//
// set
//
typedef set< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<false>, tree_type<red_black_tree> >::type > rbset_size_optimized_no;
typedef set< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<true>, tree_type<red_black_tree> >::type > rbset_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(rbset_size_optimized_yes) < sizeof(rbset_size_optimized_no));
typedef set< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<false>, tree_type<avl_tree> >::type > avlset_size_optimized_no;
typedef set< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<true>, tree_type<avl_tree> >::type > avlset_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(avlset_size_optimized_yes) < sizeof(avlset_size_optimized_no));
//
// multiset
//
typedef multiset< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<false>, tree_type<red_black_tree> >::type > rbmset_size_optimized_no;
typedef multiset< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<true>, tree_type<red_black_tree> >::type > rbmset_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(rbmset_size_optimized_yes) < sizeof(rbmset_size_optimized_no));
typedef multiset< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<false>, tree_type<avl_tree> >::type > avlmset_size_optimized_no;
typedef multiset< int*, std::less<int*>, std::allocator<int*>
, tree_assoc_options< optimize_size<true>, tree_type<avl_tree> >::type > avlmset_size_optimized_yes;
BOOST_STATIC_ASSERT(sizeof(avlmset_size_optimized_yes) < sizeof(avlmset_size_optimized_no));
return 0;
}
+30
View File
@@ -21,10 +21,28 @@
#include <boost/move/iterator.hpp>
#include <string>
#include <boost/intrusive/detail/has_member_function_callable_with.hpp>
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME rebalance
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace test {
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 0, <boost/intrusive/detail/has_member_function_callable_with.hpp>))
#include BOOST_PP_ITERATE()
namespace boost{
namespace container {
namespace test{
template<class C>
void set_test_rebalanceable(C &, boost::container::container_detail::false_type)
{}
template<class C>
void set_test_rebalanceable(C &c, boost::container::container_detail::true_type)
{
c.rebalance();
}
template<class MyBoostSet
,class MyStdSet
,class MyBoostMultiSet
@@ -459,6 +477,18 @@ int set_test ()
std::cout << "Error in boostmultiset->insert(boostmultiset->lower_bound(move_me2), boost::move(move_me2))" << std::endl;
return 1;
}
set_test_rebalanceable(*boostset
, container_detail::bool_<has_member_function_callable_with_rebalance<MyBoostSet>::value>());
if(!CheckEqualContainers(boostset, stdset)){
std::cout << "Error in boostset->rebalance()" << std::endl;
return 1;
}
set_test_rebalanceable(*boostmultiset
, container_detail::bool_<has_member_function_callable_with_rebalance<MyBoostMultiSet>::value>());
if(!CheckEqualContainers(boostmultiset, stdmultiset)){
std::cout << "Error in boostmultiset->rebalance()" << std::endl;
return 1;
}
}
}