diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 90f8c2b..d4f878d 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -21,19 +21,18 @@ doxygen autodoc EXTRACT_PRIVATE=NO ENABLE_PREPROCESSING=YES MACRO_EXPANSION=YES -# EXPAND_ONLY_PREDEF=YES -# SEARCH_INCLUDES=YES -# INCLUDE_PATH=$(BOOST_ROOT) - "PREDEFINED=\"BOOST_INTRUSIVE_DOXYGEN_INVOKED\" \\ - \"list_impl=list\" \\ - \"slist_impl=slist\" \\ - \"set_impl=set\" \\ - \"multiset_impl=multiset\" \\ - \"rbtree_impl=rbtree\" \\ - \"unordered_set_impl=unordered_set\" \\ - \"unordered_multiset_impl=unordered_multiset\" \\ - \"hashtable_impl=hashtable\" \\ - " + "PREDEFINED=BOOST_INTRUSIVE_DOXYGEN_INVOKED \\ + "list_impl=list" \\ + "slist_impl=slist" \\ + "set_impl=set" \\ + "multiset_impl=multiset" \\ + "rbtree_impl=rbtree" \\ + "unordered_set_impl=unordered_set" \\ + "unordered_multiset_impl=unordered_multiset" \\ + "hashtable_impl=hashtable" \\ + "splay_set_impl=splay_set" \\ + "splay_multiset_impl=splay_multiset" \\ + "splaytree_impl=splaytree"" ; xml intrusive : intrusive.qbk ; diff --git a/doc/html/images/blank.png b/doc/html/images/blank.png index 764bf4f..c387d42 100644 Binary files a/doc/html/images/blank.png and b/doc/html/images/blank.png differ diff --git a/doc/html/images/caution.png b/doc/html/images/caution.png index 5b7809c..b056bcc 100644 Binary files a/doc/html/images/caution.png and b/doc/html/images/caution.png differ diff --git a/doc/html/images/draft.png b/doc/html/images/draft.png index 0084708..c99e091 100644 Binary files a/doc/html/images/draft.png and b/doc/html/images/draft.png differ diff --git a/doc/html/images/home.png b/doc/html/images/home.png index 5584aac..04cc7bd 100644 Binary files a/doc/html/images/home.png and b/doc/html/images/home.png differ diff --git a/doc/html/images/important.png b/doc/html/images/important.png index 12c90f6..e257957 100644 Binary files a/doc/html/images/important.png and b/doc/html/images/important.png differ diff --git a/doc/html/images/next.png b/doc/html/images/next.png index 59800b4..f9f1081 100644 Binary files a/doc/html/images/next.png and b/doc/html/images/next.png differ diff --git a/doc/html/images/note.png b/doc/html/images/note.png index d0c3c64..28195ae 100644 Binary files a/doc/html/images/note.png and b/doc/html/images/note.png differ diff --git a/doc/html/images/prev.png b/doc/html/images/prev.png index d88a40f..22b8ac2 100644 Binary files a/doc/html/images/prev.png and b/doc/html/images/prev.png differ diff --git a/doc/html/images/tip.png b/doc/html/images/tip.png index 5c4aab3..07ef20f 100644 Binary files a/doc/html/images/tip.png and b/doc/html/images/tip.png differ diff --git a/doc/html/images/toc-blank.png b/doc/html/images/toc-blank.png index 6ffad17..75b24d6 100644 Binary files a/doc/html/images/toc-blank.png and b/doc/html/images/toc-blank.png differ diff --git a/doc/html/images/toc-minus.png b/doc/html/images/toc-minus.png index abbb020..7a8a274 100644 Binary files a/doc/html/images/toc-minus.png and b/doc/html/images/toc-minus.png differ diff --git a/doc/html/images/toc-plus.png b/doc/html/images/toc-plus.png index 941312c..29fada2 100644 Binary files a/doc/html/images/toc-plus.png and b/doc/html/images/toc-plus.png differ diff --git a/doc/html/images/warning.png b/doc/html/images/warning.png index 1c33db8..74fc1ba 100644 Binary files a/doc/html/images/warning.png and b/doc/html/images/warning.png differ diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 56d395f..f7cef4d 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -788,7 +788,7 @@ Like the rest of [*Boost.Intrusive] containers, the section [link intrusive.usage How to use Boost.Intrusive]: * [*`tag`] (for base hooks only): This argument serves as a tag, - so you can derive from more than one list hook. + so you can derive from more than one slist hook. Default: `tag`. * [*`link_mode`]: The linking policy. @@ -920,29 +920,38 @@ Now let's see an small example using both hooks: [endsect] -[section:set_multiset Intrusive associative containers: set, multiset] +[section:set_multiset Intrusive associative containers: set, multiset, rbtree] [*Boost.Intrusive] also offers associative containers that can be very useful when creating more complex associative containers, like containers maintaining -one or more indices with different sorting semantics. -The memory overhead of these containers is usually 3 pointers and an integer. If -pointers have 2 byte alignment (which is usually true in most systems), -[*Boost.Intrusive] optimizes this overhead to 3 pointers. +one or more indices with different sorting semantics. Boost.Intrusive associative +containers, like most STL associative container implemenatations are based on +red-black trees. -An empty, non constant-time size [classref boost::intrusive::set set] or -[classref boost::intrusive::multiset multiset] -has also the size of 3 pointers and an integer (3 pointers when optimized). -[classref boost::intrusive::set set] and -[classref boost::intrusive::multiset multiset] have logarithmic complexity in many +The memory overhead of these containers is usually 3 pointers and an integer. +This size can be reduced to 3 pointers if pointers have even alignment +(which is usually true in most systems). + +An empty, non constant-time size [classref boost::intrusive::set set], +[classref boost::intrusive::multiset multiset] or +[classref boost::intrusive::rbtree rbtree] +has also the size of 3 pointers and an integer (3 pointers when optimized for size). +These containers have logarithmic complexity in many operations like searches, insertions, erasures, etc... [classref boost::intrusive::set set] and [classref boost::intrusive::multiset multiset] are the intrusive equivalents of standard `std::set` and `std::multiset` containers. -[section:set_multiset_hooks set and multiset hooks] - +[classref boost::intrusive::rbtree rbtree] is a superset of [classref boost::intrusive::set set] and -[classref boost::intrusive::multiset multiset] share the same hooks. +[classref boost::intrusive::multiset multiset] containers that offers +functions to insert unique and multiple keys. + +[section:set_multiset_hooks set, multiset and rbtree hooks] + +[classref boost::intrusive::set set], +[classref boost::intrusive::multiset multiset] and +[classref boost::intrusive::rbtree rbtree] share the same hooks. This is an advantage, because the same user type can be inserted first in a [classref boost::intrusive::multiset multiset] and after that in [classref boost::intrusive::set set] without @@ -971,10 +980,10 @@ changing the definition of the user class. [classref boost::intrusive::set_base_hook set_base_hook] and [classref boost::intrusive::set_member_hook set_member_hook] receive the same options explained in the section -[link intrusive.usage How to use Boost.Intrusive]: +[link intrusive.usage How to use Boost.Intrusive] plus a size optimization option: * [*`tag`] (for base hooks only): This argument serves as a tag, - so you can derive from more than one list hook. + so you can derive from more than one base hook. Default: `tag`. * [*`link_mode`]: The linking policy. @@ -984,9 +993,16 @@ the same options explained in the section internally in the hook and propagated to the container. Default: `void_pointer`. +* [*`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. + Default: `optimize_size`. + [endsect] -[section:set_multiset_containers set and multiset containers] +[section:set_multiset_containers set, multiset and rbtree containers] [c++] @@ -996,8 +1012,11 @@ the same options explained in the section template class multiset; -[classref boost::intrusive::set set] and [classref boost::intrusive::multiset multiset] -receive the same options explained in the section [link intrusive.usage How to use Boost.Intrusive]: + template + class rbtree; + +These containers receive the same options explained in the section +[link intrusive.usage How to use Boost.Intrusive]: * [*`base_hook`] / [*`member_hook`] / [*`value_traits`]: To specify the hook type or value traits used @@ -1110,7 +1129,7 @@ the same options explained in the section [link intrusive.usage How to use Boost.Intrusive]: * [*`tag`] (for base hooks only): This argument serves as a tag, - so you can derive from more than one list hook. + so you can derive from more than one base hook. Default: `tag`. * [*`link_mode`]: The linking policy. @@ -1240,6 +1259,142 @@ the unordered container: [endsect] +[section:splay_set_multiset Intrusive splay tree-based associative containers: splay_set, splay_multiset] + +C++ associative containers are usually based on red-black tree implementations (e.g.: STL, +Boost.Intrusive associative containers). However, there are other interesting data structures +that offer some advantages (and also disadvantages). + +Splay trees are self-adjusting binary search trees used tipically in caches, memory +allocators and other applications, because splay trees have a "caching effect": recently +accessed elements have better access times that elements accessed less frequently. +For more information on splay trees see [@http://en.wikipedia.org/wiki/Splay_tree Wikipedia]. + +[*Boost.Intrusive] offers 3 containers based on splay trees: +[classref boost::intrusive::splay_set splay_set], +[classref boost::intrusive::splay_multiset splay_multiset] and +[classref boost::intrusive::splaytree splaytree]. The first two are similar to +[classref boost::intrusive::set set] or +[classref boost::intrusive::multiset multiset] and the latter is a generalization +that offers functions both to insert unique and multiple keys. + +The memory overhead of these containers with Boost.Intrusive hooks is usually 3 pointers. +An empty, non constant-time size splay container has also the size of 3 pointers. + +[section:splay_set_multiset_disadvantages Advantages and disadvantages of splay tree based containers] + +Splay tree based intrusive containers have logarithmic complexity in many +operations like searches, insertions, erasures, etc... but if some elements are +more frequently accessed than others, splay trees perform faster searches than equivalent +balanced binary trees (such as red-black trees). + +The caching effect offered by splay trees comes with a cost: the tree must be +rebalanced when a element is searched. This disallows const versions of search +functions like `find()`, `lower_bound()`, `upper_bound()`, `equal_range()`, +`count()`... + +Because of this, splay-tree based associative containers are not drop-in +replacements of [classref boost::intrusive::set set]/ +[classref boost::intrusive::splay_set splay_set]. + +Apart from this, if element searches are randomized, the tree will be rebalanced +without taking advantage of the cache effect, so splay trees can offer worse +performance than other balanced trees for some search patterns. + +[endsect] + +[section:splay_set_multiset_hooks splay_set, splay_multiset and splaytree hooks] + +[classref boost::intrusive::set set], +[classref boost::intrusive::multiset multiset] and +[classref boost::intrusive::splaytree splaytree] +share the same hooks. + +[c++] + + template + class splay_set_base_hook; + +* [classref boost::intrusive::splay_set_base_hook splay_set_base_hook]: + the user class derives publicly from this class to make + it compatible with splay tree based containers. + +[c++] + + template + class splay_set_member_hook; + +* [classref boost::intrusive::set_member_hook set_member_hook]: + the user class contains a public member of this class to make + it compatible with splay tree based containers. + +[classref boost::intrusive::splay_set_base_hook splay_set_base_hook] and +[classref boost::intrusive::splay_set_member_hook splay_set_member_hook] receive +the same options explained in the section +[link intrusive.usage How to use Boost.Intrusive]: + +* [*`tag`] (for base hooks only): This argument serves as a tag, + so you can derive from more than one base hook. + Default: `tag`. + +* [*`link_mode`]: The linking policy. + Default: `link_mode`. + +* [*`void_pointer`]: The pointer type to be used + internally in the hook and propagated to the container. + Default: `void_pointer`. + +[endsect] + +[section:set_multiset_containers splay_set, splay_multiset and splaytree containers] + +[c++] + + template + class splay_set; + + template + class splay_multiset; + + template + class splaytree; + +These containers receive the same options explained in the section +[link intrusive.usage How to use Boost.Intrusive]: + +* [*`base_hook`] / [*`member_hook`] / + [*`value_traits`]: To specify the hook type or value traits used + to configure the container (to know about value traits go to the section + titled [link intrusive.value_traits Containers with custom ValueTraits]. + +* [*`constant_time_size`]: To activate the constant-time `size()` operation. + Default: `constant_time_size` + +* [*`size_type`]: To specify the type that will be used to store the size + of the container. Default: `size_type` + +And they also can receive an additional option: + +* [*`compare`]: Comparison function for the objects to be inserted + in containers. The comparison functor must induce a strict weak ordering. + Default: `compare< std::less >` + +[endsect] + +[section:splay_set_multiset_example Example] + +Now let's see an small example using both hooks and +[classref boost::intrusive::splay_set splay_set]/ +[classref boost::intrusive::splay_multiset splay_multiset] +containers: + +[import ../example/doc_splay_set.cpp] +[doc_splay_set_code] + +[endsect] + +[endsect] + [section:advanced_lookups_insertions Advanced lookup and insertion functions for associative containers] [section:advanced_lookups Advanced lookups] @@ -1520,7 +1675,7 @@ On the other hand, `local_iterator_to` functions have their `s_local_iterator_to` static alternatives. Alternative static functions are available under certain circunstances -explained in the [link: stateful_value_traits Stateful value traits] section, +explained in the [link intrusive.value_traits.stateful_value_traits Stateful value traits] section, but the programmer uses hooks provided by [*Boost.Intrusive], those functions will be available. @@ -1906,6 +2061,66 @@ For a complete rbtree of functions see [endsect] +[section:splaytree_algorithms Intrusive splay tree algorithms] + +These algorithms are static +members of the [classref boost::intrusive::rbtree_algorithms splaytree_algorithms] class: + +[c++] + + template + struct splaytree_algorithms; + + +An empty tree is formed by a node whose pointer to the parent node is null, +the pointers to the left and right nodes to itself. +[classref boost::intrusive::splaytree_algorithms rbtree_algorithms] +is configured with a NodeTraits class, which encapsulates +the information about the node to be manipulated. NodeTraits must support the +following interface: + +[*Typedefs]: + +* `node`: The type of the node that forms the circular rbtree + +* `node_ptr`: The type of a pointer to a node (usually node*) + +* `const_node_ptr`: The type of a pointer to a const node (usually const node*) + +[*Static functions]: + +* `static node_ptr get_parent(const_node_ptr n);`: + Returns a pointer to the parent node stored in "n". + +* `static void set_parent(node_ptr n, node_ptr p);`: + Sets the pointer to the parent node stored in "n" to "p". + +* `static node_ptr get_left(const_node_ptr n);`: + Returns a pointer to the left node stored in "n". + +* `static void set_left(node_ptr n, node_ptr l);`: + Sets the pointer to the left node stored in "n" to "l". + +* `static node_ptr get_right(const_node_ptr n);`: + Returns a pointer to the right node stored in "n". + +* `static void set_right(node_ptr n, node_ptr r);`: + Sets the pointer to the right node stored in "n" to "r". + +* `static color get_color(const_node_ptr n);`: + Returns the color stored in "n". + +Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms +with our nodes: + +[import ../example/doc_splaytree_algorithms.cpp] +[doc_splaytree_algorithms_code] + +For a complete rbtree of functions see +[classref boost::intrusive::splaytree_algorithms splaytree_algorithms reference]. + +[endsect] + [endsect] [section:value_traits Containers with custom ValueTraits] @@ -2724,6 +2939,18 @@ exception handling in the library. [endsect] +[section:references References] + +* SGI's [@http://www.sgi.com/tech/stl/ STL Programmer's Guide]. + [*Boost.Intrusive] is based on STL concepts and interface. + +* Dr. Dobb's, September 1, 2005: [@http://www.ddj.com/architect/184402007 ['Implementing Splay Trees in C++] ]. + [*Boost.Intrusive] splay containers code is based on this article. + +* Olaf's original intrusive container library: [@http://freenet-homepage.de/turtle++/intrusive.html ['STL-like intrusive containers] ]. + +[endsect] + [section:acknowledgments Acknowledgements] [*Olaf Krzikalla] would like to thank: diff --git a/example/doc_rbtree_algorithms.cpp b/example/doc_rbtree_algorithms.cpp index 7867668..6eb25fb 100644 --- a/example/doc_rbtree_algorithms.cpp +++ b/example/doc_rbtree_algorithms.cpp @@ -73,10 +73,10 @@ int main() assert(n == &three); //Erase a node just using a pointer to it - algo::unlink_and_rebalance(n); + algo::unlink(&two); //Erase a node using also the header (faster) - algo::erase(&header, n); + algo::erase(&header, &three); return 0; } diff --git a/example/doc_set.cpp b/example/doc_set.cpp index 6180e8b..7a4bcd6 100644 --- a/example/doc_set.cpp +++ b/example/doc_set.cpp @@ -13,11 +13,12 @@ #include #include #include +#include using namespace boost::intrusive; - //This is a base hook -class MyClass : public set_base_hook<> + //This is a base hook optimized for size +class MyClass : public set_base_hook > { int int_; @@ -41,7 +42,7 @@ typedef set< MyClass, compare > > BaseSet; //Define an multiset using the member hook typedef member_hook, &MyClass::member_hook_> MemberOption; -typedef multiset< MyClass, MemberOption> MemberIMultiset; +typedef multiset< MyClass, MemberOption> MemberMultiset; int main() { @@ -53,7 +54,12 @@ int main() for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); BaseSet baseset; - MemberIMultiset membermultiset; + MemberMultiset membermultiset; + + //Check that size optimization is activated in the base hook + assert(sizeof(set_base_hook >) == 3*sizeof(void*)); + //Check that size optimization is deactivated in the member hook + assert(sizeof(set_member_hook<>) > 3*sizeof(void*)); //Now insert them in the reverse order in the base hook set for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) @@ -66,7 +72,7 @@ int main() //Now test sets { BaseSet::reverse_iterator rbit(baseset.rbegin()), rbitend(baseset.rend()); - MemberIMultiset::iterator mit(membermultiset.begin()), mitend(membermultiset.end()); + MemberMultiset::iterator mit(membermultiset.begin()), mitend(membermultiset.end()); VectIt it(values.begin()), itend(values.end()); //Test the objects inserted in the base hook set diff --git a/example/doc_splay_algorithms.cpp b/example/doc_splay_algorithms.cpp new file mode 100644 index 0000000..5f929fa --- /dev/null +++ b/example/doc_splay_algorithms.cpp @@ -0,0 +1,79 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_splaytree_algorithms_code +#include +#include + +struct my_node +{ + my_node(int i = 0) + : int_(i) + {} + my_node *parent_, *left_, *right_; + int color_; + //other members + int int_; +}; + +//Define our own splaytree_node_traits +struct my_splaytree_node_traits +{ + typedef my_node node; + typedef my_node * node_ptr; + typedef const my_node * const_node_ptr; + + static node_ptr get_parent(const_node_ptr n) { return n->parent_; } + static void set_parent(node_ptr n, node_ptr parent){ n->parent_ = parent; } + static node_ptr get_left(const_node_ptr n) { return n->left_; } + static void set_left(node_ptr n, node_ptr left) { n->left_ = left; } + static node_ptr get_right(const_node_ptr n) { return n->right_; } + static void set_right(node_ptr n, node_ptr right) { n->right_ = right; } +}; + +struct node_ptr_compare +{ + bool operator()(my_node *a, my_node *b) + { return a->int_ < b->int_; } +}; + +int main() +{ + typedef boost::intrusive::splaytree_algorithms algo; + my_node header, two(2), three(3); + + //Create an empty splaytree container: + //"header" will be the header node of the tree + algo::init_header(&header); + + //Now insert node "two" in the tree using the sorting functor + algo::insert_equal_upper_bound(&header, &two, node_ptr_compare()); + + //Now insert node "three" in the tree using the sorting functor + algo::insert_equal_lower_bound(&header, &three, node_ptr_compare()); + + //Now take the first node (the left node of the header) + my_node *n = header.left_; + assert(n == &two); + + //Now go to the next node + n = algo::next_node(n); + assert(n == &three); + + //Erase a node just using a pointer to it + algo::unlink(&two); + + //Erase a node using also the header (faster) + algo::erase(&header, &three); + return 0; +} + +//] \ No newline at end of file diff --git a/example/doc_splay_set.cpp b/example/doc_splay_set.cpp new file mode 100644 index 0000000..0d347f4 --- /dev/null +++ b/example/doc_splay_set.cpp @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_splay_set_code +#include +#include +#include + +using namespace boost::intrusive; + + //This is a base hook +class MyClass : public splay_set_base_hook<> +{ + int int_; + + public: + //This is a member hook + splay_set_member_hook<> member_hook_; + + MyClass(int i) + : int_(i) + {} + friend bool operator< (const MyClass &a, const MyClass &b) + { return a.int_ < b.int_; } + friend bool operator> (const MyClass &a, const MyClass &b) + { return a.int_ > b.int_; } + friend bool operator== (const MyClass &a, const MyClass &b) + { return a.int_ < b.int_; } +}; + +//Define an set using the base hook that will store values in reverse order +typedef splay_set< MyClass, compare > > BaseSplaySet; + +//Define an multiset using the member hook +typedef member_hook, &MyClass::member_hook_> MemberOption; +typedef splay_multiset< MyClass, MemberOption> MemberSplayMultiset; + +int main() +{ + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; + + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); + + BaseSplaySet baseset; + MemberSplayMultiset membermultiset; + + //Now insert them in the reverse order in the base hook set + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) + baseset.insert(*it); + + //Now insert them in the same order as in vector in the member hook set + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) + membermultiset.insert(*it); + + //Now test sets + { + BaseSplaySet::reverse_iterator rbit(baseset.rbegin()), rbitend(baseset.rend()); + MemberSplayMultiset::iterator mit(membermultiset.begin()), mitend(membermultiset.end()); + VectIt it(values.begin()), itend(values.end()); + + //Test the objects inserted in the base hook set + for(; it != itend; ++it, ++rbit) + if(&*rbit != &*it) return 1; + + //Test the objects inserted in the member hook set + for(it = values.begin(); it != itend; ++it, ++mit) + if(&*mit != &*it) return 1; + } + return 0; +} +//] diff --git a/proj/vc7ide/Intrusive.sln b/proj/vc7ide/Intrusive.sln index bb34b62..7716967 100644 --- a/proj/vc7ide/Intrusive.sln +++ b/proj/vc7ide/Intrusive.sln @@ -55,6 +55,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "external_value_traits", "ex ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "splay_multiset", "splay_multiset\splay_multiset.vcproj", "{01E70176-B6C5-BF47-2C91-A949077BA323}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "splay_set", "splay_set\splay_set.vcproj", "{1E6909E7-C971-F24A-6C7B-A92094B71B59}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -119,6 +127,14 @@ Global {97B69A72-B9D3-7389-17FB-74612F4A9543}.Debug.Build.0 = Debug|Win32 {97B69A72-B9D3-7389-17FB-74612F4A9543}.Release.ActiveCfg = Release|Win32 {97B69A72-B9D3-7389-17FB-74612F4A9543}.Release.Build.0 = Release|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Debug.ActiveCfg = Debug|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Debug.Build.0 = Debug|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Release.ActiveCfg = Release|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Release.Build.0 = Release|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Debug.ActiveCfg = Debug|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Debug.Build.0 = Debug|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Release.ActiveCfg = Release|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index 2ea2085..a6ae6c6 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -135,6 +135,9 @@ + + @@ -153,6 +156,18 @@ + + + + + + + + @@ -195,9 +210,6 @@ - - @@ -207,9 +219,18 @@ + + + + + + @@ -307,6 +328,12 @@ + + + + diff --git a/proj/vc7ide/splay_multiset/splay_multiset.vcproj b/proj/vc7ide/splay_multiset/splay_multiset.vcproj new file mode 100644 index 0000000..65751ec --- /dev/null +++ b/proj/vc7ide/splay_multiset/splay_multiset.vcproj @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/splay_set/splay_set.vcproj b/proj/vc7ide/splay_set/splay_set.vcproj new file mode 100644 index 0000000..5163087 --- /dev/null +++ b/proj/vc7ide/splay_set/splay_set.vcproj @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/to-do.txt b/proj/vc7ide/to-do.txt index 07b2a92..f32750c 100644 --- a/proj/vc7ide/to-do.txt +++ b/proj/vc7ide/to-do.txt @@ -12,3 +12,4 @@ Create a new assertion for each type of error Add resize() to list Optimize rehash for when shrinking: there is no need to hash the values. Add BOOST_STATIC_ASSERT to s_iterator_to functions and fix documentation on this issue. +rbtree::count() is recursive. diff --git a/test/itestvalue.hpp b/test/itestvalue.hpp index 06936f0..0b91415 100644 --- a/test/itestvalue.hpp +++ b/test/itestvalue.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "smart_ptr.hpp" @@ -33,16 +34,32 @@ struct set_base_hook_type template struct set_auto_base_hook_type -{ typedef set_base_hook, void_pointer, tag > type; }; +{ typedef set_base_hook, void_pointer, tag, optimize_size > type; }; template struct set_member_hook_type -{ typedef set_member_hook > type; }; +{ typedef set_member_hook, optimize_size > type; }; template struct set_auto_member_hook_type { typedef set_member_hook, void_pointer > type; }; +template +struct splay_set_base_hook_type +{ typedef splay_set_base_hook > type; }; + +template +struct splay_set_auto_base_hook_type +{ typedef splay_set_base_hook, void_pointer, tag > type; }; + +template +struct splay_set_member_hook_type +{ typedef splay_set_member_hook > type; }; + +template +struct splay_set_auto_member_hook_type +{ typedef splay_set_member_hook, void_pointer > type; }; + template struct list_base_hook_type { typedef list_base_hook > type; }; @@ -95,6 +112,8 @@ template struct testvalue : set_base_hook_type::type , set_auto_base_hook_type::type + , splay_set_base_hook_type::type + , splay_set_auto_base_hook_type::type , list_base_hook_type::type , list_auto_base_hook_type::type , slist_base_hook_type::type @@ -102,30 +121,39 @@ struct testvalue , uset_base_hook_type::type , uset_auto_base_hook_type::type { - typedef typename set_auto_base_hook_type::type set_auto_base_hook_t; - typedef typename set_base_hook_type::type set_base_hook_t; - typedef typename set_auto_member_hook_type::type set_auto_member_hook_t; - typedef typename set_member_hook_type::type set_member_hook_t; + typedef typename set_auto_base_hook_type::type set_auto_base_hook_t; + typedef typename set_base_hook_type::type set_base_hook_t; + typedef typename set_auto_member_hook_type::type set_auto_member_hook_t; + typedef typename set_member_hook_type::type set_member_hook_t; - typedef typename uset_auto_base_hook_type::type unordered_set_auto_base_hook_t; - typedef typename uset_base_hook_type::type unordered_set_base_hook_t; - typedef typename uset_auto_member_hook_type::type unordered_set_auto_member_hook_t; - typedef typename uset_member_hook_type::type unordered_set_member_hook_t; + typedef typename splay_set_auto_base_hook_type::type splay_set_auto_base_hook_t; + typedef typename splay_set_base_hook_type::type splay_set_base_hook_t; + typedef typename splay_set_auto_member_hook_type::type splay_set_auto_member_hook_t; + typedef typename splay_set_member_hook_type::type splay_set_member_hook_t; - typedef typename list_auto_base_hook_type::type list_auto_base_hook_t; - typedef typename list_base_hook_type::type list_base_hook_t; - typedef typename list_auto_member_hook_type::type list_auto_member_hook_t; - typedef typename list_member_hook_type::type list_member_hook_t; + typedef typename uset_auto_base_hook_type::type unordered_set_auto_base_hook_t; + typedef typename uset_base_hook_type::type unordered_set_base_hook_t; + typedef typename uset_auto_member_hook_type::type unordered_set_auto_member_hook_t; + typedef typename uset_member_hook_type::type unordered_set_member_hook_t; - typedef typename slist_auto_base_hook_type::type slist_auto_base_hook_t; - typedef typename slist_base_hook_type::type slist_base_hook_t; - typedef typename slist_auto_member_hook_type::type slist_auto_member_hook_t; - typedef typename slist_member_hook_type::type slist_member_hook_t; + typedef typename list_auto_base_hook_type::type list_auto_base_hook_t; + typedef typename list_base_hook_type::type list_base_hook_t; + typedef typename list_auto_member_hook_type::type list_auto_member_hook_t; + typedef typename list_member_hook_type::type list_member_hook_t; + + typedef typename slist_auto_base_hook_type::type slist_auto_base_hook_t; + typedef typename slist_base_hook_type::type slist_base_hook_t; + typedef typename slist_auto_member_hook_type::type slist_auto_member_hook_t; + typedef typename slist_member_hook_type::type slist_member_hook_t; //Set members set_member_hook_t set_node_; set_auto_member_hook_t set_auto_node_; + //SplaySet members + splay_set_member_hook_t splay_set_node_; + splay_set_auto_member_hook_t splay_set_auto_node_; + //Unordered set members unordered_set_member_hook_t unordered_set_node_; unordered_set_auto_member_hook_t unordered_set_auto_node_; @@ -163,6 +191,11 @@ struct testvalue this->set_node_ = src.set_node_; this->set_auto_node_ = src.set_auto_node_; + splay_set_base_hook_t::operator=(src); + splay_set_auto_base_hook_t::operator=(src); + this->splay_set_node_ = src.splay_set_node_; + this->splay_set_auto_node_ = src.splay_set_auto_node_; + unordered_set_base_hook_t::operator=(src); unordered_set_auto_base_hook_t::operator=(src); this->unordered_set_node_ = src.unordered_set_node_; @@ -190,6 +223,12 @@ struct testvalue set_node_.swap_nodes(other.set_node_); set_auto_node_.swap_nodes(other.set_auto_node_); + //SplaySet + splay_set_base_hook_t::swap_nodes(other); + splay_set_auto_base_hook_t::swap_nodes(other); + splay_set_node_.swap_nodes(other.splay_set_node_); + splay_set_auto_node_.swap_nodes(other.splay_set_auto_node_); + //Unordered set unordered_set_base_hook_t::swap_nodes(other); unordered_set_auto_base_hook_t::swap_nodes(other); diff --git a/test/splay_multiset_test.cpp b/test/splay_multiset_test.cpp new file mode 100644 index 0000000..dd39787 --- /dev/null +++ b/test/splay_multiset_test.cpp @@ -0,0 +1,469 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-2007. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "itestvalue.hpp" +#include "smart_ptr.hpp" +#include "common_functors.hpp" +#include +#include +#include "test_macros.hpp" +#include "test_container.hpp" +#include + +namespace boost { namespace intrusive { namespace test { + +template +struct has_const_overloads > +{ + static const bool value = false; +}; + +}}} + +using namespace boost::intrusive; +template +struct test_splay_multiset +{ + typedef typename ValueTraits::value_type value_type; + static void test_all (std::vector& values, bool splay); + static void test_sort(std::vector& values, bool splay); + static void test_insert(std::vector& values, bool splay); + static void test_swap(std::vector& values, bool splay); + static void test_find(std::vector& values, bool splay); + static void test_splay_up(std::vector& values); + static void test_splay_down(std::vector& values); + static void test_impl(bool splay); + static void test_clone(std::vector& values, bool splay); + static void test_container_from_end(std::vector& values, bool splay); +}; + +template +void test_splay_multiset::test_all + (std::vector& values, bool splay) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , constant_time_size + > splay_multiset_type; + { + splay_multiset_type testset(values.begin(), values.end()); + test::test_container(testset); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_common_unordered_and_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_non_unique_container(testset, values); + } + test_sort(values, splay); + test_insert(values, splay); + test_swap(values, splay); + test_find(values, splay); + test_splay_up(values); + test_splay_down(values); + test_impl(splay); + test_clone(values, splay); + test_container_from_end(values, splay); +} + +//test case due to an error in tree implementation: +template +void test_splay_multiset::test_impl(bool splay) +{ + typedef typename ValueTraits::value_type value_type; + std::vector values (5); + for (int i = 0; i < 5; ++i) + values[i].value_ = i; + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , constant_time_size + > multiset_type; + + multiset_type testset; + for (int i = 0; i < 5; ++i) + testset.insert (values[i]); + + testset.erase (testset.iterator_to (values[0])); + testset.erase (testset.iterator_to (values[1])); + testset.insert (values[1]); + + testset.erase (testset.iterator_to (values[2])); + testset.erase (testset.iterator_to (values[3])); +} + +//test: constructor, iterator, clear, reverse_iterator, front, back, size: +template +void test_splay_multiset::test_sort +(std::vector& values, bool splay) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , constant_time_size + > multiset_type; + + multiset_type testset1 (values.begin(), values.end()); + { int init_values [] = { 1, 2, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + testset1.clear(); + BOOST_TEST (testset1.empty()); + + typedef splay_multiset + + , value_traits + , constant_time_size + > multiset_type2; + multiset_type2 testset2 (&values[0], &values[0] + 6); + { int init_values [] = { 5, 3, 1, 4, 2, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset2.rbegin() ); } + + BOOST_TEST (testset2.begin()->value_ == 2); + BOOST_TEST (testset2.rbegin()->value_ == 5); +} + +//test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: +template +void test_splay_multiset::test_insert +(std::vector& values, bool splay) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + + multiset_type testset; + testset.insert(&values[0] + 2, &values[0] + 5); + { int init_values [] = { 1, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset.begin() ); } + + typename multiset_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 1); + + i = testset.insert (i, values[0]); + BOOST_TEST (&*i == &values[0]); + + { int init_values [] = { 5, 4, 3, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset.rbegin() ); } + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + + i = multiset_type::s_iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + + testset.erase(i); + + { int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset.begin() ); } +} + +//test: insert (seq-version), swap, erase (seq-version), size: +template +void test_splay_multiset::test_swap +(std::vector& values, bool splay) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + multiset_type testset1 (&values[0], &values[0] + 2); + multiset_type testset2; + testset2.insert (&values[0] + 2, &values[0] + 6); + + { int init_values [] = { 1, 2, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset2.begin() ); } + { int init_values [] = { 2, 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + testset1.swap (testset2); + + { int init_values [] = { 1, 2, 4, 5 }; + 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[5]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + BOOST_TEST (&*testset1.begin() == &values[3]); +} + +template +void test_splay_multiset::test_splay_up +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + typedef typename multiset_type::iterator iterator; + typedef std::multiset orig_multiset_t; + std::size_t num_values; + std::multiset original_testset (values.begin(), values.end()); + num_values = original_testset.size(); + + for(std::size_t i = 0; i != num_values; ++i){ + multiset_type testset (values.begin(), values.end()); + { + iterator it = testset.begin(); + for(std::size_t j = 0; j != i; ++j, ++it){} + testset.splay_up(it); + } + BOOST_TEST (testset.size() == num_values); + iterator it = testset.begin(); + for( typename orig_multiset_t::const_iterator origit = original_testset.begin() + , origitend = original_testset.end() + ; origit != origitend + ; ++origit, ++it){ + BOOST_TEST(*origit == *it); + } + } +} + +template +void test_splay_multiset::test_splay_down +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + typedef typename multiset_type::iterator iterator; + typedef std::multiset orig_multiset_t; + std::size_t num_values; + std::multiset original_testset (values.begin(), values.end()); + num_values = original_testset.size(); + + for(std::size_t i = 0; i != num_values; ++i){ + multiset_type testset (values.begin(), values.end()); + { + iterator it = testset.begin(); + for(std::size_t j = 0; j != i; ++j, ++it){} + BOOST_TEST(*it == *testset.splay_down(*it)); + } + BOOST_TEST (testset.size() == num_values); + iterator it = testset.begin(); + for( typename orig_multiset_t::const_iterator origit = original_testset.begin() + , origitend = original_testset.end() + ; origit != origitend + ; ++origit, ++it){ + BOOST_TEST(*origit == *it); + } + } +} + +//test: find, equal_range (lower_bound, upper_bound): +template +void test_splay_multiset::test_find +(std::vector& values, bool splay) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + multiset_type testset (values.begin(), values.end()); + typedef typename multiset_type::iterator iterator; + + value_type cmp_val; + cmp_val.value_ = 2; + iterator i = testset.find (cmp_val); + BOOST_TEST (i->value_ == 2); + BOOST_TEST ((++i)->value_ == 2); + std::pair range = testset.equal_range (cmp_val); + + BOOST_TEST (range.first->value_ == 2); + BOOST_TEST (range.second->value_ == 3); + BOOST_TEST (std::distance (range.first, range.second) == 2); + + cmp_val.value_ = 7; + BOOST_TEST (testset.find (cmp_val) == testset.end()); +} + +template +void test_splay_multiset::test_clone + (std::vector& values, bool splay) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + multiset_type testmultiset1 (&values[0], &values[0] + values.size()); + multiset_type testmultiset2; + + testmultiset2.clone_from(testmultiset1, test::new_cloner(), test::delete_disposer()); + BOOST_TEST (testmultiset2 == testmultiset1); + testmultiset2.clear_and_dispose(test::delete_disposer()); + BOOST_TEST (testmultiset2.empty()); +} + +template +void test_splay_multiset::test_container_from_end + (std::vector& values, bool splay) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_multiset + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + + multiset_type testmultiset (&values[0], &values[0] + values.size()); + BOOST_TEST (testmultiset == multiset_type::container_from_end_iterator(testmultiset.end())); + BOOST_TEST (testmultiset == multiset_type::container_from_end_iterator(testmultiset.cend())); +} + +template +class test_main_template +{ + public: + int operator()() + { + for(int n = 0; n < 2; ++n){ + typedef testvalue value_type; + static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; + std::vector > data (6); + for (int i = 0; i < 6; ++i) + data[i].value_ = random_init[i]; + + test_splay_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::splay_set_base_hook_t + >::type + >::test_all(data, 0 != (n%2)); + test_splay_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::splay_set_member_hook_t + , &value_type::splay_set_node_ + > + >::type + >::test_all(data, 0 != (n%2)); + } + return 0; + } +}; + +template +class test_main_template +{ + public: + int operator()() + { + for(int n = 0; n < 2; ++n){ + typedef testvalue value_type; + static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; + std::vector > data (6); + for (int i = 0; i < 6; ++i) + data[i].value_ = random_init[i]; + + test_splay_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::splay_set_base_hook_t + >::type + >::test_all(data, 0 != (n%2)); + + test_splay_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::splay_set_member_hook_t + , &value_type::splay_set_node_ + > + >::type + >::test_all(data, 0 != (n%2)); + + test_splay_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::splay_set_auto_base_hook_t + >::type + >::test_all(data, 0 != (n%2)); + + test_splay_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::splay_set_auto_member_hook_t + , &value_type::splay_set_auto_node_ + > + >::type + >::test_all(data, 0 != (n%2)); + } + return 0; + } +}; + +//Explicit instantiations of non-counted classes +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; + +//Explicit instantiation of counted classes +//template class multiset +// , true>; +//template class multiset +// , true>; +//template class multiset +// , true>; +//template class multiset +// , true>; + +int main( int, char* [] ) +{ + test_main_template()(); + test_main_template, false>()(); + test_main_template()(); + test_main_template, true>()(); + return boost::report_errors(); +} diff --git a/test/splay_set_test.cpp b/test/splay_set_test.cpp new file mode 100644 index 0000000..3c7a53c --- /dev/null +++ b/test/splay_set_test.cpp @@ -0,0 +1,425 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include "itestvalue.hpp" +#include "smart_ptr.hpp" +#include "common_functors.hpp" +#include +#include +#include "test_macros.hpp" +#include "test_container.hpp" +#include + +namespace boost { namespace intrusive { namespace test { + +template +struct has_const_overloads > +{ + static const bool value = false; +}; + +}}} + +using namespace boost::intrusive; + +template +struct test_splay_set +{ + typedef typename ValueTraits::value_type value_type; + static void test_all(std::vector& values); + static void test_sort(std::vector& values); + static void test_insert(std::vector& values); + static void test_swap(std::vector& values); + static void test_find(std::vector& values); + static void test_splay_up(std::vector& values); + static void test_splay_down(std::vector& values); + static void test_impl(); + static void test_clone(std::vector& values); + static void test_container_from_end(std::vector& values); +}; + +template +void test_splay_set::test_all(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + { + splay_set_type testset(values.begin(), values.end()); + test::test_container(testset); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_common_unordered_and_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_associative_container(testset, values); + testset.clear(); + testset.insert(values.begin(), values.end()); + test::test_unique_container(testset, values); + } + + test_sort(values); + test_insert(values); + test_swap(values); + test_find(values); + test_splay_up(values); + test_splay_down(values); + test_impl(); + test_clone(values); + test_container_from_end(values); +} + +//test case due to an error in tree implementation: +template +void test_splay_set::test_impl() +{ + typedef typename ValueTraits::value_type value_type; + std::vector values (5); + for (int i = 0; i < 5; ++i) + values[i].value_ = i; + + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + splay_set_type testset; + for (int i = 0; i < 5; ++i) + testset.insert (values[i]); + + testset.erase (testset.iterator_to (values[0])); + testset.erase (testset.iterator_to (values[1])); + testset.insert (values[1]); + + testset.erase (testset.iterator_to (values[2])); + testset.erase (testset.iterator_to (values[3])); +} + +//test: constructor, iterator, clear, reverse_iterator, front, back, size: +template +void test_splay_set::test_sort(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + splay_set_type testset1 (values.begin(), values.end()); + { int init_values [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } + + testset1.clear(); + BOOST_TEST (testset1.empty()); + + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , compare + , value_traits + , constant_time_size + > set_type2; + set_type2 testset2 (&values[0], &values[0] + 6); + { int init_values [] = { 5, 3, 1, 4, 2 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset2.rbegin() ); } + BOOST_TEST (testset2.begin()->value_ == 2); + BOOST_TEST (testset2.rbegin()->value_ == 5); +} + +//test: insert, const_iterator, const_reverse_iterator, erase, s_iterator_to: +template +void test_splay_set::test_insert(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + splay_set_type testset; + testset.insert(&values[0] + 2, &values[0] + 5); + + const splay_set_type& const_testset = testset; + { int init_values [] = { 1, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + + typename splay_set_type::iterator i = testset.begin(); + BOOST_TEST (i->value_ == 1); + + i = testset.insert (i, values[0]); + BOOST_TEST (&*i == &values[0]); + + { int init_values [] = { 5, 4, 3, 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset.rbegin() ); } + + i = testset.iterator_to (values[2]); + BOOST_TEST (&*i == &values[2]); + + i = splay_set_type::s_iterator_to(values[2]); + BOOST_TEST (&*i == &values[2]); + + testset.erase (i); + { int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testset.begin() ); } +} + +//test: insert (seq-version), swap, erase (seq-version), size: +template +void test_splay_set::test_swap(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + splay_set_type testset1 (&values[0], &values[0] + 2); + splay_set_type testset2; + testset2.insert (&values[0] + 2, &values[0] + 6); + testset1.swap (testset2); + + { int init_values [] = { 1, 2, 4, 5 }; + 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[5]), testset1.end()); + BOOST_TEST (testset1.size() == 1); + // BOOST_TEST (&testset1.front() == &values[3]); + BOOST_TEST (&*testset1.begin() == &values[3]); +} + +template +void test_splay_set::test_splay_up +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , size_type + , constant_time_size + > set_type; + typedef typename set_type::iterator iterator; + typedef std::set orig_set_t; + std::size_t num_values; + std::set original_testset (values.begin(), values.end()); + num_values = original_testset.size(); + + for(std::size_t i = 0; i != num_values; ++i){ + set_type testset (values.begin(), values.end()); + { + iterator it = testset.begin(); + for(std::size_t j = 0; j != i; ++j, ++it){} + testset.splay_up(it); + } + BOOST_TEST (testset.size() == num_values); + iterator it = testset.begin(); + for( typename orig_set_t::const_iterator origit = original_testset.begin() + , origitend = original_testset.end() + ; origit != origitend + ; ++origit, ++it){ + BOOST_TEST(*origit == *it); + } + } +} + +template +void test_splay_set::test_splay_down +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , size_type + , constant_time_size + > set_type; + typedef typename set_type::iterator iterator; + typedef std::set orig_set_t; + std::size_t num_values; + std::set original_testset (values.begin(), values.end()); + num_values = original_testset.size(); + + for(std::size_t i = 0; i != num_values; ++i){ + set_type testset (values.begin(), values.end()); + BOOST_TEST(testset.size() == num_values); + { + iterator it = testset.begin(); + for(std::size_t j = 0; j != i; ++j, ++it){} + BOOST_TEST(*it == *testset.splay_down(*it)); + } + BOOST_TEST (testset.size() == num_values); + iterator it = testset.begin(); + for( typename orig_set_t::const_iterator origit = original_testset.begin() + , origitend = original_testset.end() + ; origit != origitend + ; ++origit, ++it){ + BOOST_TEST(*origit == *it); + } + } +} + +//test: find, equal_range (lower_bound, upper_bound): +template +void test_splay_set::test_find(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + splay_set_type testset (values.begin(), values.end()); + typedef typename splay_set_type::iterator iterator; + + value_type cmp_val; + cmp_val.value_ = 2; + iterator i = testset.find (cmp_val); + BOOST_TEST (i->value_ == 2); + BOOST_TEST ((++i)->value_ != 2); + std::pair range = testset.equal_range (cmp_val); + + BOOST_TEST (range.first->value_ == 2); + BOOST_TEST (range.second->value_ == 3); + BOOST_TEST (std::distance (range.first, range.second) == 1); + + cmp_val.value_ = 7; + BOOST_TEST (testset.find (cmp_val) == testset.end()); +} + +template +void test_splay_set + ::test_clone(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + + splay_set_type testset1 (&values[0], &values[0] + values.size()); + splay_set_type testset2; + + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + BOOST_TEST (testset2 == testset1); + testset2.clear_and_dispose(test::delete_disposer()); + BOOST_TEST (testset2.empty()); +} + +template +void test_splay_set + ::test_container_from_end(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef splay_set + < value_type + , value_traits + , constant_time_size + > splay_set_type; + splay_set_type testset (&values[0], &values[0] + values.size()); + BOOST_TEST (testset == splay_set_type::container_from_end_iterator(testset.end())); + BOOST_TEST (testset == splay_set_type::container_from_end_iterator(testset.cend())); +} + +template +class test_main_template +{ + public: + int operator()() + { + typedef testvalue value_type; + static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; + std::vector > data (6); + for (int i = 0; i < 6; ++i) + data[i].value_ = random_init[i]; + + test_splay_set < typename detail::get_base_value_traits + < value_type + , typename value_type::splay_set_base_hook_t + >::type + >::test_all(data); + test_splay_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::splay_set_member_hook_t + , &value_type::splay_set_node_ + > + >::type + >::test_all(data); + return 0; + } +}; + +template +class test_main_template +{ + public: + int operator()() + { + typedef testvalue value_type; + static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; + std::vector > data (6); + for (int i = 0; i < 6; ++i) + data[i].value_ = random_init[i]; + + test_splay_set < typename detail::get_base_value_traits + < value_type + , typename value_type::splay_set_base_hook_t + >::type + >::test_all(data); + + test_splay_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::splay_set_member_hook_t + , &value_type::splay_set_node_ + > + >::type + >::test_all(data); + + test_splay_set < typename detail::get_base_value_traits + < value_type + , typename value_type::splay_set_auto_base_hook_t + >::type + >::test_all(data); + + test_splay_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::splay_set_auto_member_hook_t + , &value_type::splay_set_auto_node_ + > + >::type + >::test_all(data); + + return 0; + } +}; + +int main( int, char* [] ) +{ + test_main_template()(); + test_main_template, false>()(); + test_main_template()(); + test_main_template, true>()(); + return boost::report_errors(); +} +#include diff --git a/test/test_container.hpp b/test/test_container.hpp index 644ed73..4e8c4ff 100644 --- a/test/test_container.hpp +++ b/test/test_container.hpp @@ -14,11 +14,18 @@ #define BOOST_INTRUSIVE_TEST_CONTAINER_HPP #include +#include namespace boost { namespace intrusive { namespace test { +template +struct has_const_overloads +{ + static const bool value = true; +}; + template< class Container > void test_container( Container & c ) { @@ -151,7 +158,7 @@ void test_common_unordered_and_associative_container(Container & c, Data & d) } template< class Container, class Data > -void test_associative_container_invariants(Container & c, Data & d) +void test_associative_container_invariants(Container & c, Data & d, boost::intrusive::detail::true_type) { typedef typename Container::const_iterator const_iterator; for( typename Data::const_iterator di = d.begin(), de = d.end(); @@ -177,6 +184,19 @@ void test_associative_container_invariants(Container & c, Data & d) } } +template< class Container, class Data > +void test_associative_container_invariants(Container & c, Data & d, boost::intrusive::detail::false_type) +{} + +template< class Container, class Data > +void test_associative_container_invariants(Container & c, Data & d) +{ + using namespace boost::intrusive; + typedef typename detail::remove_const::type Type; + typedef detail::bool_::value> enabler; + test_associative_container_invariants(c, d, enabler()); +} + template< class Container, class Data > void test_associative_container(Container & c, Data & d) { @@ -194,7 +214,7 @@ void test_associative_container(Container & c, Data & d) } template< class Container, class Data > -void test_unordered_associative_container_invariants(Container & c, Data & d) +void test_unordered_associative_container_invariants(Container & c, Data & d, boost::intrusive::detail::true_type) { typedef typename Container::size_type size_type; typedef typename Container::const_iterator const_iterator; @@ -224,6 +244,19 @@ void test_unordered_associative_container_invariants(Container & c, Data & d) BOOST_TEST( total_objects == c.size() ); } +template< class Container, class Data > +void test_unordered_associative_container_invariants(Container & c, Data & d, boost::intrusive::detail::false_type) +{} + +template< class Container, class Data > +void test_unordered_associative_container_invariants(Container & c, Data & d) +{ + using namespace boost::intrusive; + typedef typename detail::remove_const::type Type; + typedef detail::bool_::value> enabler; + test_unordered_associative_container_invariants(c, d, enabler()); +} + template< class Container, class Data > void test_unordered_associative_container(Container & c, Data & d) { diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp index 5b42784..ceb30ba 100644 --- a/test/unordered_multiset_test.cpp +++ b/test/unordered_multiset_test.cpp @@ -317,7 +317,7 @@ void test_unordered_multiset src(testset1.begin(), testset1.end()); std::multiset dst(testset2.begin(), testset2.end()); - BOOST_TEST (src == dst); + BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin())); testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } @@ -334,7 +334,7 @@ void test_unordered_multiset src(testset1.begin(), testset1.end()); std::multiset dst(testset2.begin(), testset2.end()); - BOOST_TEST (src == dst); + BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin())); testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } @@ -351,7 +351,7 @@ void test_unordered_multiset src(testset1.begin(), testset1.end()); std::multiset dst(testset2.begin(), testset2.end()); - BOOST_TEST (src == dst); + BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin())); testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp index 1d75250..3eeccf6 100644 --- a/test/unordered_set_test.cpp +++ b/test/unordered_set_test.cpp @@ -291,7 +291,7 @@ void test_unordered_set src(testset1.begin(), testset1.end()); std::set dst(testset2.begin(), testset2.end()); - BOOST_TEST (src == dst ); + BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin())); testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } @@ -308,7 +308,7 @@ void test_unordered_set src(testset1.begin(), testset1.end()); std::set dst(testset2.begin(), testset2.end()); - BOOST_TEST (src == dst ); + BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin())); testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } @@ -325,7 +325,7 @@ void test_unordered_set src(testset1.begin(), testset1.end()); std::set dst(testset2.begin(), testset2.end()); - BOOST_TEST (src == dst ); + BOOST_TEST (src.size() == dst.size() && std::equal(src.begin(), src.end(), dst.begin())); testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); }