diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index d4f878d..2bb05df 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -32,7 +32,10 @@ doxygen autodoc "hashtable_impl=hashtable" \\ "splay_set_impl=splay_set" \\ "splay_multiset_impl=splay_multiset" \\ - "splaytree_impl=splaytree"" + "splaytree_impl=splaytree" \\ + "avl_set_impl=avl_set" \\ + "avl_multiset_impl=avl_multiset" \\ + "avltree_impl=avltree"" ; xml intrusive : intrusive.qbk ; diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index f7cef4d..59a10fc 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -928,7 +928,8 @@ one or more indices with different sorting semantics. Boost.Intrusive associativ containers, like most STL associative container implemenatations are based on red-black trees. -The memory overhead of these containers is usually 3 pointers and an integer. +The memory overhead of these containers is usually 3 pointers and a bit (with +alignment issues, this means 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). @@ -1259,11 +1260,11 @@ the unordered container: [endsect] -[section:splay_set_multiset Intrusive splay tree-based associative containers: splay_set, splay_multiset] +[section:splay_set_multiset Intrusive splay tree based associative containers: splay_set, splay_multiset and , splay_tree] 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). +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 @@ -1305,8 +1306,8 @@ performance than other balanced trees for some search patterns. [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::splay_set splay_set], +[classref boost::intrusive::splay_multiset splay_multiset] and [classref boost::intrusive::splaytree splaytree] share the same hooks. @@ -1395,6 +1396,135 @@ containers: [endsect] + +[section:avl_set_multiset Intrusive avl tree based associative containers: avl_set, avl_multiset and avltree] + +Similar to red-black trees, AVL trees are balanced binary trees. +AVL trees are often compared with red-black trees because they support the same set of operations +and because red-black trees also take O(log n) time for the basic operations. +AVL trees are more rigidly balanced than Red-Black trees, leading to slower insertion and +removal but faster retrieval, so AVL trees perform better +than red-black trees for lookup-intensive applications. + +[*Boost.Intrusive] offers 3 containers based on avl trees: +[classref boost::intrusive::avl_set avl_set], +[classref boost::intrusive::avl_multiset avl_multiset] and +[classref boost::intrusive::avltree avltree]. 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 and 2 bits (due to alignment, this usually means 3 pointers plus an integer). +This size can be reduced to 3 pointers if pointers have 4 byte alignment +(which is usually true in 32 bit systems). + +An empty, non constant-time size [classref boost::intrusive::avl_set avl_set], +[classref boost::intrusive::avl_multiset avl_multiset] or +[classref boost::intrusive::avltree avltree] +has also the size of 3 pointers and an integer (3 pointers when optimized for size). + +[section:avl_set_multiset_hooks avl_set, avl_multiset and avltree hooks] + +[classref boost::intrusive::avl_set avl_set], +[classref boost::intrusive::avl_multiset avl_multiset] and +[classref boost::intrusive::avltree avltree] +share the same hooks. + +[c++] + + template + class avl_set_base_hook; + +* [classref boost::intrusive::avl_set_base_hook avl_set_base_hook]: + the user class derives publicly from this class to make + it compatible with avl tree based containers. + +[c++] + + template + class avl_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 avl tree based containers. + +[classref boost::intrusive::avl_set_base_hook avl_set_base_hook] and +[classref boost::intrusive::avl_set_member_hook avl_set_member_hook] receive +the same options explained in the section +[link intrusive.usage How to use Boost.Intrusive] plus an option to optimize +the size of the node: + +* [*`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`. + +* [*`optimize_size`]: The hook will be optimized for size + instead of speed. The hook will embed the balance bits of the AVL + tree node in the parent pointer if pointer alignment is multiple of 4. + Optimizing the size will reduce speed performance a bit since masking + operations will be needed to access parent pointer and balance factor attributes. + Default: `optimize_size`. + +[endsect] + +[section:set_multiset_containers avl_set, avl_multiset and avltree containers] + +[c++] + + template + class avl_set; + + template + class avl_multiset; + + template + class avltree; + +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:avl_set_multiset_example Example] + +Now let's see an small example using both hooks and +[classref boost::intrusive::avl_set avl_set]/ +[classref boost::intrusive::avl_multiset avl_multiset] +containers: + +[import ../example/doc_avl_set.cpp] +[doc_avl_set_code] + +[endsect] + +[endsect] + + [section:advanced_lookups_insertions Advanced lookup and insertion functions for associative containers] [section:advanced_lookups Advanced lookups] @@ -2056,7 +2186,7 @@ with our nodes: [import ../example/doc_rbtree_algorithms.cpp] [doc_rbtree_algorithms_code] -For a complete rbtree of functions see +For a complete list of functions see [classref boost::intrusive::rbtree_algorithms rbtree_algorithms reference]. [endsect] @@ -2064,7 +2194,7 @@ For a complete rbtree of functions see [section:splaytree_algorithms Intrusive splay tree algorithms] These algorithms are static -members of the [classref boost::intrusive::rbtree_algorithms splaytree_algorithms] class: +members of the [classref boost::intrusive::splaytree_algorithms splaytree_algorithms] class: [c++] @@ -2074,14 +2204,14 @@ members of the [classref boost::intrusive::rbtree_algorithms splaytree_algorithm 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] +[classref boost::intrusive::splaytree_algorithms splaytree_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`: The type of the node that forms the circular splaytree * `node_ptr`: The type of a pointer to a node (usually node*) @@ -2107,20 +2237,88 @@ following interface: * `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 +For a complete list of functions see [classref boost::intrusive::splaytree_algorithms splaytree_algorithms reference]. [endsect] +[section:avltree_algorithms Intrusive avl tree algorithms] + +[classref boost::intrusive::avltree_algorithms avltree_algorithms] have the same +interface as [classref boost::intrusive::rbtree_algorithms rbtree_algorithms]. + +[c++] + + template + struct avltree_algorithms; + +[classref boost::intrusive::avltree_algorithms avltree_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 avltree + +* `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*) + +* `balance`: A type that can represent 3 balance types (usually an integer) + +[*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 balance get_balance(const_node_ptr n);`: + Returns the balance factor stored in "n". + +* `static void set_balance(node_ptr n, balance b);`: + Sets the balance factor stored in "n" to "b". + +* `static balance negative();`: + Returns a value representing a negative balance factor. + +* `static balance zero();`: + Returns a value representing a zero balance factor. + +* `static balance positive();`: + Returns a value representing a positive balance factor. + +Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms +with our nodes: + +[import ../example/doc_avltree_algorithms.cpp] +[doc_avltree_algorithms_code] + +For a complete list of functions see +[classref boost::intrusive::avltree_algorithms avltree_algorithms reference]. + +[endsect] + [endsect] [section:value_traits Containers with custom ValueTraits] @@ -2976,8 +3174,12 @@ helpful discussions. [*Tom Brinkman] and [*Steven Watanabe] for their comments and reviews in the Boost.Intrusive formal review. -* Thanks to of Julienne Walker and The EC Team ([@http://eternallyconfuzzled.com]) for their - great algorithms. +* Thanks to of [*Julienne Walker] and [*The EC Team] ([@http://eternallyconfuzzled.com]) + for their great algorithms. + +* Thanks to [*Daniel K. O.] for his AVL tree rebalancing code. + +* Thanks to [*Ralf Mattethat] for his splay tree article and code. * Special thanks to [*Steven Watanabe] and [*Tobias Schwinger] for their invaluable suggestions and improvements. diff --git a/example/doc_avl_set.cpp b/example/doc_avl_set.cpp new file mode 100644 index 0000000..9e69975 --- /dev/null +++ b/example/doc_avl_set.cpp @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (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_avl_set_code +#include +#include +#include +#include + +using namespace boost::intrusive; + + //This is a base hook optimized for size +class MyClass : public avl_set_base_hook > +{ + int int_; + + public: + //This is a member hook + avl_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 avl_set using the base hook that will store values in reverse order +typedef avl_set< MyClass, compare > > BaseSet; + +//Define an multiset using the member hook +typedef member_hook, &MyClass::member_hook_> MemberOption; +typedef avl_multiset< MyClass, MemberOption> MemberMultiset; + +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)); + + BaseSet baseset; + MemberMultiset membermultiset; + + //Check that size optimization is activated in the base hook + assert(sizeof(avl_set_base_hook >) == 3*sizeof(void*)); + //Check that size optimization is deactivated in the member hook + assert(sizeof(avl_set_member_hook<>) > 3*sizeof(void*)); + + //Now insert them in the reverse order in the base hook avl_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 avl_set + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) + membermultiset.insert(*it); + + //Now test avl_sets + { + BaseSet::reverse_iterator rbit(baseset.rbegin()), rbitend(baseset.rend()); + MemberMultiset::iterator mit(membermultiset.begin()), mitend(membermultiset.end()); + VectIt it(values.begin()), itend(values.end()); + + //Test the objects inserted in the base hook avl_set + for(; it != itend; ++it, ++rbit) + if(&*rbit != &*it) return 1; + + //Test the objects inserted in the member hook avl_set + for(it = values.begin(); it != itend; ++it, ++mit) + if(&*mit != &*it) return 1; + } + return 0; +} +//] diff --git a/example/doc_avltree_algorithms.cpp b/example/doc_avltree_algorithms.cpp new file mode 100644 index 0000000..9aa47b2 --- /dev/null +++ b/example/doc_avltree_algorithms.cpp @@ -0,0 +1,85 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (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. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_avltree_algorithms_code +#include +#include + +struct my_node +{ + my_node(int i = 0) + : int_(i) + {} + my_node *parent_, *left_, *right_; + int balance_; + //other members + int int_; +}; + +//Define our own avltree_node_traits +struct my_avltree_node_traits +{ + typedef my_node node; + typedef my_node * node_ptr; + typedef const my_node * const_node_ptr; + typedef int balance; + + 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; } + static balance get_balance(const_node_ptr n) { return n->balance_; } + static void set_balance(node_ptr n, balance b) { n->balance_ = b; } + static balance negative() { return -1; } + static balance zero() { return 0; } + static balance positive() { return 1; } +}; + +struct node_ptr_compare +{ + bool operator()(my_node *a, my_node *b) + { return a->int_ < b->int_; } +}; + +int main() +{ + typedef boost::intrusive::avltree_algorithms algo; + my_node header, two(2), three(3); + + //Create an empty avltree 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; +} + +//] diff --git a/example/doc_splaytree_algorithms.cpp b/example/doc_splaytree_algorithms.cpp new file mode 100644 index 0000000..f6c7f6f --- /dev/null +++ b/example/doc_splaytree_algorithms.cpp @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (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. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_splaytree_algorithms_code +#include +#include + +struct my_node +{ + my_node(int i = 0) + : int_(i) + {} + my_node *parent_, *left_, *right_; + //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; +} + +//] diff --git a/proj/vc7ide/Intrusive.sln b/proj/vc7ide/Intrusive.sln index 7716967..709f4d7 100644 --- a/proj/vc7ide/Intrusive.sln +++ b/proj/vc7ide/Intrusive.sln @@ -63,6 +63,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "splay_set", "splay_set\spla ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avl_multiset", "avl_multiset\avl_multiset.vcproj", "{0AE70176-5B8C-4BC7-392C-A4A312B07893}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avl_set", "avl_set\avl_set.vcproj", "{16909EE7-24AF-97C1-C76B-204B971BA959}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -135,6 +143,14 @@ Global {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 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Debug.ActiveCfg = Debug|Win32 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Debug.Build.0 = Debug|Win32 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Release.ActiveCfg = Release|Win32 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Release.Build.0 = Release|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.Debug.ActiveCfg = Debug|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.Debug.Build.0 = Debug|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.Release.ActiveCfg = Release|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.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 a6ae6c6..2a06564 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -105,6 +105,18 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + + + + + + + + @@ -135,6 +147,9 @@ + + @@ -183,6 +198,9 @@ + + @@ -219,9 +237,6 @@ - - @@ -286,6 +301,12 @@ + + + + @@ -334,6 +355,9 @@ + + diff --git a/proj/vc7ide/avl_multiset/avl_multiset.vcproj b/proj/vc7ide/avl_multiset/avl_multiset.vcproj new file mode 100644 index 0000000..760ce0c --- /dev/null +++ b/proj/vc7ide/avl_multiset/avl_multiset.vcproj @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/avl_set/avl_set.vcproj b/proj/vc7ide/avl_set/avl_set.vcproj new file mode 100644 index 0000000..cb26dd5 --- /dev/null +++ b/proj/vc7ide/avl_set/avl_set.vcproj @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/avl_multiset_test.cpp b/test/avl_multiset_test.cpp new file mode 100644 index 0000000..be9ad3d --- /dev/null +++ b/test/avl_multiset_test.cpp @@ -0,0 +1,394 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (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_avl_multiset +{ + 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_impl(); + static void test_clone(std::vector& values); + static void test_container_from_end(std::vector& values); +}; + +template +void test_avl_multiset::test_all + (std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_multiset + < value_type + , value_traits + , constant_time_size + > avl_multiset_type; + { + avl_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); + test_insert(values); + test_swap(values); + test_find(values); + test_impl(); + test_clone(values); + test_container_from_end(values); +} + +//test case due to an error in tree implementation: +template +void test_avl_multiset::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 avl_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_avl_multiset::test_sort +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_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 avl_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_avl_multiset::test_insert +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_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_avl_multiset::test_swap +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_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]); +} + +//test: find, equal_range (lower_bound, upper_bound): +template +void test_avl_multiset::test_find +(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_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_avl_multiset::test_clone + (std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_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_avl_multiset::test_container_from_end + (std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_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_avl_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::avl_set_base_hook_t + >::type + >::test_all(data); + test_avl_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::avl_set_member_hook_t + , &value_type::avl_set_node_ + > + >::type + >::test_all(data); + } + 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_avl_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::avl_set_base_hook_t + >::type + >::test_all(data); + + test_avl_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::avl_set_member_hook_t + , &value_type::avl_set_node_ + > + >::type + >::test_all(data); + + test_avl_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::avl_set_auto_base_hook_t + >::type + >::test_all(data); + + test_avl_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::avl_set_auto_member_hook_t + , &value_type::avl_set_auto_node_ + > + >::type + >::test_all(data); + } + 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/avl_set_test.cpp b/test/avl_set_test.cpp new file mode 100644 index 0000000..2eedd77 --- /dev/null +++ b/test/avl_set_test.cpp @@ -0,0 +1,350 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (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_avl_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_impl(); + static void test_clone(std::vector& values); + static void test_container_from_end(std::vector& values); +}; + +template +void test_avl_set::test_all(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + { + avl_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_impl(); + test_clone(values); + test_container_from_end(values); +} + +//test case due to an error in tree implementation: +template +void test_avl_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 avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + avl_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_avl_set::test_sort(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + avl_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 avl_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_avl_set::test_insert(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + avl_set_type testset; + testset.insert(&values[0] + 2, &values[0] + 5); + + const avl_set_type& const_testset = testset; + { int init_values [] = { 1, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); } + + typename avl_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 = avl_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_avl_set::test_swap(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + avl_set_type testset1 (&values[0], &values[0] + 2); + avl_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]); +} + +//test: find, equal_range (lower_bound, upper_bound): +template +void test_avl_set::test_find(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + avl_set_type testset (values.begin(), values.end()); + typedef typename avl_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_avl_set + ::test_clone(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + + avl_set_type testset1 (&values[0], &values[0] + values.size()); + avl_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_avl_set + ::test_container_from_end(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef avl_set + < value_type + , value_traits + , constant_time_size + > avl_set_type; + avl_set_type testset (&values[0], &values[0] + values.size()); + BOOST_TEST (testset == avl_set_type::container_from_end_iterator(testset.end())); + BOOST_TEST (testset == avl_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_avl_set < typename detail::get_base_value_traits + < value_type + , typename value_type::avl_set_base_hook_t + >::type + >::test_all(data); + test_avl_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::avl_set_member_hook_t + , &value_type::avl_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_avl_set < typename detail::get_base_value_traits + < value_type + , typename value_type::avl_set_base_hook_t + >::type + >::test_all(data); + + test_avl_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::avl_set_member_hook_t + , &value_type::avl_set_node_ + > + >::type + >::test_all(data); + + test_avl_set < typename detail::get_base_value_traits + < value_type + , typename value_type::avl_set_auto_base_hook_t + >::type + >::test_all(data); + + test_avl_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::avl_set_auto_member_hook_t + , &value_type::avl_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/itestvalue.hpp b/test/itestvalue.hpp index 0b91415..b7d92a4 100644 --- a/test/itestvalue.hpp +++ b/test/itestvalue.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include "smart_ptr.hpp" @@ -60,6 +61,22 @@ template struct splay_set_auto_member_hook_type { typedef splay_set_member_hook, void_pointer > type; }; +template +struct avl_set_base_hook_type +{ typedef avl_set_base_hook > type; }; + +template +struct avl_set_auto_base_hook_type +{ typedef avl_set_base_hook, void_pointer, tag, optimize_size > type; }; + +template +struct avl_set_member_hook_type +{ typedef avl_set_member_hook, optimize_size > type; }; + +template +struct avl_set_auto_member_hook_type +{ typedef avl_set_member_hook, void_pointer > type; }; + template struct list_base_hook_type { typedef list_base_hook > type; }; @@ -114,6 +131,8 @@ struct testvalue , set_auto_base_hook_type::type , splay_set_base_hook_type::type , splay_set_auto_base_hook_type::type + , avl_set_base_hook_type::type + , avl_set_auto_base_hook_type::type , list_base_hook_type::type , list_auto_base_hook_type::type , slist_base_hook_type::type @@ -131,6 +150,11 @@ struct testvalue 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 avl_set_auto_base_hook_type::type avl_set_auto_base_hook_t; + typedef typename avl_set_base_hook_type::type avl_set_base_hook_t; + typedef typename avl_set_auto_member_hook_type::type avl_set_auto_member_hook_t; + typedef typename avl_set_member_hook_type::type avl_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; @@ -154,6 +178,10 @@ struct testvalue splay_set_member_hook_t splay_set_node_; splay_set_auto_member_hook_t splay_set_auto_node_; + //AvlSet members + avl_set_member_hook_t avl_set_node_; + avl_set_auto_member_hook_t avl_set_auto_node_; + //Unordered set members unordered_set_member_hook_t unordered_set_node_; unordered_set_auto_member_hook_t unordered_set_auto_node_; @@ -196,6 +224,11 @@ struct testvalue this->splay_set_node_ = src.splay_set_node_; this->splay_set_auto_node_ = src.splay_set_auto_node_; + avl_set_base_hook_t::operator=(src); + avl_set_auto_base_hook_t::operator=(src); + this->avl_set_node_ = src.avl_set_node_; + this->avl_set_auto_node_ = src.avl_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_; @@ -229,6 +262,12 @@ struct testvalue splay_set_node_.swap_nodes(other.splay_set_node_); splay_set_auto_node_.swap_nodes(other.splay_set_auto_node_); + //AvlSet + avl_set_base_hook_t::swap_nodes(other); + avl_set_auto_base_hook_t::swap_nodes(other); + avl_set_node_.swap_nodes(other.avl_set_node_); + avl_set_auto_node_.swap_nodes(other.avl_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/smart_ptr.hpp b/test/smart_ptr.hpp index cd6b55c..6ed0d07 100644 --- a/test/smart_ptr.hpp +++ b/test/smart_ptr.hpp @@ -12,6 +12,8 @@ #define BOOST_INTRUSIVE_SMART_PTR_HPP #include +#include +#include #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -343,4 +345,78 @@ inline smart_ptr } //namespace intrusive { } //namespace boost { +namespace boost{ + +//This is to support embedding a bit in the pointer +//for intrusive containers, saving space +namespace intrusive { + +template +struct has_pointer_plus_bit, N> +{ + static const bool value = has_pointer_plus_bit::value; +}; + +//Specialization +template +struct pointer_plus_bit > +{ + typedef smart_ptr pointer; + + static pointer get_pointer(const pointer &n) + { return pointer_plus_bit::get_pointer(n.get()); } + + static void set_pointer(pointer &n, pointer p) + { + T *raw_n = n.get(); + pointer_plus_bit::set_pointer(raw_n, p.get()); + n = raw_n; + } + + static bool get_bit(const pointer &n) + { return pointer_plus_bit::get_bit(n.get()); } + + static void set_bit(pointer &n, bool c) + { + T *raw_n = n.get(); + pointer_plus_bit::set_bit(raw_n, c); + n = raw_n; + } +}; + +template +struct has_pointer_plus_2_bits, N> +{ + static const bool value = has_pointer_plus_2_bits::value; +}; + +template +struct pointer_plus_2_bits > +{ + typedef smart_ptr pointer; + + static pointer get_pointer(const pointer &n) + { return pointer_plus_2_bits::get_pointer(n.get()); } + + static void set_pointer(pointer &n, pointer p) + { + T *raw_n = n.get(); + pointer_plus_2_bits::set_pointer(raw_n, p.get()); + n = raw_n; + } + + static std::size_t get_bits(const pointer &n) + { return pointer_plus_2_bits::get_bits(n.get()); } + + static void set_bits(pointer &n, std::size_t c) + { + T *raw_n = n.get(); + pointer_plus_2_bits::set_bits(raw_n, c); + n = raw_n; + } +}; + +} //namespace intrusive +} //namespace boost{ + #endif //#ifndef BOOST_INTRUSIVE_SMART_PTR_HPP