Changes and fixes for Boost 1.37

[SVN r49277]
This commit is contained in:
Ion Gaztañaga
2008-10-11 13:18:02 +00:00
parent d8641cd15c
commit be6ca1b7ec
15 changed files with 1012 additions and 180 deletions

View File

@@ -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 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 transmitted to the containers, so all the internal pointers used by intrusive containers
configured with these hooks will be smart pointers. As an example, 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 called `offset_ptr`. [*Boost.Intrusive] can be configured to use this smart pointer
to allow shared memory intrusive containers. 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. 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 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 <myassert.h>
[endsect] [endsect]
@@ -1032,8 +1041,9 @@ the same options explained in the section
* [*`optimize_size<bool Enable>`]: The hook will be optimized for size * [*`optimize_size<bool Enable>`]: The hook will be optimized for size
instead of speed. The hook will embed the color bit of the red-black 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. tree node in the parent pointer if pointer alignment is even.
Optimizing the size will reduce speed performance a bit since masking In some platforms, optimizing the size might reduce speed performance a bit
operations will be needed to access parent pointer and color attributes. 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<false>`. Default: `optimize_size<false>`.
[endsect] [endsect]
@@ -1283,11 +1293,17 @@ And they also can receive additional options:
(e.g. strings with a long common predicate) sometimes (specially when the (e.g. strings with a long common predicate) sometimes (specially when the
load factor is high or we have many equivalent elements in an load factor is high or we have many equivalent elements in an
[classref boost::intrusive::unordered_multiset unordered_multiset] and [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 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 equal hashes, so comparing the hash values of two elements before using the
comparison functor can speed up some implementations. comparison functor can speed up some implementations.
* [*`incremental<bool Enabled>`]: Activates incremental hashing (also known as Linear Hashing).
This option implies `power_2_buckets<true>` 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<false>`
[endsect] [endsect]
[section:unordered_set_unordered_multiset_example Example] [section:unordered_set_unordered_multiset_example Example]
@@ -1558,8 +1574,9 @@ the size of the node:
* [*`optimize_size<bool Enable>`]: The hook will be optimized for size * [*`optimize_size<bool Enable>`]: The hook will be optimized for size
instead of speed. The hook will embed the balance bits of the AVL 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. tree node in the parent pointer if pointer alignment is multiple of 4.
Optimizing the size will reduce speed performance a bit since masking In some platforms, optimizing the size might reduce speed performance a bit
operations will be needed to access parent pointer and balance factor attributes. 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<false>`. Default: `optimize_size<false>`.
[endsect] [endsect]
@@ -1890,7 +1907,7 @@ and [classref boost::intrusive::unordered_set unordered_set] reference for more
With multiple ordered and unordered associative containers With multiple ordered and unordered associative containers
([classref boost::intrusive::multiset multiset] and ([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. no need for these advanced insertion functions, since insertions are always succesful.
[endsect] [endsect]
@@ -1982,7 +1999,7 @@ The cloning function works as follows:
all the constructed elements are disposed using the disposer function object. 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] [import ../example/doc_clone_from.cpp]
[doc_clone_from] [doc_clone_from]
@@ -2116,7 +2133,7 @@ These hooks support these options:
be inserted container. Additionally, these hooks don't support `unlink()` and be inserted container. Additionally, these hooks don't support `unlink()` and
`swap_nodes()` operations for the same reason. `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]. class in a [classref slist] and the other one in a [classref list].
[import ../example/doc_any_hook.cpp] [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 Instead of using [*Boost.Intrusive] predefined hooks
a user might want to develop customized containers, for example, using nodes that are a user might want to develop customized containers, for example, using nodes that are
optimized for a specific 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 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 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 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] [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 equivalent non-intrusive containers. Memory locality improvements are noticeable
when the objects to be inserted are small. Minimizing memory allocation/deallocation calls is also 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 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 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] [section:release_notes_boost_1_36_00 Boost 1.36 Release]
* Added `linear<>` and `cache_last<>` options to singly linked lists. * 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] [endsect]
[section:acknowledgments Acknowledgements] [section:acknowledgements Acknowledegements]
[*Olaf Krzikalla] would like to thank: [*Olaf Krzikalla] would like to thank:

View File

@@ -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. //This is a container those value is an abstract class: you can't do this with std::list.
typedef list<Window> win_list; typedef list<Window> win_list;
//An static intrusive list declaration //A static intrusive list declaration
static win_list all_windows; static win_list all_windows;
//Constructor. Includes this window in the list //Constructor. Includes this window in the list

View File

@@ -267,6 +267,9 @@
<File <File
RelativePath="..\..\..\..\..\boost\intrusive\detail\utilities.hpp"> RelativePath="..\..\..\..\..\boost\intrusive\detail\utilities.hpp">
</File> </File>
<File
RelativePath="..\..\..\..\..\boost\intrusive\detail\workaround.hpp">
</File>
</Filter> </Filter>
</Filter> </Filter>
<Filter <Filter

3
proj/vc7ide/to-do.txt Normal file
View File

@@ -0,0 +1,3 @@
-> Implement C++0x features (variadic templates & rvalue references)
-> Offer bidirectional iterator for hashtables
-> Non-array buckets

View File

@@ -3,7 +3,7 @@
ProjectType="Visual C++" ProjectType="Visual C++"
Version="7.10" Version="7.10"
Name="unordered_set" Name="unordered_set"
ProjectGUID="{90E701E6-2C91-F4A7-BA6C-A9F3B0949279}" ProjectGUID="{9101EE76-BB6C-2C91-F4B7-A27B94908F19}"
Keyword="Win32Proj"> Keyword="Win32Proj">
<Platforms> <Platforms>
<Platform <Platform
@@ -21,6 +21,7 @@
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="../../../../../" AdditionalIncludeDirectories="../../../../../"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
GeneratePreprocessedFile="0"
MinimalRebuild="TRUE" MinimalRebuild="TRUE"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="5" RuntimeLibrary="5"
@@ -116,7 +117,7 @@
<Filter <Filter
Name="Source Files" Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4F3C77F1-B78A-C745-4726-2D752AA322FF}"> UniqueIdentifier="{4F3C77F1-B78A-C745-4726-252AD75C322E}">
<File <File
RelativePath="..\..\..\test\unordered_set_test.cpp"> RelativePath="..\..\..\test\unordered_set_test.cpp">
</File> </File>

View File

@@ -13,6 +13,9 @@
#include <boost/intrusive/slist.hpp> #include <boost/intrusive/slist.hpp>
#include <boost/intrusive/set.hpp> #include <boost/intrusive/set.hpp>
#include <boost/intrusive/unordered_set.hpp> #include <boost/intrusive/unordered_set.hpp>
#include <boost/intrusive/splay_set.hpp>
#include <boost/intrusive/avl_set.hpp>
#include <boost/intrusive/sg_set.hpp>
#include "smart_ptr.hpp" #include "smart_ptr.hpp"
#include <vector> #include <vector>
@@ -28,6 +31,12 @@ class MyClass
< void_pointer<smart_ptr<void> >, link_mode<normal_link> > < void_pointer<smart_ptr<void> >, link_mode<normal_link> >
, public unordered_set_base_hook , public unordered_set_base_hook
< void_pointer<smart_ptr<void> >, link_mode<normal_link> > < void_pointer<smart_ptr<void> >, link_mode<normal_link> >
, public avl_set_base_hook
< void_pointer<smart_ptr<void> >, link_mode<normal_link> >
, public splay_set_base_hook
< void_pointer<smart_ptr<void> >, link_mode<normal_link> >
, public bs_set_base_hook
< void_pointer<smart_ptr<void> >, link_mode<normal_link> >
{ {
int int_; int int_;
@@ -51,6 +60,9 @@ typedef list<MyClass> List;
typedef slist<MyClass> Slist; typedef slist<MyClass> Slist;
typedef set<MyClass> Set; typedef set<MyClass> Set;
typedef unordered_set<MyClass> USet; typedef unordered_set<MyClass> USet;
typedef avl_set<MyClass> AvlSet;
typedef splay_set<MyClass> SplaySet;
typedef sg_set<MyClass> SgSet;
int main() int main()
{ {
@@ -67,6 +79,9 @@ int main()
Slist my_slist; Slist my_slist;
Set my_set; Set my_set;
USet my_uset(USet::bucket_traits(buckets, 100)); USet my_uset(USet::bucket_traits(buckets, 100));
AvlSet my_avlset;
SplaySet my_splayset;
SgSet my_sgset;
//Now insert them in the reverse order //Now insert them in the reverse order
//in the base hook intrusive list //in the base hook intrusive list
@@ -75,6 +90,9 @@ int main()
my_slist.push_front(*it); my_slist.push_front(*it);
my_set.insert(*it); my_set.insert(*it);
my_uset.insert(*it); my_uset.insert(*it);
my_avlset.insert(*it);
my_splayset.insert(*it);
my_sgset.insert(*it);
} }
//Now test lists //Now test lists
@@ -82,13 +100,24 @@ int main()
List::const_iterator list_it(my_list.cbegin()); List::const_iterator list_it(my_list.cbegin());
Slist::const_iterator slist_it(my_slist.cbegin()); Slist::const_iterator slist_it(my_slist.cbegin());
Set::const_reverse_iterator set_rit(my_set.crbegin()); 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()); VectRit vect_it(values.rbegin()), vect_itend(values.rend());
//Test the objects inserted in the base hook list //Test the objects inserted in the base hook list
for(; vect_it != vect_itend; ++vect_it, ++list_it, ++slist_it, ++set_rit){ for(; vect_it != vect_itend
if(&*list_it != &*vect_it) return 1; ; ++vect_it, ++list_it
if(&*slist_it != &*vect_it) return 1; , ++slist_it, ++set_rit
if(&*set_rit != &*vect_it) return 1; , ++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; if(my_uset.find(*set_rit) == my_uset.cend()) return 1;
} }
} }

View File

@@ -13,6 +13,7 @@
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/list.hpp> #include <boost/intrusive/list.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include "itestvalue.hpp" #include "itestvalue.hpp"
#include "smart_ptr.hpp" #include "smart_ptr.hpp"
@@ -446,13 +447,12 @@ class test_main_template<VoidPointer, false>
> >
>::type >::type
>::test_all(data); >::test_all(data);
/*
test_list<stateful_value_traits // test_list<stateful_value_traits
< value_type // < value_type
, list_node_traits<VoidPointer> // , list_node_traits<VoidPointer>
, safe_link> // , safe_link>
>::test_all(data); // >::test_all(data);
*/
test_list < typename detail::get_base_value_traits test_list < typename detail::get_base_value_traits
< value_type < value_type
, typename value_type::list_auto_base_hook_t , typename value_type::list_auto_base_hook_t
@@ -467,13 +467,13 @@ class test_main_template<VoidPointer, false>
> >
>::type >::type
>::test_all(data); >::test_all(data);
/*
test_list<stateful_value_traits // test_list<stateful_value_traits
< value_type // < value_type
, list_node_traits<VoidPointer> // , list_node_traits<VoidPointer>
, auto_unlink> // , auto_unlink>
>::test_all(data); // >::test_all(data);
*/
return 0; return 0;
} }
}; };
@@ -488,3 +488,285 @@ int main( int, char* [] )
return boost::report_errors(); return boost::report_errors();
} }
#include <boost/intrusive/detail/config_end.hpp> #include <boost/intrusive/detail/config_end.hpp>
/*
#include <cstddef>
////////////////////////////////////////////////////
// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will
// be used to "unpack" into comma-separated values
// in a function call.
////////////////////////////////////////////////////
template<int... Indexes>
struct index_tuple{};
template<std::size_t Num, typename Tuple = index_tuple<> >
struct build_number_seq;
template<std::size_t Num, int... Indexes>
struct build_number_seq<Num, index_tuple<Indexes...> >
: build_number_seq<Num - 1, index_tuple<Indexes..., sizeof...(Indexes)> >
{};
template<int... Indexes>
struct build_number_seq<0, index_tuple<Indexes...> >
{ typedef index_tuple<Indexes...> type; };
template<class ...Types>
struct typelist
{};
template<class T>
struct invert_typelist;
template<int I, typename Tuple>
struct typelist_element;
template<int I, typename Head, typename... Tail>
struct typelist_element<I, typelist<Head, Tail...> >
{
typedef typename typelist_element<I-1, typelist<Tail...> >::type type;
};
template<typename Head, typename... Tail>
struct typelist_element<0, typelist<Head, Tail...> >
{
typedef Head type;
};
template<int ...Ints, class ...Types>
typelist<typename typelist_element<(sizeof...(Types) - 1) - Ints, typelist<Types...> >::type...>
inverted_typelist(index_tuple<Ints...>, typelist<Types...>)
{
return typelist<typename typelist_element<(sizeof...(Types) - 1) - Ints, typelist<Types...> >::type...>();
}
template<class Typelist>
struct sizeof_typelist;
template<class ...Types>
struct sizeof_typelist< typelist<Types...> >
{
static const std::size_t value = sizeof...(Types);
};
//invert_typelist_impl
template<class Typelist, class Indexes>
struct invert_typelist_impl;
template<class Typelist, int ...Ints>
struct invert_typelist_impl< Typelist, index_tuple<Ints...> >
{
static const std::size_t last_idx = sizeof_typelist<Typelist>::value - 1;
typedef typelist
<typename typelist_element<last_idx - Ints, Typelist>::type...> type;
};
template<class Typelist, int Int>
struct invert_typelist_impl< Typelist, index_tuple<Int> >
{
typedef Typelist type;
};
template<class Typelist>
struct invert_typelist_impl< Typelist, index_tuple<> >
{
typedef Typelist type;
};
//invert_typelist
template<class Typelist>
struct invert_typelist;
template<class ...Types>
struct invert_typelist< typelist<Types...> >
{
typedef typelist<Types...> typelist_t;
typedef typename build_number_seq<sizeof...(Types)>::type indexes_t;
typedef typename invert_typelist_impl<typelist_t, indexes_t>::type type;
};
struct none
{
template<class Base>
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<class VoidPointer>
struct void_pointer
{
/// @cond
template<class Base>
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<class Tag>
struct tag
{
/// @cond
template<class Base>
struct pack : Base
{
typedef Tag tag;
};
/// @endcond
};
//!This option setter specifies if the hook
//!should be optimized for size instead of for speed.
template<bool Enabled>
struct optimize_size
{
/// @cond
template<class Base>
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<bool Enabled>
struct linear
{
/// @cond
template<class Base>
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<bool Enabled>
struct cache_last
{
/// @cond
template<class Base>
struct pack : Base
{
static const bool cache_last = Enabled;
};
/// @endcond
};
template<class Typelist>
struct do_pack;
template<>
struct do_pack<typelist<> >;
template<class Prev>
struct do_pack<typelist<Prev> >
{
typedef Prev type;
};
template<class Prev, class Last>
struct do_pack<typelist<Prev, Last> >
{
typedef typename Prev::template pack<Last> type;
};
template<class Prev, class ...Others>
struct do_pack<typelist<Prev, Others...> >
{
typedef typename Prev::template pack
<typename do_pack<typelist<Others...>>::type> type;
};
template<class ...Options>
struct pack_options
{
typedef typelist<Options...> typelist_t;
typedef typename invert_typelist<typelist_t>::type inverted_typelist;
typedef typename do_pack<inverted_typelist>::type type;
};
struct hook_defaults
: public pack_options
< none
, void_pointer<void*>
, tag<int>
, optimize_size<false>
, linear<false>
>::type
{};
#include <iostream>
#include <typeinfo>
struct S
{};
int main()
{
{
typedef typelist<int, float, double> typelist_t;
typedef invert_typelist<typelist_t>::type inverted_typelist;
std::cout << "original: " << typeid(typelist_t).name() << std::endl;
std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl;
}
{
typedef typelist<int> typelist_t;
typedef invert_typelist<typelist_t>::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<typelist_t>::type inverted_typelist;
std::cout << "original: " << typeid(typelist_t).name() << std::endl;
std::cout << "inverted: " << typeid(inverted_typelist).name() << std::endl;
}
{
typedef pack_options<S, none>::type options_t;
std::cout << "options_t " << typeid(options_t).name() << std::endl;
}
{
typedef pack_options<S, none, none>::type options_t;
std::cout << "options_t " << typeid(options_t).name() << std::endl;
}
hook_defaults h;
return 1;
}
*/

View File

@@ -108,7 +108,6 @@ class test_main_template<VoidPointer, false>
int main( int, char* [] ) int main( int, char* [] )
{ {
test_main_template<void*, false>()(); test_main_template<void*, false>()();
test_main_template<boost::intrusive::smart_ptr<void>, false>()(); test_main_template<boost::intrusive::smart_ptr<void>, false>()();
test_main_template<void*, true>()(); test_main_template<void*, true>()();

View File

@@ -18,8 +18,18 @@
namespace boost { namespace intrusive { namespace test { namespace boost { namespace intrusive { namespace test {
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_rebalance<boost::intrusive::sg_multiset<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_rebalance<boost::intrusive::sg_multiset<T,
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
> >
{ {
static const bool value = true; static const bool value = true;
}; };

View File

@@ -17,8 +17,18 @@
namespace boost { namespace intrusive { namespace test { namespace boost { namespace intrusive { namespace test {
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_rebalance<boost::intrusive::sg_set<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_rebalance<boost::intrusive::sg_set<T,
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
> >
{ {
static const bool value = true; static const bool value = true;
}; };

View File

@@ -19,20 +19,51 @@
namespace boost { namespace intrusive { namespace test { namespace boost { namespace intrusive { namespace test {
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_const_overloads<boost::intrusive::splay_multiset<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_const_overloads<boost::intrusive::splay_multiset<
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
T, O1, O2, O3, O4
#else
T, Options...
#endif
>
>
{ {
static const bool value = false; static const bool value = false;
}; };
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_splay<boost::intrusive::splay_multiset<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_splay<boost::intrusive::splay_multiset<T,
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
> >
{ {
static const bool value = true; static const bool value = true;
}; };
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_rebalance<boost::intrusive::splay_multiset<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_rebalance<boost::intrusive::splay_multiset<T,
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
> >
{ {
static const bool value = true; static const bool value = true;
}; };

View File

@@ -17,20 +17,50 @@
namespace boost { namespace intrusive { namespace test { namespace boost { namespace intrusive { namespace test {
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_const_overloads<boost::intrusive::splay_set<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_const_overloads<boost::intrusive::splay_set<T,
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
> >
{ {
static const bool value = false; static const bool value = false;
}; };
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_splay<boost::intrusive::splay_set<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_splay<boost::intrusive::splay_set<T,
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
> >
{ {
static const bool value = true; static const bool value = true;
}; };
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4> template<class T, class O1, class O2, class O3, class O4>
struct has_rebalance<boost::intrusive::splay_set<T, O1, O2, O3, O4> > #else
template<class T, class ...Options>
#endif
struct has_rebalance<boost::intrusive::splay_set<T,
#if !defined (BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
> >
{ {
static const bool value = true; static const bool value = true;
}; };

View File

@@ -15,10 +15,7 @@
#define TEST_INTRUSIVE_SEQUENCE( INTVALUES, ITERATOR )\ #define TEST_INTRUSIVE_SEQUENCE( INTVALUES, ITERATOR )\
{ \ { \
const int init_values_size = sizeof(INTVALUES)/sizeof(INTVALUES[0]); \ BOOST_TEST (std::equal(&INTVALUES[0], &INTVALUES[0] + sizeof(INTVALUES)/sizeof(INTVALUES[0]), ITERATOR) ); \
std::vector<int> expected; \
expected.assign(&INTVALUES[0], &INTVALUES[0] + init_values_size); \
BOOST_TEST (std::equal(expected.begin(), expected.end(), ITERATOR) ); \
} }
#define TEST_INTRUSIVE_SEQUENCE_EXPECTED( EXPECTEDVECTOR, ITERATOR )\ #define TEST_INTRUSIVE_SEQUENCE_EXPECTED( EXPECTEDVECTOR, ITERATOR )\

View File

@@ -25,9 +25,9 @@
using namespace boost::intrusive; using namespace boost::intrusive;
static const std::size_t BucketSize = 11; static const std::size_t BucketSize = 8;
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
struct test_unordered_multiset struct test_unordered_multiset
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
@@ -35,14 +35,16 @@ struct test_unordered_multiset
static void test_sort(std::vector<value_type>& values); static void test_sort(std::vector<value_type>& values);
static void test_insert(std::vector<value_type>& values); static void test_insert(std::vector<value_type>& values);
static void test_swap(std::vector<value_type>& values); static void test_swap(std::vector<value_type>& values);
static void test_rehash(std::vector<value_type>& values); static void test_rehash(std::vector<value_type>& values, detail::true_);
static void test_rehash(std::vector<value_type>& values, detail::false_);
static void test_find(std::vector<value_type>& values); static void test_find(std::vector<value_type>& values);
static void test_impl(); static void test_impl();
static void test_clone(std::vector<value_type>& values); static void test_clone(std::vector<value_type>& values);
}; };
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_all (std::vector<typename ValueTraits::value_type>& values) void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_all (std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset typedef unordered_multiset
@@ -51,6 +53,7 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_all (st
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
{ {
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -71,15 +74,16 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_all (st
test_sort(values); test_sort(values);
test_insert(values); test_insert(values);
test_swap(values); test_swap(values);
test_rehash(values); test_rehash(values, detail::bool_<Incremental>());
test_find(values); test_find(values);
test_impl(); test_impl();
test_clone(values); test_clone(values);
} }
//test case due to an error in tree implementation: //test case due to an error in tree implementation:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_impl() void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>
::test_impl()
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset typedef unordered_multiset
@@ -88,6 +92,7 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_impl()
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -110,8 +115,9 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_impl()
} }
//test: constructor, iterator, clear, reverse_iterator, front, back, size: //test: constructor, iterator, clear, reverse_iterator, front, back, size:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_sort(std::vector<typename ValueTraits::value_type>& values) void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>
::test_sort(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset typedef unordered_multiset
@@ -120,21 +126,29 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_sort(st
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
typename unordered_multiset_type::bucket_type buckets [BucketSize]; typename unordered_multiset_type::bucket_type buckets [BucketSize];
unordered_multiset_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); unordered_multiset_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize));
{ int init_values [] = { 1, 2, 2, 3, 4, 5 }; if(Incremental){
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } { 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(); testset1.clear();
BOOST_TEST (testset1.empty()); BOOST_TEST (testset1.empty());
} }
//test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: //test: insert, const_iterator, const_reverse_iterator, erase, iterator_to:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_insert(std::vector<typename ValueTraits::value_type>& values) void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>
::test_insert(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset typedef unordered_multiset
@@ -143,54 +157,100 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_insert(
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
typedef typename unordered_multiset_type::iterator iterator; typedef typename unordered_multiset_type::iterator iterator;
{ typename unordered_multiset_type::bucket_type buckets [BucketSize];
typename unordered_multiset_type::bucket_type buckets [BucketSize]; unordered_multiset_type testset(bucket_traits(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; const unordered_multiset_type& const_testset = testset;
{ int init_values [] = { 1, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
typename unordered_multiset_type::iterator i = testset.begin(); if(Incremental){
BOOST_TEST (i->value_ == 1); {
{ int init_values [] = { 4, 5, 1 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
i = testset.insert (values[0]); typename unordered_multiset_type::iterator i = testset.begin();
BOOST_TEST (&*i == &values[0]); BOOST_TEST (i->value_ == 4);
i = testset.iterator_to (values[2]);
BOOST_TEST (&*i == &values[2]);
testset.erase(i);
{ int init_values [] = { 1, 3, 5 }; i = testset.insert (values[0]);
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } BOOST_TEST (&*i == &values[0]);
testset.clear();
testset.insert(&values[0], &values[0] + values.size()); i = testset.iterator_to (values[2]);
BOOST_TEST (&*i == &values[2]);
testset.erase(i);
{ int init_values [] = { 1, 2, 2, 3, 4, 5 }; { int init_values [] = { 5, 1, 3 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
testset.clear();
testset.insert(&values[0], &values[0] + values.size());
BOOST_TEST (testset.erase(1) == 1); { int init_values [] = { 4, 5, 1, 2, 2, 3 };
BOOST_TEST (testset.erase(2) == 2); TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
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 BOOST_TEST (testset.erase(1) == 1);
typename unordered_multiset_type::bucket_type single_bucket[1]; BOOST_TEST (testset.erase(2) == 2);
unordered_multiset_type testset2(bucket_traits(single_bucket, 1)); BOOST_TEST (testset.erase(3) == 1);
testset2.insert(&values[0], &values[0] + values.size()); BOOST_TEST (testset.erase(4) == 1);
BOOST_TEST (testset2.erase(5) == 1); BOOST_TEST (testset.erase(5) == 1);
BOOST_TEST (testset2.erase(2) == 2); BOOST_TEST (testset.empty() == true);
BOOST_TEST (testset2.erase(1) == 1);
BOOST_TEST (testset2.erase(4) == 1); //Now with a single bucket
BOOST_TEST (testset2.erase(3) == 1); typename unordered_multiset_type::bucket_type single_bucket[1];
BOOST_TEST (testset2.empty() == true); 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 //Now erase just one per loop
@@ -270,11 +330,12 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_insert(
} }
} }
} }
} }
//test: insert (seq-version), swap, erase (seq-version), size: //test: insert (seq-version), swap, erase (seq-version), size:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_swap(std::vector<typename ValueTraits::value_type>& values) void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_swap(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset typedef unordered_multiset
@@ -283,17 +344,30 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_swap(st
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
typename unordered_multiset_type::bucket_type buckets [BucketSize]; 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); typename unordered_multiset_type::bucket_type buckets2 [BucketSize];
testset1.swap (testset2); 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 }; { int init_values [] = { 1, 2, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
@@ -306,9 +380,13 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_swap(st
} }
} }
//test: rehash: //test: rehash:
template<class ValueTraits, bool CacheBegin, bool CompareHash>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_rehash(std::vector<typename ValueTraits::value_type>& values) template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>
::test_rehash(std::vector<typename ValueTraits::value_type>& values, detail::true_)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset typedef unordered_multiset
@@ -317,6 +395,135 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_rehash(
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<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<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>
::test_rehash(std::vector<typename ValueTraits::value_type>& values, detail::false_)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
, compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -325,36 +532,37 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_rehash(
typename unordered_multiset_type::bucket_type buckets3 [BucketSize*2]; typename unordered_multiset_type::bucket_type buckets3 [BucketSize*2];
unordered_multiset_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); 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 }; { int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
testset1.rehash(bucket_traits(buckets2, 2)); 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 }; { int init_values [] = { 4, 2, 2, 5, 3, 1 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
testset1.rehash(bucket_traits(buckets3, BucketSize*2)); 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 }; { int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
//Now rehash reducing the buckets //Now rehash reducing the buckets
testset1.rehash(bucket_traits(buckets3, 2)); 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 }; { int init_values [] = { 4, 2, 2, 5, 3, 1 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
//Now rehash increasing the buckets //Now rehash increasing the buckets
testset1.rehash(bucket_traits(buckets3, BucketSize*2)); 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 }; { int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
} }
//test: find, equal_range (lower_bound, upper_bound): //test: find, equal_range (lower_bound, upper_bound):
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_find(std::vector<typename ValueTraits::value_type>& values) void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_find(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset typedef unordered_multiset
@@ -363,6 +571,7 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_find(st
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -387,8 +596,8 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>::test_find(st
} }
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash> void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash, Incremental>
::test_clone(std::vector<typename ValueTraits::value_type>& values) ::test_clone(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
@@ -398,6 +607,7 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_multiset_type; > unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits; typedef typename unordered_multiset_type::bucket_traits bucket_traits;
{ {
@@ -442,7 +652,7 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>
unordered_multiset_type testset2 (bucket_traits(buckets2, BucketSize*2)); unordered_multiset_type testset2 (bucket_traits(buckets2, BucketSize*2));
testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>()); testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
//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<typename ValueTraits::value_type> std::multiset<typename ValueTraits::value_type>
src(testset1.begin(), testset1.end()); src(testset1.begin(), testset1.end());
std::multiset<typename ValueTraits::value_type> std::multiset<typename ValueTraits::value_type>
@@ -453,7 +663,7 @@ void test_unordered_multiset<ValueTraits, CacheBegin, CompareHash>
} }
} }
template<class VoidPointer, bool constant_time_size> template<class VoidPointer, bool constant_time_size, bool Incremental>
class test_main_template class test_main_template
{ {
public: public:
@@ -471,6 +681,7 @@ class test_main_template
>::type >::type
, true , true
, false , false
, Incremental
>::test_all(data); >::test_all(data);
test_unordered_multiset < typename detail::get_member_value_traits test_unordered_multiset < typename detail::get_member_value_traits
@@ -482,14 +693,15 @@ class test_main_template
>::type >::type
, false , false
, false , false
, Incremental
>::test_all(data); >::test_all(data);
return 0; return 0;
} }
}; };
template<class VoidPointer> template<class VoidPointer, bool Incremental>
class test_main_template<VoidPointer, false> class test_main_template<VoidPointer, false, Incremental>
{ {
public: public:
int operator()() int operator()()
@@ -506,6 +718,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, true , true
, false , false
, Incremental
>::test_all(data); >::test_all(data);
test_unordered_multiset < typename detail::get_member_value_traits test_unordered_multiset < typename detail::get_member_value_traits
@@ -517,6 +730,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, false , false
, false , false
, Incremental
>::test_all(data); >::test_all(data);
test_unordered_multiset < typename detail::get_base_value_traits test_unordered_multiset < typename detail::get_base_value_traits
@@ -525,6 +739,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, true , true
, true , true
, Incremental
>::test_all(data); >::test_all(data);
test_unordered_multiset < typename detail::get_member_value_traits test_unordered_multiset < typename detail::get_member_value_traits
@@ -536,6 +751,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, false , false
, true , true
, Incremental
>::test_all(data); >::test_all(data);
return 0; return 0;
} }
@@ -543,10 +759,14 @@ class test_main_template<VoidPointer, false>
int main( int, char* [] ) int main( int, char* [] )
{ {
test_main_template<void*, false>()(); test_main_template<void*, false, true>()();
test_main_template<smart_ptr<void>, false>()(); test_main_template<smart_ptr<void>, false, true>()();
test_main_template<void*, true>()(); test_main_template<void*, true, true>()();
test_main_template<smart_ptr<void>, true>()(); test_main_template<smart_ptr<void>, true, true>()();
test_main_template<void*, false, false>()();
test_main_template<smart_ptr<void>, false, false>()();
test_main_template<void*, true, true>()();
test_main_template<smart_ptr<void>, true, false>()();
return boost::report_errors(); return boost::report_errors();
} }

View File

@@ -24,9 +24,9 @@
using namespace boost::intrusive; using namespace boost::intrusive;
static const std::size_t BucketSize = 11; static const std::size_t BucketSize = 8;
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
struct test_unordered_set struct test_unordered_set
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
@@ -34,14 +34,16 @@ struct test_unordered_set
static void test_sort(std::vector<value_type>& values); static void test_sort(std::vector<value_type>& values);
static void test_insert(std::vector<value_type>& values); static void test_insert(std::vector<value_type>& values);
static void test_swap(std::vector<value_type>& values); static void test_swap(std::vector<value_type>& values);
static void test_rehash(std::vector<value_type>& values); static void test_rehash(std::vector<value_type>& values, detail::true_);
static void test_rehash(std::vector<value_type>& values, detail::false_);
static void test_find(std::vector<value_type>& values); static void test_find(std::vector<value_type>& values);
static void test_impl(); static void test_impl();
static void test_clone(std::vector<value_type>& values); static void test_clone(std::vector<value_type>& values);
}; };
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_all(std::vector<typename ValueTraits::value_type>& values) void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_all(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_set typedef unordered_set
@@ -50,6 +52,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_all(std::vec
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
{ {
@@ -70,15 +73,15 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_all(std::vec
test_sort(values); test_sort(values);
test_insert(values); test_insert(values);
test_swap(values); test_swap(values);
test_rehash(values); test_rehash(values, detail::bool_<Incremental>());
test_find(values); test_find(values);
test_impl(); test_impl();
test_clone(values); test_clone(values);
} }
//test case due to an error in tree implementation: //test case due to an error in tree implementation:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_impl() void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::test_impl()
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_set typedef unordered_set
@@ -87,6 +90,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_impl()
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -107,8 +111,9 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_impl()
} }
//test: constructor, iterator, clear, reverse_iterator, front, back, size: //test: constructor, iterator, clear, reverse_iterator, front, back, size:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_sort(std::vector<typename ValueTraits::value_type>& values) void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_sort(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_set typedef unordered_set
@@ -117,23 +122,31 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_sort(std::ve
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
typename unordered_set_type::bucket_type buckets [BucketSize]; typename unordered_set_type::bucket_type buckets [BucketSize];
unordered_set_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); unordered_set_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize));
BOOST_TEST (5 == std::distance(testset1.begin(), testset1.end())); 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(); testset1.clear();
BOOST_TEST (testset1.empty()); BOOST_TEST (testset1.empty());
} }
//test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: //test: insert, const_iterator, const_reverse_iterator, erase, iterator_to:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_insert(std::vector<typename ValueTraits::value_type>& values) void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_insert(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_set typedef unordered_set
@@ -142,6 +155,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_insert(std::
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -150,27 +164,47 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_insert(std::
testset.insert(&values[0] + 2, &values[0] + 5); testset.insert(&values[0] + 2, &values[0] + 5);
const unordered_set_type& const_testset = testset; const unordered_set_type& const_testset = testset;
{ int init_values [] = { 1, 4, 5 }; if(Incremental)
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } {
{ 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(); i = testset.insert(values[0]).first;
BOOST_TEST (i->value_ == 1); BOOST_TEST (&*i == &values[0]);
i = testset.insert(values[0]).first; i = testset.iterator_to (values[2]);
BOOST_TEST (&*i == &values[0]); BOOST_TEST (&*i == &values[2]);
i = testset.iterator_to (values[2]); testset.erase (i);
BOOST_TEST (&*i == &values[2]);
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 }; i = testset.insert(values[0]).first;
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } 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: //test: insert (seq-version), swap, erase (seq-version), size:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_swap(std::vector<typename ValueTraits::value_type>& values) void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_swap(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_set typedef unordered_set
@@ -179,6 +213,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_swap(std::ve
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -190,20 +225,30 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_swap(std::ve
testset2.insert (&values[0] + 2, &values[0] + 6); testset2.insert (&values[0] + 2, &values[0] + 6);
testset1.swap (testset2); 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() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
{ int init_values [] = { 2, 3 }; { int init_values [] = { 2, 3 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); }
testset1.erase (testset1.iterator_to(values[5]), testset1.end());
testset1.erase (testset1.iterator_to(values[5]), testset1.end()); BOOST_TEST (testset1.size() == 1);
BOOST_TEST (testset1.size() == 1); BOOST_TEST (&*testset1.begin() == &values[3]);
// BOOST_TEST (&testset1.front() == &values[3]); }
BOOST_TEST (&*testset1.begin() == &values[3]);
} }
//test: rehash: //test: rehash:
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_rehash(std::vector<typename ValueTraits::value_type>& values) void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_rehash(std::vector<typename ValueTraits::value_type>& values, detail::true_)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_set typedef unordered_set
@@ -212,6 +257,137 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_rehash(std::
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<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<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_rehash(std::vector<typename ValueTraits::value_type>& values, detail::false_)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
, compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -220,37 +396,38 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_rehash(std::
typename unordered_set_type::bucket_type buckets3 [BucketSize*2]; typename unordered_set_type::bucket_type buckets3 [BucketSize*2];
unordered_set_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); 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 }; { int init_values [] = { 1, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
testset1.rehash(bucket_traits(buckets2, 2)); 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 }; { int init_values [] = { 4, 2, 5, 3, 1 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
testset1.rehash(bucket_traits(buckets3, BucketSize*2)); 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 }; { int init_values [] = { 1, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
//Now rehash reducing the buckets //Now rehash reducing the buckets
testset1.rehash(bucket_traits(buckets3, 2)); 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 }; { int init_values [] = { 4, 2, 5, 3, 1 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
//Now rehash increasing the buckets //Now rehash increasing the buckets
testset1.rehash(bucket_traits(buckets3, BucketSize*2)); 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 }; { int init_values [] = { 1, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); }
} }
//test: find, equal_range (lower_bound, upper_bound): //test: find, equal_range (lower_bound, upper_bound):
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_find(std::vector<typename ValueTraits::value_type>& values) void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>::
test_find(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef unordered_set typedef unordered_set
@@ -259,6 +436,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_find(std::ve
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -281,8 +459,8 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>::test_find(std::ve
BOOST_TEST (testset.find (cmp_val) == testset.end()); BOOST_TEST (testset.find (cmp_val) == testset.end());
} }
template<class ValueTraits, bool CacheBegin, bool CompareHash> template<class ValueTraits, bool CacheBegin, bool CompareHash, bool Incremental>
void test_unordered_set<ValueTraits, CacheBegin, CompareHash> void test_unordered_set<ValueTraits, CacheBegin, CompareHash, Incremental>
::test_clone(std::vector<typename ValueTraits::value_type>& values) ::test_clone(std::vector<typename ValueTraits::value_type>& values)
{ {
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
@@ -292,6 +470,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>
, constant_time_size<value_type::constant_time_size> , constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin> , cache_begin<CacheBegin>
, compare_hash<CompareHash> , compare_hash<CompareHash>
, incremental<Incremental>
> unordered_set_type; > unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits; typedef typename unordered_set_type::bucket_traits bucket_traits;
{ {
@@ -319,7 +498,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>
unordered_set_type testset2 (bucket_traits(buckets2, BucketSize)); unordered_set_type testset2 (bucket_traits(buckets2, BucketSize));
testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>()); testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
//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<typename ValueTraits::value_type> std::set<typename ValueTraits::value_type>
src(testset1.begin(), testset1.end()); src(testset1.begin(), testset1.end());
std::set<typename ValueTraits::value_type> std::set<typename ValueTraits::value_type>
@@ -347,7 +526,7 @@ void test_unordered_set<ValueTraits, CacheBegin, CompareHash>
} }
} }
template<class VoidPointer, bool constant_time_size> template<class VoidPointer, bool constant_time_size, bool incremental>
class test_main_template class test_main_template
{ {
public: public:
@@ -365,6 +544,7 @@ class test_main_template
>::type >::type
, true , true
, false , false
, incremental
>::test_all(data); >::test_all(data);
test_unordered_set < typename detail::get_member_value_traits test_unordered_set < typename detail::get_member_value_traits
< value_type < value_type
@@ -375,14 +555,15 @@ class test_main_template
>::type >::type
, false , false
, false , false
, incremental
>::test_all(data); >::test_all(data);
return 0; return 0;
} }
}; };
template<class VoidPointer> template<class VoidPointer, bool incremental>
class test_main_template<VoidPointer, false> class test_main_template<VoidPointer, false, incremental>
{ {
public: public:
int operator()() int operator()()
@@ -399,6 +580,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, true , true
, false , false
, incremental
>::test_all(data); >::test_all(data);
test_unordered_set < typename detail::get_member_value_traits test_unordered_set < typename detail::get_member_value_traits
@@ -410,6 +592,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, false , false
, false , false
, incremental
>::test_all(data); >::test_all(data);
test_unordered_set < typename detail::get_base_value_traits test_unordered_set < typename detail::get_base_value_traits
@@ -418,6 +601,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, true , true
, true , true
, incremental
>::test_all(data); >::test_all(data);
test_unordered_set < typename detail::get_member_value_traits test_unordered_set < typename detail::get_member_value_traits
@@ -429,6 +613,7 @@ class test_main_template<VoidPointer, false>
>::type >::type
, false , false
, true , true
, incremental
>::test_all(data); >::test_all(data);
return 0; return 0;
} }
@@ -436,10 +621,14 @@ class test_main_template<VoidPointer, false>
int main( int, char* [] ) int main( int, char* [] )
{ {
test_main_template<void*, false>()(); test_main_template<void*, false, true>()();
test_main_template<smart_ptr<void>, false>()(); test_main_template<smart_ptr<void>, false, true>()();
test_main_template<void*, true>()(); test_main_template<void*, true, true>()();
test_main_template<smart_ptr<void>, true>()(); test_main_template<smart_ptr<void>, true, true>()();
test_main_template<void*, false, false>()();
test_main_template<smart_ptr<void>, false, false>()();
test_main_template<void*, true, true>()();
test_main_template<smart_ptr<void>, true, false>()();
return boost::report_errors(); return boost::report_errors();
} }
#include <boost/intrusive/detail/config_end.hpp> #include <boost/intrusive/detail/config_end.hpp>