diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 2b410ed..b80d17e 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -596,7 +596,7 @@ Apart from that, [*Boost.Intrusive] offers additional features: be configured to use any type of pointer. This configuration information is also transmitted to the containers, so all the internal pointers used by intrusive containers configured with these hooks will be smart pointers. As an example, - [*Boost.Interprocess] defines an mart pointer compatible with shared memory, + [*Boost.Interprocess] defines a smart pointer compatible with shared memory, called `offset_ptr`. [*Boost.Intrusive] can be configured to use this smart pointer to allow shared memory intrusive containers. @@ -656,6 +656,15 @@ want to redefine intrusive safe-mode assertions without modifying the global used in hooks' destructors to check that the hook is in a default state. If any of these macros is not redefined, the assertion will default to `BOOST_ASSERT`. +If `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT` or `BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT` +is defined and the programmer needs to include a file to configure that assertion, it can define +`BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE` or `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT_INCLUDE` +with the name of the file to include: + +[c++] + + #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT MYASSERT + #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE [endsect] @@ -1032,8 +1041,9 @@ the same options explained in the section * [*`optimize_size`]: The hook will be optimized for size instead of speed. The hook will embed the color bit of the red-black tree node in the parent pointer if pointer alignment is even. - Optimizing the size will reduce speed performance a bit since masking - operations will be needed to access parent pointer and color attributes. + In some platforms, optimizing the size might reduce speed performance a bit + since masking operations will be needed to access parent pointer and color attributes, + in other platforms this option improves performance due to improved memory locality. Default: `optimize_size`. [endsect] @@ -1283,11 +1293,17 @@ And they also can receive additional options: (e.g. strings with a long common predicate) sometimes (specially when the load factor is high or we have many equivalent elements in an [classref boost::intrusive::unordered_multiset unordered_multiset] and - no `optimize_multikey<>` is activatedin the hook) + no `optimize_multikey<>` is activated in the hook) the equality function is a performance problem. Two equal values must have equal hashes, so comparing the hash values of two elements before using the comparison functor can speed up some implementations. +* [*`incremental`]: Activates incremental hashing (also known as Linear Hashing). + This option implies `power_2_buckets` and the container will require power of two buckets. + For more information on incremental hashing, see + [@http://en.wikipedia.org/wiki/Linear_hashing `Linear hash` on Wikipedia] + Default: `incremental` + [endsect] [section:unordered_set_unordered_multiset_example Example] @@ -1558,8 +1574,9 @@ the size of the node: * [*`optimize_size`]: The hook will be optimized for size instead of speed. The hook will embed the balance bits of the AVL tree node in the parent pointer if pointer alignment is multiple of 4. - Optimizing the size will reduce speed performance a bit since masking - operations will be needed to access parent pointer and balance factor attributes. + In some platforms, optimizing the size might reduce speed performance a bit + since masking operations will be needed to access parent pointer and balance factor attributes, + in other platforms this option improves performance due to improved memory locality. Default: `optimize_size`. [endsect] @@ -1890,7 +1907,7 @@ and [classref boost::intrusive::unordered_set unordered_set] reference for more With multiple ordered and unordered associative containers ([classref boost::intrusive::multiset multiset] and -[classref boost::intrusive::unordered_multiset unordered_multiset]) there's +[classref boost::intrusive::unordered_multiset unordered_multiset]) there is no need for these advanced insertion functions, since insertions are always succesful. [endsect] @@ -1982,7 +1999,7 @@ The cloning function works as follows: all the constructed elements are disposed using the disposer function object. -Here's an example of `clone_from`: +Here is an example of `clone_from`: [import ../example/doc_clone_from.cpp] [doc_clone_from] @@ -2116,7 +2133,7 @@ These hooks support these options: be inserted container. Additionally, these hooks don't support `unlink()` and `swap_nodes()` operations for the same reason. -Here's an example that creates a class with two any hooks, and uses one to insert the +Here is an example that creates a class with two any hooks, and uses one to insert the class in a [classref slist] and the other one in a [classref list]. [import ../example/doc_any_hook.cpp] @@ -2699,7 +2716,7 @@ used in node algorithms, since these types can be different. Apart from this, Instead of using [*Boost.Intrusive] predefined hooks a user might want to develop customized containers, for example, using nodes that are optimized for a specific -application or that are compatible with a a legacy ABI. A user might want +application or that are compatible with a legacy ABI. A user might want to have only two additional pointers in his class and insert the class in a doubly linked list sometimes and in a singly linked list in other situations. You can't achieve this using [*Boost.Intrusive] predefined hooks. Now, instead of using @@ -3459,7 +3476,7 @@ The disperse list is again the slowest. [section:performance_results_conclusions Conclusions] -Intrusive containers can offer performance benefits that can not be achieved with +Intrusive containers can offer performance benefits that cannot be achieved with equivalent non-intrusive containers. Memory locality improvements are noticeable when the objects to be inserted are small. Minimizing memory allocation/deallocation calls is also an important factor and intrusive containers make this simple if the user allocates @@ -3471,6 +3488,17 @@ all the objects to be inserted in intrusive containers in containers like `std:: [section:release_notes Release Notes] +[section:release_notes_boost_1_37_00 Boost 1.37 Release] + +* Intrusive now takes advantage of compilers with variadic templates. +* `clone_from` functions now copy predicates and hash functions of associative containers. +* Added incremental hashing to unordered containers via `incremental<>` option. +* Update some function parameters from `iterator` to `const_iterator` in containers + to keep up with the draft of the next standard. +* Added an option to specify include files for intrusive configurable assertion macros. + +[endsect] + [section:release_notes_boost_1_36_00 Boost 1.36 Release] * Added `linear<>` and `cache_last<>` options to singly linked lists. @@ -3512,7 +3540,7 @@ all the objects to be inserted in intrusive containers in containers like `std:: [endsect] -[section:acknowledgments Acknowledgements] +[section:acknowledgements Acknowledegements] [*Olaf Krzikalla] would like to thank: diff --git a/example/doc_window.cpp b/example/doc_window.cpp index 9f49e9e..7a0e12d 100644 --- a/example/doc_window.cpp +++ b/example/doc_window.cpp @@ -21,7 +21,7 @@ class Window : public list_base_hook<> //This is a container those value is an abstract class: you can't do this with std::list. typedef list win_list; - //An static intrusive list declaration + //A static intrusive list declaration static win_list all_windows; //Constructor. Includes this window in the list diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index b42d957..c5a1d2e 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -267,6 +267,9 @@ + + Implement C++0x features (variadic templates & rvalue references) +-> Offer bidirectional iterator for hashtables +-> Non-array buckets diff --git a/proj/vc7ide/unordered_set/unordered_set.vcproj b/proj/vc7ide/unordered_set/unordered_set.vcproj index b7e9681..1496175 100644 --- a/proj/vc7ide/unordered_set/unordered_set.vcproj +++ b/proj/vc7ide/unordered_set/unordered_set.vcproj @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="7.10" Name="unordered_set" - ProjectGUID="{90E701E6-2C91-F4A7-BA6C-A9F3B0949279}" + ProjectGUID="{9101EE76-BB6C-2C91-F4B7-A27B94908F19}" Keyword="Win32Proj"> + UniqueIdentifier="{4F3C77F1-B78A-C745-4726-252AD75C322E}"> diff --git a/test/default_hook_test.cpp b/test/default_hook_test.cpp index 938095f..90f664d 100644 --- a/test/default_hook_test.cpp +++ b/test/default_hook_test.cpp @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include "smart_ptr.hpp" #include @@ -28,6 +31,12 @@ class MyClass < void_pointer >, link_mode > , public unordered_set_base_hook < void_pointer >, link_mode > +, public avl_set_base_hook + < void_pointer >, link_mode > +, public splay_set_base_hook + < void_pointer >, link_mode > +, public bs_set_base_hook + < void_pointer >, link_mode > { int int_; @@ -51,6 +60,9 @@ typedef list List; typedef slist Slist; typedef set Set; typedef unordered_set USet; +typedef avl_set AvlSet; +typedef splay_set SplaySet; +typedef sg_set SgSet; int main() { @@ -67,6 +79,9 @@ int main() Slist my_slist; Set my_set; USet my_uset(USet::bucket_traits(buckets, 100)); + AvlSet my_avlset; + SplaySet my_splayset; + SgSet my_sgset; //Now insert them in the reverse order //in the base hook intrusive list @@ -75,6 +90,9 @@ int main() my_slist.push_front(*it); my_set.insert(*it); my_uset.insert(*it); + my_avlset.insert(*it); + my_splayset.insert(*it); + my_sgset.insert(*it); } //Now test lists @@ -82,13 +100,24 @@ int main() List::const_iterator list_it(my_list.cbegin()); Slist::const_iterator slist_it(my_slist.cbegin()); Set::const_reverse_iterator set_rit(my_set.crbegin()); + AvlSet::const_reverse_iterator avl_set_rit(my_avlset.crbegin()); + SplaySet::const_reverse_iterator splay_set_rit(my_splayset.crbegin()); + SgSet::const_reverse_iterator sg_set_rit(my_sgset.crbegin()); + VectRit vect_it(values.rbegin()), vect_itend(values.rend()); //Test the objects inserted in the base hook list - for(; vect_it != vect_itend; ++vect_it, ++list_it, ++slist_it, ++set_rit){ - if(&*list_it != &*vect_it) return 1; - if(&*slist_it != &*vect_it) return 1; - if(&*set_rit != &*vect_it) return 1; + for(; vect_it != vect_itend + ; ++vect_it, ++list_it + , ++slist_it, ++set_rit + , ++avl_set_rit, ++splay_set_rit + , ++sg_set_rit){ + if(&*list_it != &*vect_it) return 1; + if(&*slist_it != &*vect_it) return 1; + if(&*set_rit != &*vect_it) return 1; + if(&*avl_set_rit != &*vect_it) return 1; + if(&*splay_set_rit != &*vect_it)return 1; + if(&*sg_set_rit != &*vect_it) return 1; if(my_uset.find(*set_rit) == my_uset.cend()) return 1; } } diff --git a/test/list_test.cpp b/test/list_test.cpp index 37998be..65cfa8b 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -13,6 +13,7 @@ #include #include + #include #include "itestvalue.hpp" #include "smart_ptr.hpp" @@ -446,13 +447,12 @@ class test_main_template > >::type >::test_all(data); -/* - test_list - , safe_link> - >::test_all(data); -*/ + +// test_list +// , safe_link> +// >::test_all(data); test_list < typename detail::get_base_value_traits < value_type , typename value_type::list_auto_base_hook_t @@ -467,13 +467,13 @@ class test_main_template > >::type >::test_all(data); -/* - test_list - , auto_unlink> - >::test_all(data); -*/ + +// test_list +// , auto_unlink> +// >::test_all(data); + return 0; } }; @@ -488,3 +488,285 @@ int main( int, char* [] ) return boost::report_errors(); } #include + + + + + + + + + + + + + +/* +#include + + +//////////////////////////////////////////////////// +// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will +// be used to "unpack" into comma-separated values +// in a function call. +//////////////////////////////////////////////////// + +template +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + +template +struct typelist +{}; + +template +struct invert_typelist; + +template +struct typelist_element; + +template +struct typelist_element > +{ + typedef typename typelist_element >::type type; +}; + +template +struct typelist_element<0, typelist > +{ + typedef Head type; +}; + +template +typelist >::type...> + inverted_typelist(index_tuple, typelist) +{ + return typelist >::type...>(); +} + + +template +struct sizeof_typelist; + +template +struct sizeof_typelist< typelist > +{ + static const std::size_t value = sizeof...(Types); +}; + +//invert_typelist_impl +template +struct invert_typelist_impl; + + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + static const std::size_t last_idx = sizeof_typelist::value - 1; + typedef typelist + ::type...> type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + typedef Typelist type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple<> > +{ + typedef Typelist type; +}; + +//invert_typelist +template +struct invert_typelist; + +template +struct invert_typelist< typelist > +{ + typedef typelist typelist_t; + typedef typename build_number_seq::type indexes_t; + typedef typename invert_typelist_impl::type type; +}; + +struct none +{ + template + struct pack : Base + { }; +}; + +//!This option setter specifies the type of +//!a void pointer. This will instruct the hook +//!to use this type of pointer instead of the +//!default one +template +struct void_pointer +{ +/// @cond + template + struct pack : Base + { + typedef VoidPointer void_pointer; + }; +/// @endcond +}; + +//!This option setter specifies the type of +//!the tag of a base hook. A type cannot have two +//!base hooks of the same type, so a tag can be used +//!to differentiate two base hooks with otherwise same type +template +struct tag +{ +/// @cond + template + struct pack : Base + { + typedef Tag tag; + }; +/// @endcond +}; + + +//!This option setter specifies if the hook +//!should be optimized for size instead of for speed. +template +struct optimize_size +{ +/// @cond + template + struct pack : Base + { + static const bool optimize_size = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the list container should +//!use a linear implementation instead of a circular one. +template +struct linear +{ +/// @cond + template + struct pack : Base + { + static const bool linear = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the list container should +//!use a linear implementation instead of a circular one. +template +struct cache_last +{ +/// @cond + template + struct pack : Base + { + static const bool cache_last = Enabled; + }; +/// @endcond +}; + + + +template +struct do_pack; + +template<> +struct do_pack >; + +template +struct do_pack > +{ + typedef Prev type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack + >::type> type; +}; + + +template +struct pack_options +{ + typedef typelist typelist_t; + typedef typename invert_typelist::type inverted_typelist; + typedef typename do_pack::type type; +}; + +struct hook_defaults + : public pack_options + < none + , void_pointer + , tag + , optimize_size + , linear + >::type +{}; + + +#include +#include + +struct S +{}; + +int main() +{ + { + typedef typelist typelist_t; + typedef invert_typelist::type inverted_typelist; + std::cout << "original: " << typeid(typelist_t).name() << std::endl; + std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; + } + { + typedef typelist typelist_t; + typedef invert_typelist::type inverted_typelist; + std::cout << "original: " << typeid(typelist_t).name() << std::endl; + std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; + } + { + typedef typelist<> typelist_t; + typedef invert_typelist::type inverted_typelist; + std::cout << "original: " << typeid(typelist_t).name() << std::endl; + std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl; + } + { + typedef pack_options::type options_t; + std::cout << "options_t " << typeid(options_t).name() << std::endl; + } + { + typedef pack_options::type options_t; + std::cout << "options_t " << typeid(options_t).name() << std::endl; + } + + hook_defaults h; + return 1; +} +*/ \ No newline at end of file diff --git a/test/set_test.cpp b/test/set_test.cpp index a6b214e..44a0141 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -108,7 +108,6 @@ class test_main_template int main( int, char* [] ) { - test_main_template()(); test_main_template, false>()(); test_main_template()(); diff --git a/test/sg_multiset_test.cpp b/test/sg_multiset_test.cpp index 48f15f4..e5bff6a 100644 --- a/test/sg_multiset_test.cpp +++ b/test/sg_multiset_test.cpp @@ -18,8 +18,18 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/sg_set_test.cpp b/test/sg_set_test.cpp index 9d85e32..df424cc 100644 --- a/test/sg_set_test.cpp +++ b/test/sg_set_test.cpp @@ -17,8 +17,18 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/splay_multiset_test.cpp b/test/splay_multiset_test.cpp index a8601ac..fbccdef 100644 --- a/test/splay_multiset_test.cpp +++ b/test/splay_multiset_test.cpp @@ -19,20 +19,51 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_const_overloads > +#else +template +#endif +struct has_const_overloads +> { static const bool value = false; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_splay > +#else +template +#endif +struct has_splay > { static const bool value = true; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/splay_set_test.cpp b/test/splay_set_test.cpp index b18b4e7..3f61609 100644 --- a/test/splay_set_test.cpp +++ b/test/splay_set_test.cpp @@ -17,20 +17,50 @@ namespace boost { namespace intrusive { namespace test { +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_const_overloads > +#else +template +#endif +struct has_const_overloads > { static const bool value = false; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_splay > +#else +template +#endif +struct has_splay > { static const bool value = true; }; +#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES) template -struct has_rebalance > +#else +template +#endif +struct has_rebalance > { static const bool value = true; }; diff --git a/test/test_macros.hpp b/test/test_macros.hpp index d612b9f..3a76541 100644 --- a/test/test_macros.hpp +++ b/test/test_macros.hpp @@ -15,10 +15,7 @@ #define TEST_INTRUSIVE_SEQUENCE( INTVALUES, ITERATOR )\ { \ - const int init_values_size = sizeof(INTVALUES)/sizeof(INTVALUES[0]); \ - std::vector expected; \ - expected.assign(&INTVALUES[0], &INTVALUES[0] + init_values_size); \ - BOOST_TEST (std::equal(expected.begin(), expected.end(), ITERATOR) ); \ + BOOST_TEST (std::equal(&INTVALUES[0], &INTVALUES[0] + sizeof(INTVALUES)/sizeof(INTVALUES[0]), ITERATOR) ); \ } #define TEST_INTRUSIVE_SEQUENCE_EXPECTED( EXPECTEDVECTOR, ITERATOR )\ diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp index e10efd2..1adab30 100644 --- a/test/unordered_multiset_test.cpp +++ b/test/unordered_multiset_test.cpp @@ -25,9 +25,9 @@ using namespace boost::intrusive; -static const std::size_t BucketSize = 11; +static const std::size_t BucketSize = 8; -template +template struct test_unordered_multiset { typedef typename ValueTraits::value_type value_type; @@ -35,14 +35,16 @@ struct test_unordered_multiset static void test_sort(std::vector& values); static void test_insert(std::vector& values); static void test_swap(std::vector& values); - static void test_rehash(std::vector& values); + static void test_rehash(std::vector& values, detail::true_); + static void test_rehash(std::vector& values, detail::false_); static void test_find(std::vector& values); static void test_impl(); static void test_clone(std::vector& values); }; -template -void test_unordered_multiset::test_all (std::vector& values) +template +void test_unordered_multiset:: + test_all (std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -51,6 +53,7 @@ void test_unordered_multiset::test_all (st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; { typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -71,15 +74,16 @@ void test_unordered_multiset::test_all (st test_sort(values); test_insert(values); test_swap(values); - test_rehash(values); + test_rehash(values, detail::bool_()); test_find(values); test_impl(); test_clone(values); } //test case due to an error in tree implementation: -template -void test_unordered_multiset::test_impl() +template +void test_unordered_multiset + ::test_impl() { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -88,6 +92,7 @@ void test_unordered_multiset::test_impl() , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -110,8 +115,9 @@ void test_unordered_multiset::test_impl() } //test: constructor, iterator, clear, reverse_iterator, front, back, size: -template -void test_unordered_multiset::test_sort(std::vector& values) +template +void test_unordered_multiset + ::test_sort(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -120,21 +126,29 @@ void test_unordered_multiset::test_sort(st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; typename unordered_multiset_type::bucket_type buckets [BucketSize]; unordered_multiset_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); - { int init_values [] = { 1, 2, 2, 3, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + else{ + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } testset1.clear(); BOOST_TEST (testset1.empty()); } - + //test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: -template -void test_unordered_multiset::test_insert(std::vector& values) +template +void test_unordered_multiset + ::test_insert(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -143,54 +157,100 @@ void test_unordered_multiset::test_insert( , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::iterator iterator; - { - typename unordered_multiset_type::bucket_type buckets [BucketSize]; - unordered_multiset_type testset(bucket_traits(buckets, BucketSize)); + typename unordered_multiset_type::bucket_type buckets [BucketSize]; + unordered_multiset_type testset(bucket_traits(buckets, BucketSize)); - testset.insert(&values[0] + 2, &values[0] + 5); + testset.insert(&values[0] + 2, &values[0] + 5); - const unordered_multiset_type& const_testset = testset; - { int init_values [] = { 1, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + const unordered_multiset_type& const_testset = testset; - typename unordered_multiset_type::iterator i = testset.begin(); - BOOST_TEST (i->value_ == 1); + if(Incremental){ + { + { int init_values [] = { 4, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } - i = testset.insert (values[0]); - BOOST_TEST (&*i == &values[0]); - - i = testset.iterator_to (values[2]); - BOOST_TEST (&*i == &values[2]); - testset.erase(i); + typename unordered_multiset_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 4); - { int init_values [] = { 1, 3, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } - testset.clear(); - testset.insert(&values[0], &values[0] + values.size()); + i = testset.insert (values[0]); + BOOST_TEST (&*i == &values[0]); + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + testset.erase(i); - { int init_values [] = { 1, 2, 2, 3, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + { int init_values [] = { 5, 1, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + testset.clear(); + testset.insert(&values[0], &values[0] + values.size()); - BOOST_TEST (testset.erase(1) == 1); - BOOST_TEST (testset.erase(2) == 2); - BOOST_TEST (testset.erase(3) == 1); - BOOST_TEST (testset.erase(4) == 1); - BOOST_TEST (testset.erase(5) == 1); - BOOST_TEST (testset.empty() == true); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } - //Now with a single bucket - typename unordered_multiset_type::bucket_type single_bucket[1]; - unordered_multiset_type testset2(bucket_traits(single_bucket, 1)); - testset2.insert(&values[0], &values[0] + values.size()); - BOOST_TEST (testset2.erase(5) == 1); - BOOST_TEST (testset2.erase(2) == 2); - BOOST_TEST (testset2.erase(1) == 1); - BOOST_TEST (testset2.erase(4) == 1); - BOOST_TEST (testset2.erase(3) == 1); - BOOST_TEST (testset2.empty() == true); + BOOST_TEST (testset.erase(1) == 1); + BOOST_TEST (testset.erase(2) == 2); + BOOST_TEST (testset.erase(3) == 1); + BOOST_TEST (testset.erase(4) == 1); + BOOST_TEST (testset.erase(5) == 1); + BOOST_TEST (testset.empty() == true); + + //Now with a single bucket + typename unordered_multiset_type::bucket_type single_bucket[1]; + unordered_multiset_type testset2(bucket_traits(single_bucket, 1)); + testset2.insert(&values[0], &values[0] + values.size()); + BOOST_TEST (testset2.erase(5) == 1); + BOOST_TEST (testset2.erase(2) == 2); + BOOST_TEST (testset2.erase(1) == 1); + BOOST_TEST (testset2.erase(4) == 1); + BOOST_TEST (testset2.erase(3) == 1); + BOOST_TEST (testset2.empty() == true); + } + } + else{ + { + { int init_values [] = { 1, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + + typename unordered_multiset_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 1); + + i = testset.insert (values[0]); + BOOST_TEST (&*i == &values[0]); + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + testset.erase(i); + + { int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + testset.clear(); + testset.insert(&values[0], &values[0] + values.size()); + + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + + BOOST_TEST (testset.erase(1) == 1); + BOOST_TEST (testset.erase(2) == 2); + BOOST_TEST (testset.erase(3) == 1); + BOOST_TEST (testset.erase(4) == 1); + BOOST_TEST (testset.erase(5) == 1); + BOOST_TEST (testset.empty() == true); + + //Now with a single bucket + typename unordered_multiset_type::bucket_type single_bucket[1]; + unordered_multiset_type testset2(bucket_traits(single_bucket, 1)); + testset2.insert(&values[0], &values[0] + values.size()); + BOOST_TEST (testset2.erase(5) == 1); + BOOST_TEST (testset2.erase(2) == 2); + BOOST_TEST (testset2.erase(1) == 1); + BOOST_TEST (testset2.erase(4) == 1); + BOOST_TEST (testset2.erase(3) == 1); + BOOST_TEST (testset2.empty() == true); + } } { //Now erase just one per loop @@ -270,11 +330,12 @@ void test_unordered_multiset::test_insert( } } } -} +} //test: insert (seq-version), swap, erase (seq-version), size: -template -void test_unordered_multiset::test_swap(std::vector& values) +template +void test_unordered_multiset:: + test_swap(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -283,17 +344,30 @@ void test_unordered_multiset::test_swap(st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; typename unordered_multiset_type::bucket_type buckets [BucketSize]; - { - typename unordered_multiset_type::bucket_type buckets2 [BucketSize]; - unordered_multiset_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets, BucketSize)); - unordered_multiset_type testset2(bucket_traits(buckets2, BucketSize)); - testset2.insert (&values[0] + 2, &values[0] + 6); - testset1.swap (testset2); + typename unordered_multiset_type::bucket_type buckets2 [BucketSize]; + unordered_multiset_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets, BucketSize)); + unordered_multiset_type testset2(bucket_traits(buckets2, BucketSize)); + testset2.insert (&values[0] + 2, &values[0] + 6); + testset1.swap (testset2); + + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + { int init_values [] = { 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } + testset1.erase (testset1.iterator_to(values[4]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + // BOOST_TEST (&testset1.front() == &values[3]); + BOOST_TEST (&*testset1.begin() == &values[2]); + } + else{ { int init_values [] = { 1, 2, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } @@ -306,9 +380,13 @@ void test_unordered_multiset::test_swap(st } } + + //test: rehash: -template -void test_unordered_multiset::test_rehash(std::vector& values) + +template +void test_unordered_multiset + ::test_rehash(std::vector& values, detail::true_) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -317,6 +395,135 @@ void test_unordered_multiset::test_rehash( , constant_time_size , cache_begin , compare_hash + , incremental + > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; + //Build a uset + typename unordered_multiset_type::bucket_type buckets1 [BucketSize]; + typename unordered_multiset_type::bucket_type buckets2 [BucketSize*2]; + unordered_multiset_type testset1(&values[0], &values[0] + values.size(), bucket_traits(buckets1, BucketSize)); + //Test current state + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Rest of incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket != BucketSize; ++split_bucket){ + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (split_bucket+1)); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //This incremental rehash should fail because we've reached the end of the bucket array + BOOST_TEST (testset1.incremental_rehash() == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //Full shrink rehash + testset1.rehash(bucket_traits(buckets1, 4)); + BOOST_TEST (testset1.size() == values.size()); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full shrink rehash again + testset1.rehash(bucket_traits(buckets1, 2)); + BOOST_TEST (testset1.size() == values.size()); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 2, 2, 4, 3, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full growing rehash + testset1.rehash(bucket_traits(buckets1, BucketSize)); + BOOST_TEST (testset1.size() == values.size()); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash shrinking + //First incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket > 6; --split_bucket){ + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (split_bucket-1)); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step 2 + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2)); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //This incremental rehash should fail because we've reached the half of the bucket array + BOOST_TEST(testset1.incremental_rehash(false) == false); + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } +} +template +void test_unordered_multiset + ::test_rehash(std::vector& values, detail::false_) +{ + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size + , cache_begin + , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -325,36 +532,37 @@ void test_unordered_multiset::test_rehash( typename unordered_multiset_type::bucket_type buckets3 [BucketSize*2]; unordered_multiset_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets2, 2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 4, 2, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash reducing the buckets testset1.rehash(bucket_traits(buckets3, 2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 4, 2, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash increasing the buckets testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 6); + BOOST_TEST (testset1.size() == values.size()); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } } //test: find, equal_range (lower_bound, upper_bound): -template -void test_unordered_multiset::test_find(std::vector& values) +template +void test_unordered_multiset:: + test_find(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_multiset @@ -363,6 +571,7 @@ void test_unordered_multiset::test_find(st , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; @@ -387,8 +596,8 @@ void test_unordered_multiset::test_find(st } -template -void test_unordered_multiset +template +void test_unordered_multiset ::test_clone(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -398,6 +607,7 @@ void test_unordered_multiset , constant_time_size , cache_begin , compare_hash + , incremental > unordered_multiset_type; typedef typename unordered_multiset_type::bucket_traits bucket_traits; { @@ -442,7 +652,7 @@ void test_unordered_multiset unordered_multiset_type testset2 (bucket_traits(buckets2, BucketSize*2)); testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); - //Ordering is not guarantee in the cloning so insert data in a set and test + //Ordering is not guaranteed in the cloning so insert data in a set and test std::multiset src(testset1.begin(), testset1.end()); std::multiset @@ -453,7 +663,7 @@ void test_unordered_multiset } } -template +template class test_main_template { public: @@ -471,6 +681,7 @@ class test_main_template >::type , true , false + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_member_value_traits @@ -482,14 +693,15 @@ class test_main_template >::type , false , false + , Incremental >::test_all(data); return 0; } }; -template -class test_main_template +template +class test_main_template { public: int operator()() @@ -506,6 +718,7 @@ class test_main_template >::type , true , false + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_member_value_traits @@ -517,6 +730,7 @@ class test_main_template >::type , false , false + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_base_value_traits @@ -525,6 +739,7 @@ class test_main_template >::type , true , true + , Incremental >::test_all(data); test_unordered_multiset < typename detail::get_member_value_traits @@ -536,6 +751,7 @@ class test_main_template >::type , false , true + , Incremental >::test_all(data); return 0; } @@ -543,10 +759,14 @@ class test_main_template int main( int, char* [] ) { - test_main_template()(); - test_main_template, false>()(); - test_main_template()(); - test_main_template, true>()(); + test_main_template()(); + test_main_template, false, true>()(); + test_main_template()(); + test_main_template, true, true>()(); + test_main_template()(); + test_main_template, false, false>()(); + test_main_template()(); + test_main_template, true, false>()(); return boost::report_errors(); } diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp index 7702a2e..8aa27da 100644 --- a/test/unordered_set_test.cpp +++ b/test/unordered_set_test.cpp @@ -24,9 +24,9 @@ using namespace boost::intrusive; -static const std::size_t BucketSize = 11; +static const std::size_t BucketSize = 8; -template +template struct test_unordered_set { typedef typename ValueTraits::value_type value_type; @@ -34,14 +34,16 @@ struct test_unordered_set static void test_sort(std::vector& values); static void test_insert(std::vector& values); static void test_swap(std::vector& values); - static void test_rehash(std::vector& values); + static void test_rehash(std::vector& values, detail::true_); + static void test_rehash(std::vector& values, detail::false_); static void test_find(std::vector& values); static void test_impl(); static void test_clone(std::vector& values); }; -template -void test_unordered_set::test_all(std::vector& values) +template +void test_unordered_set:: + test_all(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -50,6 +52,7 @@ void test_unordered_set::test_all(std::vec , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; { @@ -70,15 +73,15 @@ void test_unordered_set::test_all(std::vec test_sort(values); test_insert(values); test_swap(values); - test_rehash(values); + test_rehash(values, detail::bool_()); test_find(values); test_impl(); test_clone(values); } //test case due to an error in tree implementation: -template -void test_unordered_set::test_impl() +template +void test_unordered_set::test_impl() { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -87,6 +90,7 @@ void test_unordered_set::test_impl() , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -107,8 +111,9 @@ void test_unordered_set::test_impl() } //test: constructor, iterator, clear, reverse_iterator, front, back, size: -template -void test_unordered_set::test_sort(std::vector& values) +template +void test_unordered_set:: + test_sort(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -117,23 +122,31 @@ void test_unordered_set::test_sort(std::ve , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; typename unordered_set_type::bucket_type buckets [BucketSize]; unordered_set_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); - BOOST_TEST (5 == std::distance(testset1.begin(), testset1.end())); - { int init_values [] = { 1, 2, 3, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + else{ + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } testset1.clear(); BOOST_TEST (testset1.empty()); } //test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: -template -void test_unordered_set::test_insert(std::vector& values) +template +void test_unordered_set:: + test_insert(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -142,6 +155,7 @@ void test_unordered_set::test_insert(std:: , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -150,27 +164,47 @@ void test_unordered_set::test_insert(std:: testset.insert(&values[0] + 2, &values[0] + 5); const unordered_set_type& const_testset = testset; - { int init_values [] = { 1, 4, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + if(Incremental) + { + { int init_values [] = { 4, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + typename unordered_set_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 4); - typename unordered_set_type::iterator i = testset.begin(); - BOOST_TEST (i->value_ == 1); + i = testset.insert(values[0]).first; + BOOST_TEST (&*i == &values[0]); - i = testset.insert(values[0]).first; - BOOST_TEST (&*i == &values[0]); + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); - i = testset.iterator_to (values[2]); - BOOST_TEST (&*i == &values[2]); + testset.erase (i); - testset.erase (i); + { int init_values [] = { 5, 1, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + } + else{ + { int init_values [] = { 1, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + typename unordered_set_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 1); - { int init_values [] = { 1, 3, 5 }; - TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + i = testset.insert(values[0]).first; + BOOST_TEST (&*i == &values[0]); + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + + testset.erase (i); + + { int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + } } //test: insert (seq-version), swap, erase (seq-version), size: -template -void test_unordered_set::test_swap(std::vector& values) +template +void test_unordered_set:: + test_swap(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -179,6 +213,7 @@ void test_unordered_set::test_swap(std::ve , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -190,20 +225,30 @@ void test_unordered_set::test_swap(std::ve testset2.insert (&values[0] + 2, &values[0] + 6); testset1.swap (testset2); - { int init_values [] = { 1, 2, 4, 5 }; + if(Incremental){ + { int init_values [] = { 4, 5, 1, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + { int init_values [] = { 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } + testset1.erase (testset1.iterator_to(values[4]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + BOOST_TEST (&*testset1.begin() == &values[2]); + } + else{ + { int init_values [] = { 1, 2, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } - { int init_values [] = { 2, 3 }; + { int init_values [] = { 2, 3 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } - - testset1.erase (testset1.iterator_to(values[5]), testset1.end()); - BOOST_TEST (testset1.size() == 1); - // BOOST_TEST (&testset1.front() == &values[3]); - BOOST_TEST (&*testset1.begin() == &values[3]); + testset1.erase (testset1.iterator_to(values[5]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + BOOST_TEST (&*testset1.begin() == &values[3]); + } } //test: rehash: -template -void test_unordered_set::test_rehash(std::vector& values) +template +void test_unordered_set:: + test_rehash(std::vector& values, detail::true_) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -212,6 +257,137 @@ void test_unordered_set::test_rehash(std:: , constant_time_size , cache_begin , compare_hash + , incremental + > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; + //Build a uset + typename unordered_set_type::bucket_type buckets1 [BucketSize]; + typename unordered_set_type::bucket_type buckets2 [BucketSize*2]; + unordered_set_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); + //Test current state + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Rest of incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket != BucketSize; ++split_bucket){ + BOOST_TEST (testset1.incremental_rehash() == true); + BOOST_TEST(testset1.split_count() == (split_bucket+1)); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //This incremental rehash should fail because we've reached the end of the bucket array + BOOST_TEST(testset1.incremental_rehash() == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + // + //Try incremental hashing specifying a new bucket traits pointing to the same array + // + //This incremental rehash should fail because the new size is not twice the original + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize)) == false); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should success because the new size is twice the original + //and split_count is the same as the old bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets2, BucketSize*2)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //This incremental rehash should also success because the new size is half the original + //and split_count is the same as the new bucket count + BOOST_TEST(testset1.incremental_rehash(bucket_traits(buckets1, BucketSize)) == true); + BOOST_TEST(testset1.split_count() == BucketSize); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + //Full shrink rehash + testset1.rehash(bucket_traits(buckets1, 4)); + BOOST_TEST (testset1.size() == values.size()-1); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full shrink rehash again + testset1.rehash(bucket_traits(buckets1, 2)); + BOOST_TEST (testset1.size() == values.size()-1); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 2, 4, 3, 5, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Full growing rehash + testset1.rehash(bucket_traits(buckets1, BucketSize)); + BOOST_TEST (testset1.size() == values.size()-1); + BOOST_TEST (testset1.incremental_rehash() == false); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash shrinking + //First incremental rehashes should lead to the same sequence + for(std::size_t split_bucket = testset1.split_count(); split_bucket > 6; --split_bucket){ + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (split_bucket-1)); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + } + //Incremental rehash step + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2+1)); + { int init_values [] = { 5, 1, 2, 3, 4 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //Incremental rehash step 2 + BOOST_TEST (testset1.incremental_rehash(false) == true); + BOOST_TEST(testset1.split_count() == (BucketSize/2)); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + //This incremental rehash should fail because we've reached the half of the bucket array + BOOST_TEST(testset1.incremental_rehash(false) == false); + BOOST_TEST(testset1.split_count() == BucketSize/2); + { int init_values [] = { 4, 5, 1, 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } +} + +//test: rehash: +template +void test_unordered_set:: + test_rehash(std::vector& values, detail::false_) +{ + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size + , cache_begin + , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -220,37 +396,38 @@ void test_unordered_set::test_rehash(std:: typename unordered_set_type::bucket_type buckets3 [BucketSize*2]; unordered_set_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets2, 2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 4, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash reducing the buckets testset1.rehash(bucket_traits(buckets3, 2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 4, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash increasing the buckets testset1.rehash(bucket_traits(buckets3, BucketSize*2)); - BOOST_TEST (testset1.size() == 5); + BOOST_TEST (testset1.size() == values.size()-1); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } } //test: find, equal_range (lower_bound, upper_bound): -template -void test_unordered_set::test_find(std::vector& values) +template +void test_unordered_set:: + test_find(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef unordered_set @@ -259,6 +436,7 @@ void test_unordered_set::test_find(std::ve , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; @@ -281,8 +459,8 @@ void test_unordered_set::test_find(std::ve BOOST_TEST (testset.find (cmp_val) == testset.end()); } -template -void test_unordered_set +template +void test_unordered_set ::test_clone(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -292,6 +470,7 @@ void test_unordered_set , constant_time_size , cache_begin , compare_hash + , incremental > unordered_set_type; typedef typename unordered_set_type::bucket_traits bucket_traits; { @@ -319,7 +498,7 @@ void test_unordered_set unordered_set_type testset2 (bucket_traits(buckets2, BucketSize)); testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); - //Ordering is not guarantee in the cloning so insert data in a set and test + //Ordering is not guaranteed in the cloning so insert data in a set and test std::set src(testset1.begin(), testset1.end()); std::set @@ -347,7 +526,7 @@ void test_unordered_set } } -template +template class test_main_template { public: @@ -365,6 +544,7 @@ class test_main_template >::type , true , false + , incremental >::test_all(data); test_unordered_set < typename detail::get_member_value_traits < value_type @@ -375,14 +555,15 @@ class test_main_template >::type , false , false + , incremental >::test_all(data); return 0; } }; -template -class test_main_template +template +class test_main_template { public: int operator()() @@ -399,6 +580,7 @@ class test_main_template >::type , true , false + , incremental >::test_all(data); test_unordered_set < typename detail::get_member_value_traits @@ -410,6 +592,7 @@ class test_main_template >::type , false , false + , incremental >::test_all(data); test_unordered_set < typename detail::get_base_value_traits @@ -418,6 +601,7 @@ class test_main_template >::type , true , true + , incremental >::test_all(data); test_unordered_set < typename detail::get_member_value_traits @@ -429,6 +613,7 @@ class test_main_template >::type , false , true + , incremental >::test_all(data); return 0; } @@ -436,10 +621,14 @@ class test_main_template int main( int, char* [] ) { - test_main_template()(); - test_main_template, false>()(); - test_main_template()(); - test_main_template, true>()(); + test_main_template()(); + test_main_template, false, true>()(); + test_main_template()(); + test_main_template, true, true>()(); + test_main_template()(); + test_main_template, false, false>()(); + test_main_template()(); + test_main_template, true, false>()(); return boost::report_errors(); } #include