Intrusive:

*  Added `linear<>` and `cache_last<>` options to singly linked lists.
*  Added `optimize_multikey<>` option to unordered container hooks.
*  Optimized unordered containers when `store_hash` option is used in the hook.
*  Implementation changed to be exception agnostic so that it can be used
   in environments without exceptions.
*  Added `container_from_iterator` function to tree-based containers.

Interprocess:

*  Added anonymous shared memory for UNIX systems.
*  Fixed file lock compilation errors

[SVN r44819]
This commit is contained in:
Ion Gaztañaga
2008-04-27 15:03:06 +00:00
parent daea35153f
commit 7e50778757
49 changed files with 2616 additions and 1080 deletions

View File

@@ -528,7 +528,25 @@ chapters:
small for user classes (usually the size of two pointers). Many operations have
constant time complexity.
* [*set/multiset]: A `std::set/std::multiset` like intrusive associative containers.
* [*set/multiset/rbtree]: A `std::set/std::multiset` like intrusive associative containers
based on red-black trees.
The size overhead is moderate for user classes (usually the size of three pointers).
Many operations have logarithmic time complexity.
* [*avl_set/avl_multiset/avltree]: A `std::set/std::multiset` like intrusive associative
containers based on AVL trees.
The size overhead is moderate for user classes (usually the size of three pointers).
Many operations have logarithmic time complexity.
* [*splay_set/splay_multiset/splaytree]: A `std::set/std::multiset` like intrusive associative
containers based on splay trees. Splay trees have no constant operations, but they
have some interesting caching properties.
The size overhead is moderate for user classes (usually the size of three pointers).
Many operations have logarithmic time complexity.
* [*sg_set/sg_multiset/sgtree]: A `std::set/std::multiset` like intrusive associative
containers based on scapegoat trees. Scapegoat can be configured with the desired
balance factor to achieve the desised rebalancing frequency/search time compromise.
The size overhead is moderate for user classes (usually the size of three pointers).
Many operations have logarithmic time complexity.
@@ -539,7 +557,7 @@ chapters:
The size overhead is moderate for user classes (an average of two pointers per element).
Many operations have an amortized constant time complexity.
Each of these intrusive containers can be configured with constant or linear time
Most of these intrusive containers can be configured with constant or linear time
size:
* [*Linear time size]: The intrusive container doesn't hold a size member that it's
@@ -753,7 +771,7 @@ linear time complexity, even some that usually are constant time, like
only provides forward iterators.
For most cases, a doubly linked list is preferrable because it offers more
constant-time functions with a slightly bigger overhead.
constant-time functions with a slightly bigger size overhead.
However, for some applications like
constructing more elaborated containers, singly linked lists are essential
because of their low size overhead.
@@ -784,7 +802,8 @@ Like the rest of [*Boost.Intrusive] containers,
it [classref boost::intrusive::slist slist]-compatible.
[classref boost::intrusive::slist_base_hook slist_base_hook] and
[classref boost::intrusive::slist_member_hook slist_member_hook] receive the same options explained in
[classref boost::intrusive::slist_member_hook slist_member_hook]
receive the same options explained in
the section [link intrusive.usage How to use Boost.Intrusive]:
* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag,
@@ -807,7 +826,7 @@ the section [link intrusive.usage How to use Boost.Intrusive]:
template <class T, class ...Options>
class slist;
[classref boost::intrusive::slist slist] receives the same options explained in
[classref boost::intrusive::slist slist] receives the options explained in
the section [link intrusive.usage How to use Boost.Intrusive]:
* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] /
@@ -819,7 +838,23 @@ the section [link intrusive.usage How to use Boost.Intrusive]:
Default: `constant_time_size<true>`
* [*`size_type<bool Enabled>`]: To specify the type that will be used to store the size
of the container. Default: `size_type<std::size_t>`
of the container. Default: `size_type<std::size_t>`.
[classref boost::intrusive::slist slist] can receive additional options:
* [*`linear<bool Enable>`]: the singly linked list is implemented as a
null-terminated list instead of a circular list. This allows `O(1)` swap,
but losses some operations like `container_from_end_iterator`.
* [*`cache_last<bool Enable>`]: the singly linked also stores a pointer to the
last element of the singly linked list. This allows `O(1)` swap,
`splice_after(iterator, slist &)` and makes the list offer new functions
like `push_back(reference)` and `back()`. Logically, the size an empty list is
increased in `sizeof(void_pointer)` and the the cached last node pointer must
be updated in every operation, and that might incur in a slight performance impact.
`auto_unlink` hooks are not usable if `linear<true>` and/or `cache_last<true>` options are
used. If `auto_unlink` hooks are used and those options are specified, a static
assertion will be raised.
[endsect]
@@ -1151,6 +1186,11 @@ Apart from them, these hooks offer additional options:
rehashing is frequent or hashing the value is a slow operation.
Default: `store_hash<false>`.
* [*`optimize_multikey<bool Enabled>`]: This option reserves additional space in
the hook that will be used to group equal elements in unordered multisets,
improving significantly the performance when many equal values are inserted
in these containers. Default: `optimize_multikey<false>`.
[endsect]
[section:unordered_set_unordered_multiset_containers unordered_set and unordered_multiset containers]
@@ -1210,7 +1250,7 @@ receive the same options explained in the section
* [*`size_type<bool Enabled>`]: To specify the type that will be used to store the size
of the container. Default: `size_type<std::size_t>`
And they also can receive two additional options:
And they also can receive additional options:
* [*`equal<class Equal>`]: Equality function for the objects to be inserted
in containers. Default: `equal< std::equal_to<T> >`
@@ -1228,7 +1268,14 @@ And they also can receive two additional options:
modulo operations and for some applications modulo operations can impose
a considerable overhead. In debug mode an assertion will be raised if the user
provides a bucket length that is not power of two.
Default: `constant_time_size<false>`.
Default: `power_2_buckets<false>`.
* [*`cache_begin<bool Enabled>`]: Due to its internal structure, finding the first
element of an unordered container (`begin()` operation) is
amortized constant-time. It's possible to speed up `begin()` and other operations
related to it (like `clear()`) if the container caches internally the position
of the first element. This imposes the overhead of one pointer to the size
of the container. Default: `cache_begin<false>`.
[endsect]
@@ -1301,13 +1348,13 @@ more frequently accessed than others, splay trees perform faster searches than e
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
rebalanced when an 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].
[classref boost::intrusive::multiset multiset].
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
@@ -1565,22 +1612,22 @@ time, scapegoat trees have no additional per-node overhead compared to a regular
search tree.
A binary search tree is said to be weight balanced if half the nodes are on the left
of the root, and half on the right. An α-height-balanced tree is defined with defined
of the root, and half on the right. An a-height-balanced tree is defined with defined
with the following equation:
[*['height(tree) <= log1/α(tree.size())]]
[*['height(tree) <= log1/a(tree.size())]]
* [*['α == 1]]: A tree forming a linked list is considered balanced.
* [*['α == 0.5]]: Only a perfectly balanced binary is considered balanced.
* [*['a == 1]]: A tree forming a linked list is considered balanced.
* [*['a == 0.5]]: Only a perfectly balanced binary is considered balanced.
Scapegoat trees are loosely ['α-height-balanced] so:
Scapegoat trees are loosely ['a-height-balanced] so:
[*['height(tree) <= log1/α(tree.size()) + 1]]
[*['height(tree) <= log1/a(tree.size()) + 1]]
Scapegoat trees support any α between 0.5 and 1. If α is higher, the tree is rebalanced
Scapegoat trees support any a between 0.5 and 1. If a is higher, the tree is rebalanced
less often, obtaining quicker insertions but slower searches. Lower
α values improve search times. Scapegoat-trees implemented in [*Boost.Intrusive] offer the possibility of
[*changing α at run-time] taking advantage of the flexibility of scapegoat trees.
a values improve search times. Scapegoat-trees implemented in [*Boost.Intrusive] offer the possibility of
[*changing a at run-time] taking advantage of the flexibility of scapegoat trees.
For more information on scapegoat trees see [@http://en.wikipedia.org/wiki/Scapegoat_tree Wikipedia entry].
Scapegoat trees also have downsides:
@@ -1591,7 +1638,7 @@ Scapegoat trees also have downsides:
tree is also considerably increased.
* The operations needed to determine if the tree is unbalanced require floating-point
operations like ['log1/α]. If the system has no floating point operations (like some
operations like ['log1/a]. If the system has no floating point operations (like some
embedded systems), scapegoat tree operations might become slow.
[*Boost.Intrusive] offers 3 containers based on scapegoat trees:
@@ -1689,9 +1736,9 @@ And they also can receive additional options:
* [*`floating_point<bool Enable>`]:
When this option is deactivated, the scapegoat tree loses the ability to change
the balance factor α at run-time, but the size of an empty container is reduced
the balance factor a at run-time, but the size of an empty container is reduced
and no floating point operations are performed, normally increasing container
performance. The fixed α factor that is used when this option is activated
performance. The fixed a factor that is used when this option is activated
is ['1/sqrt(2) ~ 0,70711]. Default: `floating_point<true>`
[endsect]
@@ -2523,6 +2570,63 @@ For a complete list of functions see
[endsect]
[/
/
/[section:sgtree_algorithms Intrusive sg tree algorithms]
/
/
/[classref boost::intrusive::sgtree_algorithms sgtree_algorithms] have the same
/interface as [classref boost::intrusive::rbtree_algorithms rbtree_algorithms].
/
/[c++]
/
/ template<class NodeTraits>
/ struct sgtree_algorithms;
/
/[classref boost::intrusive::sgtree_algorithms sgtree_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 sgtree
/
/* `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".
/
/Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms
/with our nodes:
/
/[import ../example/doc_sgtree_algorithms.cpp]
/[doc_sgtree_algorithms_code]
/
/For a complete list of functions see
/[classref boost::intrusive::sgtree_algorithms sgtree_algorithms reference].
/
/[endsect]
/]
[endsect]
[section:value_traits Containers with custom ValueTraits]
@@ -3104,7 +3208,7 @@ lists need to perform the same operations.
These are the results:
[table Reverse times for Visual C++ 7.1 / Windows XP
[[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object) (small object / big object)]]
[[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]]
[[`normal_link` intrusive list] [2656 / 10625] [1 / 1.83]]
[[`safe_link` intrusive list] [2812 / 10937] [1.05 / 1.89]]
[[`auto_unlink` intrusive list] [2710 / 10781] [1.02 / 1.86]]
@@ -3310,18 +3414,18 @@ all the objects to be inserted in intrusive containers in containers like `std::
[endsect]
[section:disabling_exceptions Disabling exceptions support]
[section:release_notes Release Notes]
[*Boost.Intrusive] might be useful in environments where exceptions are not available
or recommendable (like embedded or real-time systems). [*Boost.Intrusive] uses the
global Boost mechanism to disable exception handling, so that if the compiler
configuration disables exceptions, `BOOST_NO_EXCEPTIONS` is defined and exception
handling is disabled.
[section:release_notes_boost_1_36_00 Boost 1.36 Release]
This mechanism is a global mechanism to disable exceptions. If for any reason,
the user wants to disable exception handling [*only] in [*Boost.Intrusive],
`BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING` can be defined to disable
exception handling in the library.
* Added `linear<>` and `cache_last<>` options to singly linked lists.
* Added `optimize_multikey<>` option to unordered container hooks.
* Optimized unordered containers when `store_hash` option is used in the hook.
* Implementation changed to be exception agnostic so that it can be used
in environments without exceptions.
* Added `container_from_iterator` function to tree-based containers.
[endsect]
[endsect]
@@ -3331,13 +3435,13 @@ exception handling in the library.
* Visual 7.1/WinXP
* Visual 8.0/WinXP
* Visual 9.0/WinXP
* GCC 4.1.1/MinGW
* GCC 3.4.4/Cygwin
* Intel 9.1/WinXP
* GCC 4.1.2/Linux
* GCC 3.4.3/Solaris 11
* GCC 4.0/Mac Os 10.4.1
* SunCC 5.8/Solaris 11
[endsect]

View File

@@ -240,7 +240,7 @@ class avl_set_impl
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator
//! of avl_set.
//!
//! <b>Effects</b>: Returns a const reference to the avl_set associated to the end iterator
//! <b>Effects</b>: Returns a const reference to the set associated to the end iterator
//!
//! <b>Throws</b>: Nothing.
//!
@@ -252,6 +252,34 @@ class avl_set_impl
, &avl_set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of set.
//!
//! <b>Effects</b>: Returns a reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static avl_set_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<avl_set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &avl_set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of set.
//!
//! <b>Effects</b>: Returns a const reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const avl_set_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<avl_set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &avl_set_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the avl_set.
//!
//! <b>Complexity</b>: Constant.
@@ -1085,6 +1113,12 @@ class avl_set
static const avl_set &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const avl_set &>(Base::container_from_end_iterator(end_iterator)); }
static avl_set &container_from_iterator(iterator end_iterator)
{ return static_cast<avl_set &>(Base::container_from_iterator(end_iterator)); }
static const avl_set &container_from_iterator(const_iterator end_iterator)
{ return static_cast<const avl_set &>(Base::container_from_iterator(end_iterator)); }
};
#endif
@@ -1317,6 +1351,34 @@ class avl_multiset_impl
, &avl_multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static avl_multiset_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<avl_multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &avl_multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const avl_multiset_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<avl_multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &avl_multiset_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the avl_multiset.
//!
//! <b>Complexity</b>: Constant.
@@ -2057,6 +2119,12 @@ class avl_multiset
static const avl_multiset &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const avl_multiset &>(Base::container_from_end_iterator(end_iterator)); }
static avl_multiset &container_from_iterator(iterator end_iterator)
{ return static_cast<avl_multiset &>(Base::container_from_iterator(end_iterator)); }
static const avl_multiset &container_from_iterator(const_iterator end_iterator)
{ return static_cast<const avl_multiset &>(Base::container_from_iterator(end_iterator)); }
};
#endif

View File

@@ -387,6 +387,28 @@ class avltree_impl
static const avltree_impl &container_from_end_iterator(const_iterator end_iterator)
{ return priv_container_from_end_iterator(end_iterator); }
//! <b>Precondition</b>: it must be a valid iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static avltree_impl &container_from_iterator(iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Precondition</b>: it must be a valid end const_iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const avltree_impl &container_from_iterator(const_iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Effects</b>: Returns the value_compare object used by the tree.
//!
//! <b>Complexity</b>: Constant.
@@ -1233,6 +1255,9 @@ class avltree_impl
avltree_impl *avl = detail::parent_from_member<avltree_impl, data_t>(d, &avltree_impl::data_);
return *avl;
}
static avltree_impl &priv_container_from_iterator(const const_iterator &it)
{ return priv_container_from_end_iterator(it.end_iterator_from_it()); }
};
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
@@ -1426,6 +1451,12 @@ class avltree
static const avltree &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const avltree &>(Base::container_from_end_iterator(end_iterator)); }
static avltree &container_from_iterator(iterator it)
{ return static_cast<avltree &>(Base::container_from_iterator(it)); }
static const avltree &container_from_iterator(const_iterator it)
{ return static_cast<const avltree &>(Base::container_from_iterator(it)); }
};
#endif

View File

@@ -20,7 +20,6 @@
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/tree_algorithms.hpp>
@@ -641,6 +640,16 @@ class avltree_algorithms
rebalance_after_insertion(header, new_value);
}
//! <b>Requires</b>: "n" must be a node inserted in a tree.
//!
//! <b>Effects</b>: Returns a pointer to the header node of the tree.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: Nothing.
static node_ptr get_header(node_ptr n)
{ return tree_algorithms::get_header(n); }
/// @cond
private:

View File

@@ -62,8 +62,8 @@ class circular_list_algorithms
//! <b>Throws</b>: Nothing.
static void init(node_ptr this_node)
{
NodeTraits::set_next(this_node, 0);
NodeTraits::set_previous(this_node, 0);
NodeTraits::set_next(this_node, node_ptr(0));
NodeTraits::set_previous(this_node, node_ptr(0));
}
//! <b>Effects</b>: Returns true is "this_node" is in a non-used state

View File

@@ -305,12 +305,12 @@ class circular_slist_algorithms
static node_ptr move_backwards(node_ptr p, std::size_t n)
{
//Null shift, nothing to do
if(!n) return 0;
if(!n) return node_ptr(0);
node_ptr first = NodeTraits::get_next(p);
//count() == 1 or 2, nothing to do
if(NodeTraits::get_next(first) == p)
return 0;
return node_ptr(0);
bool end_found = false;
node_ptr new_last(0);
@@ -326,7 +326,7 @@ class circular_slist_algorithms
//Shortcut the shift with the modulo of the size of the list
n %= i;
if(!n)
return 0;
return node_ptr(0);
i = 0;
//Unlink p and continue the new first node search
first = NodeTraits::get_next(p);
@@ -357,11 +357,11 @@ class circular_slist_algorithms
static node_ptr move_forward(node_ptr p, std::size_t n)
{
//Null shift, nothing to do
if(!n) return 0;
if(!n) return node_ptr(0);
node_ptr first = node_traits::get_next(p);
//count() == 1 or 2, nothing to do
if(node_traits::get_next(first) == p) return 0;
if(node_traits::get_next(first) == p) return node_ptr(0);
//Iterate until p is found to know where the current last node is.
//If the shift count is less than the size of the list, we can also obtain
@@ -380,7 +380,7 @@ class circular_slist_algorithms
//Shortcut the shift with the modulo of the size of the list
std::size_t new_before_last_pos = (distance - (n % distance))% distance;
//If the shift is a multiple of the size there is nothing to do
if(!new_before_last_pos) return 0;
if(!new_before_last_pos) return node_ptr(0);
for( new_last = p
; new_before_last_pos--

View File

@@ -17,7 +17,7 @@
#include <iterator>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/avltree_algorithms.hpp>
#include <boost/intrusive/pointer_plus_2_bits.hpp>
#include <boost/intrusive/pointer_plus_bits.hpp>
#include <boost/intrusive/detail/mpl.hpp>
namespace boost {
@@ -111,7 +111,7 @@ struct compact_avltree_node_traits_impl
<VoidPointer, const node>::type const_node_ptr;
typedef typename node::balance balance;
typedef pointer_plus_2_bits<node_ptr> ptr_bit;
typedef pointer_plus_bits<node_ptr, 2> ptr_bit;
static node_ptr get_parent(const_node_ptr n)
{ return ptr_bit::get_pointer(n->parent_); }
@@ -148,7 +148,7 @@ struct compact_avltree_node_traits_impl
};
//Dispatches the implementation based on the boolean
template<class VoidPointer, bool compact>
template<class VoidPointer, bool Compact>
struct avltree_node_traits_dispatch
: public default_avltree_node_traits_impl<VoidPointer>
{};
@@ -164,10 +164,10 @@ struct avltree_node_traits
: public avltree_node_traits_dispatch
< VoidPointer
, OptimizeSize &&
has_pointer_plus_2_bits
max_pointer_plus_bits
< VoidPointer
, detail::alignment_of<compact_avltree_node<VoidPointer> >::value
>::value
>::value >= 2u
>
{};

View File

@@ -47,7 +47,7 @@ class common_slist_algorithms
{ NodeTraits::set_next(this_node, this_node); }
static void init(node_ptr this_node)
{ NodeTraits::set_next(this_node, 0); }
{ NodeTraits::set_next(this_node, node_ptr(0)); }
static bool unique(const_node_ptr this_node)
{

View File

@@ -23,8 +23,15 @@ template<typename T, bool IsEmpty = true>
class ebo_functor_holder_impl
{
public:
ebo_functor_holder_impl(){}
ebo_functor_holder_impl(const T& t):t(t){}
ebo_functor_holder_impl()
{}
ebo_functor_holder_impl(const T& t)
: t(t)
{}
template<class Arg1, class Arg2>
ebo_functor_holder_impl(const Arg1& arg1, const Arg2& arg2)
: t(arg1, arg2)
{}
T& get(){return t;}
const T& get()const{return t;}
@@ -38,8 +45,15 @@ class ebo_functor_holder_impl<T, false>
: public T
{
public:
ebo_functor_holder_impl(){}
ebo_functor_holder_impl(const T& t):T(t){}
ebo_functor_holder_impl()
{}
ebo_functor_holder_impl(const T& t)
: T(t)
{}
template<class Arg1, class Arg2>
ebo_functor_holder_impl(const Arg1& arg1, const Arg2& arg2)
: T(arg1, arg2)
{}
T& get(){return *this;}
const T& get()const{return *this;}
@@ -54,7 +68,14 @@ class ebo_functor_holder
public:
ebo_functor_holder(){}
ebo_functor_holder(const T& t):super(t){}
ebo_functor_holder(const T& t)
: super(t)
{}
template<class Arg1, class Arg2>
ebo_functor_holder(const Arg1& arg1, const Arg2& arg2)
: super(arg1, arg2)
{}
ebo_functor_holder& operator=(const ebo_functor_holder& x)
{

View File

@@ -50,6 +50,7 @@ const std::size_t prime_list_holder<Dummy>::prime_list_size
template <class Slist>
struct bucket_impl : public Slist
{
typedef Slist slist_type;
bucket_impl()
{}
@@ -69,28 +70,6 @@ struct bucket_impl : public Slist
//Slist::clear();
return *this;
}
static typename Slist::difference_type get_bucket_num
( typename Slist::const_iterator it
, const bucket_impl<Slist> &first_bucket
, const bucket_impl<Slist> &last_bucket)
{
typename Slist::const_iterator
first(first_bucket.cend()), last(last_bucket.cend());
//The end node is embedded in the singly linked list:
//iterate until we reach it.
while(!(first.pointed_node() <= it.pointed_node() &&
it.pointed_node() <= last.pointed_node())){
++it;
}
//Now get the bucket_impl from the iterator
const bucket_impl &b = static_cast<const bucket_impl&>
(Slist::container_from_end_iterator(it));
//Now just calculate the index b has in the bucket array
return &b - &first_bucket;
}
};
template<class Slist>
@@ -133,6 +112,9 @@ class hashtable_iterator
< typename Container::pointer, const Container>::type const_cont_ptr;
typedef typename Container::size_type size_type;
static typename Container::node_ptr downcast_bucket(typename bucket_type::node_ptr p)
{ return typename Container::node_ptr(&static_cast<typename Container::node&>(*p)); }
public:
typedef typename detail::add_const_if_c
<typename Container::value_type, IsConst>::type value_type;
@@ -172,7 +154,7 @@ class hashtable_iterator
{ return *this->operator ->(); }
value_type* operator->() const
{ return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(slist_it_.pointed_node())); }
{ return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(downcast_bucket(slist_it_.pointed_node()))); }
const Container *get_container() const
{ return detail::get_pointer(cont_); }
@@ -186,17 +168,19 @@ class hashtable_iterator
const Container *cont = detail::get_pointer(cont_);
bucket_type* buckets = detail::get_pointer(cont->bucket_pointer());
size_type buckets_len = cont->bucket_count();
const_siterator first(buckets[0].cend());
const_siterator last (buckets[buckets_len].cend());
++slist_it_;
if(first.pointed_node() <= slist_it_.pointed_node() &&
slist_it_.pointed_node()<= last.pointed_node() ){
size_type n_bucket = (size_type)
bucket_type::get_bucket_num(slist_it_, buckets[0], buckets[buckets_len]);
if(buckets[0].cend().pointed_node() <= slist_it_.pointed_node() &&
slist_it_.pointed_node()<= buckets[buckets_len].cend().pointed_node() ){
//Now get the bucket_impl from the iterator
const bucket_type &b = static_cast<const bucket_type&>
(bucket_type::slist_type::container_from_end_iterator(slist_it_));
//Now just calculate the index b has in the bucket array
size_type n_bucket = static_cast<size_type>(&b - &buckets[0]);
do{
if (++n_bucket == buckets_len){
slist_it_ = buckets->end();
slist_it_ = (&buckets[0] + buckets_len)->end();
break;
}
slist_it_ = buckets[n_bucket].begin();

View File

@@ -32,7 +32,8 @@ struct list_node
{
typedef typename boost::pointer_to_other
<VoidPointer, list_node>::type node_ptr;
node_ptr prev_, next_;
node_ptr next_;
node_ptr prev_;
};
template<class VoidPointer>
@@ -85,7 +86,7 @@ class list_iterator
typedef value_type * pointer;
list_iterator()
: members_ (0, 0)
: members_ (node_ptr(0), 0)
{}
explicit list_iterator(node_ptr node, const Container *cont_ptr)

View File

@@ -13,6 +13,8 @@
#ifndef BOOST_INTRUSIVE_DETAIL_MPL_HPP
#define BOOST_INTRUSIVE_DETAIL_MPL_HPP
#include <cstddef>
namespace boost {
namespace intrusive {
namespace detail {
@@ -290,6 +292,24 @@ class is_empty_class
static const bool value = sizeof(empty_helper_t1<Class>) == sizeof(empty_helper_t2);
};
template<std::size_t S>
struct ls_zeros
{
static const std::size_t value = (S & std::size_t(1)) ? 0 : (1 + ls_zeros<(S>>1u)>::value);
};
template<>
struct ls_zeros<0>
{
static const std::size_t value = 0;
};
template<>
struct ls_zeros<1>
{
static const std::size_t value = 0;
};
} //namespace detail
} //namespace intrusive
} //namespace boost

View File

@@ -1,28 +0,0 @@
/////////////////////////////////////////////////////////////////////////////
//
// (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.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_NO_EXCEPTION_SUPPORT_HPP
#if !(defined BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING)
# include <boost/detail/no_exceptions_support.hpp>
# define BOOST_INTRUSIVE_TRY BOOST_TRY
# define BOOST_INTRUSIVE_CATCH(x) BOOST_CATCH(x)
# define BOOST_INTRUSIVE_RETHROW BOOST_RETHROW
# define BOOST_INTRUSIVE_CATCH_END BOOST_CATCH_END
#else
# define BOOST_INTRUSIVE_TRY { if (true)
# define BOOST_INTRUSIVE_CATCH(x) else if (false)
# define BOOST_INTRUSIVE_RETHROW
# define BOOST_INTRUSIVE_CATCH_END }
#endif
#endif //#ifndef BOOST_INTRUSIVE_NO_EXCEPTION_SUPPORT_HPP

View File

@@ -18,7 +18,7 @@
#include <iterator>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/rbtree_algorithms.hpp>
#include <boost/intrusive/pointer_plus_bit.hpp>
#include <boost/intrusive/pointer_plus_bits.hpp>
#include <boost/intrusive/detail/mpl.hpp>
namespace boost {
@@ -110,7 +110,7 @@ struct compact_rbtree_node_traits_impl
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef pointer_plus_bit<node_ptr> ptr_bit;
typedef pointer_plus_bits<node_ptr, 1> ptr_bit;
typedef typename node::color color;
@@ -133,10 +133,10 @@ struct compact_rbtree_node_traits_impl
{ n->right_ = r; }
static color get_color(const_node_ptr n)
{ return (color)ptr_bit::get_bit(n->parent_); }
{ return (color)ptr_bit::get_bits(n->parent_); }
static void set_color(node_ptr n, color c)
{ ptr_bit::set_bit(n->parent_, c != 0); }
{ ptr_bit::set_bits(n->parent_, c != 0); }
static color black()
{ return node::black_t; }
@@ -146,7 +146,7 @@ struct compact_rbtree_node_traits_impl
};
//Dispatches the implementation based on the boolean
template<class VoidPointer, bool compact>
template<class VoidPointer, bool Compact>
struct rbtree_node_traits_dispatch
: public default_rbtree_node_traits_impl<VoidPointer>
{};
@@ -161,11 +161,11 @@ template<class VoidPointer, bool OptimizeSize = false>
struct rbtree_node_traits
: public rbtree_node_traits_dispatch
< VoidPointer
, OptimizeSize &&
has_pointer_plus_bit
, OptimizeSize &&
(max_pointer_plus_bits
< VoidPointer
, detail::alignment_of<compact_rbtree_node<VoidPointer> >::value
>::value
>::value >= 1)
>
{};

View File

@@ -78,7 +78,7 @@ class slist_iterator
typedef value_type * pointer;
slist_iterator()
: members_ (0, 0)
: members_ (node_ptr(0), 0)
{}
explicit slist_iterator(node_ptr node, const Container *cont_ptr)

View File

@@ -17,7 +17,6 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <cstddef>
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
namespace boost {
@@ -97,6 +96,7 @@ class tree_algorithms
{
/// @cond
private:
typedef typename NodeTraits::node node;
/// @endcond
@@ -123,6 +123,26 @@ class tree_algorithms
/// @cond
private:
template<class Disposer>
struct dispose_subtree_disposer
{
dispose_subtree_disposer(Disposer &disp, node_ptr subtree)
: disposer_(&disp), subtree_(subtree)
{}
void release()
{ disposer_ = 0; }
~dispose_subtree_disposer()
{
if(disposer_){
dispose_subtree(subtree_, *disposer_);
}
}
Disposer *disposer_;
node_ptr subtree_;
};
static node_ptr uncast(const_node_ptr ptr)
{
return node_ptr(const_cast<node*>(::boost::intrusive::detail::get_pointer(ptr)));
@@ -505,9 +525,21 @@ class tree_algorithms
//! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.
static void init(node_ptr node)
{
NodeTraits::set_parent(node, 0);
NodeTraits::set_left(node, 0);
NodeTraits::set_right(node, 0);
NodeTraits::set_parent(node, node_ptr(0));
NodeTraits::set_left(node, node_ptr(0));
NodeTraits::set_right(node, node_ptr(0));
};
//! <b>Effects</b>: Returns true if node is in the same state as if called init(node)
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
static bool inited(const_node_ptr node)
{
return !NodeTraits::get_parent(node) &&
!NodeTraits::get_left(node) &&
!NodeTraits::get_right(node) ;
};
//! <b>Requires</b>: node must not be part of any tree.
@@ -522,7 +554,7 @@ class tree_algorithms
//! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.
static void init_header(node_ptr header)
{
NodeTraits::set_parent(header, 0);
NodeTraits::set_parent(header, node_ptr(0));
NodeTraits::set_left(header, header);
NodeTraits::set_right(header, header);
}
@@ -565,7 +597,7 @@ class tree_algorithms
{
node_ptr leftmost = NodeTraits::get_left(header);
if (leftmost == header)
return 0;
return node_ptr(0);
node_ptr leftmost_parent(NodeTraits::get_parent(leftmost));
node_ptr leftmost_right (NodeTraits::get_right(leftmost));
bool is_root = leftmost_parent == header;
@@ -580,12 +612,12 @@ class tree_algorithms
NodeTraits::set_left(NodeTraits::get_parent(header), leftmost_right);
}
else if (is_root){
NodeTraits::set_parent(header, 0);
NodeTraits::set_parent(header, node_ptr(0));
NodeTraits::set_left(header, header);
NodeTraits::set_right(header, header);
}
else{
NodeTraits::set_left(leftmost_parent, 0);
NodeTraits::set_left(leftmost_parent, node_ptr(0));
NodeTraits::set_left(header, leftmost_parent);
}
return leftmost;
@@ -1143,58 +1175,54 @@ class tree_algorithms
node_ptr rightmost = target_sub_root;
//First set the subroot
NodeTraits::set_left(target_sub_root, 0);
NodeTraits::set_right(target_sub_root, 0);
NodeTraits::set_left(target_sub_root, node_ptr(0));
NodeTraits::set_right(target_sub_root, node_ptr(0));
NodeTraits::set_parent(target_sub_root, target_parent);
try {
while(true) {
//First clone left nodes
if( NodeTraits::get_left(current) &&
!NodeTraits::get_left(insertion_point)) {
current = NodeTraits::get_left(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, 0);
NodeTraits::set_right (insertion_point, 0);
//Insert left
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_left (temp, insertion_point);
//Update leftmost
if(rightmost == target_sub_root)
leftmost = insertion_point;
}
//Then clone right nodes
else if( NodeTraits::get_right(current) &&
!NodeTraits::get_right(insertion_point)){
current = NodeTraits::get_right(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, 0);
NodeTraits::set_right (insertion_point, 0);
//Insert right
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_right (temp, insertion_point);
//Update rightmost
rightmost = insertion_point;
}
//If not, go up
else if(current == source_root){
break;
}
else{
//Branch completed, go up searching more nodes to clone
current = NodeTraits::get_parent(current);
insertion_point = NodeTraits::get_parent(insertion_point);
}
dispose_subtree_disposer<Disposer> rollback(disposer, target_sub_root);
while(true) {
//First clone left nodes
if( NodeTraits::get_left(current) &&
!NodeTraits::get_left(insertion_point)) {
current = NodeTraits::get_left(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, node_ptr(0));
NodeTraits::set_right (insertion_point, node_ptr(0));
//Insert left
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_left (temp, insertion_point);
//Update leftmost
if(rightmost == target_sub_root)
leftmost = insertion_point;
}
//Then clone right nodes
else if( NodeTraits::get_right(current) &&
!NodeTraits::get_right(insertion_point)){
current = NodeTraits::get_right(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, node_ptr(0));
NodeTraits::set_right (insertion_point, node_ptr(0));
//Insert right
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_right (temp, insertion_point);
//Update rightmost
rightmost = insertion_point;
}
//If not, go up
else if(current == source_root){
break;
}
else{
//Branch completed, go up searching more nodes to clone
current = NodeTraits::get_parent(current);
insertion_point = NodeTraits::get_parent(insertion_point);
}
}
catch(...) {
dispose_subtree(target_sub_root, disposer);
throw;
}
rollback.release();
leftmost_out = leftmost;
rightmost_out = rightmost;
}
@@ -1321,8 +1349,8 @@ class tree_algorithms
NodeTraits::set_right(header, z);
}
NodeTraits::set_parent(z, par);
NodeTraits::set_right(z, 0);
NodeTraits::set_left(z, 0);
NodeTraits::set_right(z, node_ptr(0));
NodeTraits::set_left(z, node_ptr(0));
}
static void erase(node_ptr header, node_ptr z)
@@ -1384,7 +1412,7 @@ class tree_algorithms
{
std::size_t len;
len = 0;
if(!old_root) return 0;
if(!old_root) return node_ptr(0);
//To avoid irregularities in the algorithm (old_root can be a
//left or right child or even the root of the tree) just put the
@@ -1392,8 +1420,8 @@ class tree_algorithms
//information to restore the original relationship after
//the algorithm is applied.
node_ptr super_root = NodeTraits::get_parent(old_root);
assert(super_root);
BOOST_INTRUSIVE_INVARIANT_ASSERT(super_root);
//Get info
node_ptr super_root_right_backup = NodeTraits::get_right(super_root);
bool super_root_is_header = is_header(super_root);
@@ -1464,7 +1492,7 @@ class tree_algorithms
//information to restore the original relationship after
//the algorithm is applied.
node_ptr super_root = NodeTraits::get_parent(old_root);
assert(super_root);
BOOST_INTRUSIVE_INVARIANT_ASSERT(super_root);
//Get info
node_ptr super_root_right_backup = NodeTraits::get_right(super_root);
@@ -1511,6 +1539,28 @@ class tree_algorithms
return new_root;
}
//! <b>Requires</b>: "n" must be a node inserted in a tree.
//!
//! <b>Effects</b>: Returns a pointer to the header node of the tree.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: Nothing.
static node_ptr get_root(node_ptr node)
{
BOOST_INTRUSIVE_INVARIANT_ASSERT((!inited(node)));
node_ptr x = NodeTraits::get_parent(node);
if(x){
while(!is_header(x)){
x = NodeTraits::get_parent(x);
}
return x;
}
else{
return node;
}
}
private:
static void erase_impl(node_ptr header, node_ptr z, data_for_rebalance &info)
{
@@ -1569,7 +1619,6 @@ class tree_algorithms
info.x_parent = x_parent;
info.y = y;
}
};
} //namespace detail {

View File

@@ -168,6 +168,11 @@ class tree_iterator
return 0;
}
tree_iterator end_iterator_from_it() const
{
return tree_iterator(node_algorithms::get_header(this->pointed_node()), this->get_container());
}
private:
struct members
: public detail::select_constptr

View File

@@ -235,16 +235,9 @@ struct node_cloner
node_cloner(F f, const Container *cont)
: base_t(f), cont_(cont)
{}
node_ptr operator()(node_ptr p)
{
node_ptr n = cont_->get_real_value_traits().to_node_ptr
(*base_t::get()(*cont_->get_real_value_traits().to_value_ptr(p)));
//Cloned node must be in default mode if the linking mode requires it
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n));
return n;
}
{ return this->operator()(*p); }
node_ptr operator()(const node &to_clone)
{
@@ -396,16 +389,16 @@ template <link_mode_type LinkMode>
struct link_dispatch
{};
template<class Container>
void destructor_impl(Container &cont, detail::link_dispatch<safe_link>)
{ (void)cont; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!cont.is_linked()); }
template<class Hook>
void destructor_impl(Hook &hook, detail::link_dispatch<safe_link>)
{ (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked()); }
template<class Container>
void destructor_impl(Container &cont, detail::link_dispatch<auto_unlink>)
{ cont.unlink(); }
template<class Hook>
void destructor_impl(Hook &hook, detail::link_dispatch<auto_unlink>)
{ hook.unlink(); }
template<class Container>
void destructor_impl(Container &, detail::link_dispatch<normal_link>)
template<class Hook>
void destructor_impl(Hook &, detail::link_dispatch<normal_link>)
{}
template<class T, class NodeTraits, link_mode_type LinkMode, class Tag, int HookType>
@@ -548,6 +541,62 @@ inline std::size_t sqrt2_pow_2xplus1 (std::size_t x)
return (value >> (pow - x)) + 1;
}
template<class Container, class Disposer>
class exception_disposer
{
Container *cont_;
Disposer &disp_;
exception_disposer(const exception_disposer&);
exception_disposer &operator=(const exception_disposer&);
public:
exception_disposer(Container &cont, Disposer &disp)
: cont_(&cont), disp_(disp)
{}
void release()
{ cont_ = 0; }
~exception_disposer()
{
if(cont_){
cont_->clear_and_dispose(disp_);
}
}
};
template<class Container, class Disposer>
class exception_array_disposer
{
Container *cont_;
Disposer &disp_;
typename Container::size_type &constructed_;
exception_array_disposer(const exception_array_disposer&);
exception_array_disposer &operator=(const exception_array_disposer&);
public:
typedef typename Container::size_type size_type;
exception_array_disposer
(Container &cont, Disposer &disp, size_type &constructed)
: cont_(&cont), disp_(disp), constructed_(constructed)
{}
void release()
{ cont_ = 0; }
~exception_array_disposer()
{
size_type n = constructed_;
if(cont_){
while(n--){
cont_[n].clear_and_dispose(disp_);
}
}
}
};
} //namespace detail
} //namespace intrusive
} //namespace boost

File diff suppressed because it is too large Load Diff

View File

@@ -283,8 +283,7 @@ template
>
class bs_set_member_hook;
//hash/unordered
//rbtree/set/multiset
//hashtable/unordered_set/unordered_multiset
template
< class T
, class O1 = none
@@ -294,6 +293,7 @@ template
, class O5 = none
, class O6 = none
, class O7 = none
, class O8 = none
>
class hashtable;
@@ -306,6 +306,7 @@ template
, class O5 = none
, class O6 = none
, class O7 = none
, class O8 = none
>
class unordered_set;
@@ -318,6 +319,7 @@ template
, class O5 = none
, class O6 = none
, class O7 = none
, class O8 = none
>
class unordered_multiset;

View File

@@ -136,7 +136,7 @@ class linear_slist_algorithms
//!
//! <b>Throws</b>: Nothing.
static void init_header(node_ptr this_node)
{ NodeTraits::set_next(this_node, 0); }
{ NodeTraits::set_next(this_node, node_ptr(0)); }
//! <b>Requires</b>: this_node and prev_init_node must be in the same linear list.
//!
@@ -195,7 +195,7 @@ class linear_slist_algorithms
//! <b>Complexity</b>: This function is linear to the contained elements.
static node_ptr reverse(node_ptr p)
{
if(!p) return 0;
if(!p) return node_ptr(0);
node_ptr i = NodeTraits::get_next(p);
node_ptr first(p);
while(i){
@@ -218,7 +218,7 @@ class linear_slist_algorithms
//! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
static std::pair<node_ptr, node_ptr> move_first_n_backwards(node_ptr p, std::size_t n)
{
std::pair<node_ptr, node_ptr> ret(0, 0);
std::pair<node_ptr, node_ptr> ret(node_ptr(0), node_ptr(0));
//Null shift, or count() == 0 or 1, nothing to do
if(!n || !p || !NodeTraits::get_next(p)){
return ret;
@@ -252,12 +252,12 @@ class linear_slist_algorithms
//If the p has not been found in the previous loop, find it
//starting in the new first node and unlink it
if(!end_found){
old_last = base_t::get_previous_node(first, 0);
old_last = base_t::get_previous_node(first, node_ptr(0));
}
//Now link p after the new last node
NodeTraits::set_next(old_last, p);
NodeTraits::set_next(new_last, 0);
NodeTraits::set_next(new_last, node_ptr(0));
ret.first = first;
ret.second = new_last;
return ret;
@@ -273,7 +273,7 @@ class linear_slist_algorithms
//! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
static std::pair<node_ptr, node_ptr> move_first_n_forward(node_ptr p, std::size_t n)
{
std::pair<node_ptr, node_ptr> ret(0, 0);
std::pair<node_ptr, node_ptr> ret(node_ptr(0), node_ptr(0));
//Null shift, or count() == 0 or 1, nothing to do
if(!n || !p || !NodeTraits::get_next(p))
return ret;
@@ -311,7 +311,7 @@ class linear_slist_algorithms
node_ptr new_first(node_traits::get_next(new_last));
//Now put the old beginning after the old end
NodeTraits::set_next(old_last, p);
NodeTraits::set_next(new_last, 0);
NodeTraits::set_next(new_last, node_ptr(0));
ret.first = new_first;
ret.second = new_last;
return ret;

View File

@@ -24,7 +24,7 @@
#include <boost/intrusive/link_mode.hpp>
#include <boost/static_assert.hpp>
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <iterator>
#include <algorithm>
#include <functional>
@@ -732,17 +732,13 @@ class list_impl
void clone_from(const list_impl &src, Cloner cloner, Disposer disposer)
{
this->clear_and_dispose(disposer);
BOOST_INTRUSIVE_TRY{
const_iterator b(src.begin()), e(src.end());
for(; b != e; ++b){
this->push_back(*cloner(*b));
}
detail::exception_disposer<list_impl, Disposer>
rollback(*this, disposer);
const_iterator b(src.begin()), e(src.end());
for(; b != e; ++b){
this->push_back(*cloner(*b));
}
BOOST_INTRUSIVE_CATCH(...){
this->clear_and_dispose(disposer);
BOOST_INTRUSIVE_RETHROW;
}
BOOST_INTRUSIVE_CATCH_END
rollback.release();
}
//! <b>Requires</b>: value must be an lvalue and p must be a valid iterator of *this.

View File

@@ -406,6 +406,24 @@ struct store_hash
/// @endcond
};
//!This option setter specifies if the unordered hook
//!should offer room to store another link to another node
//!with the same key.
//!Storing this link will speed up lookups and insertions on
//!unordered_multiset containers with a great number of elements
//!with the same key.
template<bool Enabled>
struct optimize_multikey
{
/// @cond
template<class Base>
struct pack : Base
{
static const bool optimize_multikey = Enabled;
};
/// @endcond
};
//!This option setter specifies if the bucket array will be always power of two.
//!This allows using masks instead of the default modulo operation to determine
//!the bucket number from the hash value, leading to better performance.
@@ -423,6 +441,22 @@ struct power_2_buckets
/// @endcond
};
//!This option setter specifies if the container will cache a pointer to the first
//!non-empty bucket so that begin() is always constant-time.
//!This is specially helpful when we can have containers with a few elements
//!but with big bucket arrays (that is, hashtables with low load factors).
template<bool Enabled>
struct cache_begin
{
/// @cond
template<class Base>
struct pack : Base
{
static const bool cache_begin = Enabled;
};
/// @endcond
};
/// @cond
template<class Prev, class Next>
@@ -500,6 +534,7 @@ struct hook_defaults
, optimize_size<false>
, store_hash<false>
, linear<false>
, optimize_multikey<false>
>::type
{};

View File

@@ -1,82 +0,0 @@
/////////////////////////////////////////////////////////////////////////////
//
// (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.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_POINTER_PLUS_2_BIT_HPP
#define BOOST_INTRUSIVE_POINTER_PLUS_2_BIT_HPP
namespace boost {
namespace intrusive {
//!This trait class is used to know if a pointer
//!can embed 2 extra bits of information if
//!it's going to be used to point to objects
//!with an alignment of "Alignment" bytes.
template<class VoidPointer, std::size_t Alignment>
struct has_pointer_plus_2_bits
{
static const bool value = false;
};
//!This is an specialization for raw pointers.
//!Raw pointers can embed two extra bits in the lower bits
//!if the alignment is multiple of 4.
template<std::size_t N>
struct has_pointer_plus_2_bits<void*, N>
{
static const bool value = (N % 4u == 0);
};
//!This is class that is supposed to have static methods
//!to embed 2 extra bits of information in a pointer.
//!
//!This is a declaration and there is no default implementation,
//!because operations to embed bits change with every pointer type.
//!
//!An implementation that detects that a pointer type whose
//!has_pointer_plus_2_bits<>::value is non-zero can make use of these
//!operations to embed bits in the pointer.
template<class Pointer>
struct pointer_plus_2_bits
{
static const bool value = false;
};
//!This is the specialization to embed 2 extra bits of information
//!in a raw pointer. Extra bits are stored in the lower bits of the pointer.
template<class T>
struct pointer_plus_2_bits<T*>
{
typedef T* pointer;
static pointer get_pointer(pointer n)
{ return pointer(std::size_t(n) & ~std::size_t(3u)); }
static void set_pointer(pointer &n, pointer p)
{
assert(0 == (std::size_t(p) & std::size_t(3u)));
n = pointer(std::size_t(p) | (std::size_t(n) & std::size_t(3u)));
}
static std::size_t get_bits(pointer n)
{ return (std::size_t(n) & std::size_t(3u)); }
static void set_bits(pointer &n, std::size_t c)
{
assert(c < 4);
n = pointer(std::size_t(get_pointer(n)) | c);
}
};
} //namespace intrusive
} //namespace boost
#endif //BOOST_INTRUSIVE_POINTER_PLUS_2_BIT_HPP

View File

@@ -1,78 +0,0 @@
/////////////////////////////////////////////////////////////////////////////
//
// (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.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_POINTER_PLUS_BIT_HPP
#define BOOST_INTRUSIVE_POINTER_PLUS_BIT_HPP
namespace boost {
namespace intrusive {
//!This trait class is used to know if a pointer
//!can embed an extra bit of information if
//!it's going to be used to point to objects
//!with an alignment of "Alignment" bytes.
template<class VoidPointer, std::size_t Alignment>
struct has_pointer_plus_bit
{
static const bool value = false;
};
//!This is an specialization for raw pointers.
//!Raw pointers can embed an extra bit in the lower bit
//!if the alignment is multiple of 2.
template<std::size_t N>
struct has_pointer_plus_bit<void*, N>
{
static const bool value = (N % 2u == 0);
};
//!This is class that is supposed to have static methods
//!to embed an extra bit of information in a pointer.
//!This is a declaration and there is no default implementation,
//!because operations to embed the bit change with every pointer type.
//!
//!An implementation that detects that a pointer type whose
//!has_pointer_plus_bit<>::value is non-zero can make use of these
//!operations to embed the bit in the pointer.
template<class Pointer>
struct pointer_plus_bit
{
static const bool value = false;
};
//!This is the specialization to embed an extra bit of information
//!in a raw pointer. The extra bit is stored in the lower bit of the pointer.
template<class T>
struct pointer_plus_bit<T*>
{
typedef T* pointer;
static pointer get_pointer(pointer n)
{ return pointer(std::size_t(n) & ~std::size_t(1u)); }
static void set_pointer(pointer &n, pointer p)
{
assert(0 == (std::size_t(p) & std::size_t(1u)));
n = pointer(std::size_t(p) | (std::size_t(n) & std::size_t(1u)));
}
static bool get_bit(pointer n)
{ return (std::size_t(n) & std::size_t(1u)) != 0; }
static void set_bit(pointer &n, bool c)
{ n = pointer(std::size_t(get_pointer(n)) | std::size_t(c)); }
};
} //namespace intrusive
} //namespace boost
#endif //BOOST_INTRUSIVE_POINTER_PLUS_BIT_HPP

View File

@@ -0,0 +1,81 @@
/////////////////////////////////////////////////////////////////////////////
//
// (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.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_POINTER_PLUS_BITS_HPP
#define BOOST_INTRUSIVE_POINTER_PLUS_BITS_HPP
#include <boost/intrusive/detail/mpl.hpp> //ls_zeros
namespace boost {
namespace intrusive {
//!This trait class is used to know if a pointer
//!can embed extra bits of information if
//!it's going to be used to point to objects
//!with an alignment of "Alignment" bytes.
template<class VoidPointer, std::size_t Alignment>
struct max_pointer_plus_bits
{
static const std::size_t value = 0;
};
//!This is an specialization for raw pointers.
//!Raw pointers can embed extra bits in the lower bits
//!if the alignment is multiple of 2pow(NumBits).
template<std::size_t Alignment>
struct max_pointer_plus_bits<void*, Alignment>
{
static const std::size_t value = detail::ls_zeros<Alignment>::value;
};
//!This is class that is supposed to have static methods
//!to embed extra bits of information in a pointer.
//!This is a declaration and there is no default implementation,
//!because operations to embed the bits change with every pointer type.
//!
//!An implementation that detects that a pointer type whose
//!has_pointer_plus_bits<>::value is non-zero can make use of these
//!operations to embed the bits in the pointer.
template<class Pointer, std::size_t NumBits>
struct pointer_plus_bits;
//!This is the specialization to embed extra bits of information
//!in a raw pointer. The extra bits are stored in the lower bit of the pointer.
template<class T, std::size_t NumBits>
struct pointer_plus_bits<T*, NumBits>
{
static const std::size_t Mask = ((std::size_t(1u) << NumBits) - 1);
typedef T* pointer;
static pointer get_pointer(pointer n)
{ return pointer(std::size_t(n) & ~Mask); }
static void set_pointer(pointer &n, pointer p)
{
assert(0 == (std::size_t(p) & Mask));
n = pointer(std::size_t(p) | (std::size_t(n) & Mask));
}
static std::size_t get_bits(pointer n)
{ return (std::size_t(n) & Mask); }
static void set_bits(pointer &n, std::size_t c)
{
assert(c <= Mask);
n = pointer(std::size_t(get_pointer(n)) | c);
}
};
} //namespace intrusive
} //namespace boost
#endif //BOOST_INTRUSIVE_POINTER_PLUS_BITS_HPP

View File

@@ -379,7 +379,7 @@ class rbtree_impl
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the rbtree associated to the end iterator
//! <b>Effects</b>: Returns a const reference to the rbtree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
@@ -387,6 +387,28 @@ class rbtree_impl
static const rbtree_impl &container_from_end_iterator(const_iterator end_iterator)
{ return priv_container_from_end_iterator(end_iterator); }
//! <b>Precondition</b>: it must be a valid iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static rbtree_impl &container_from_iterator(iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Precondition</b>: it must be a valid end const_iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the end iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const rbtree_impl &container_from_iterator(const_iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Effects</b>: Returns the value_compare object used by the tree.
//!
//! <b>Complexity</b>: Constant.
@@ -1176,33 +1198,26 @@ class rbtree_impl
static void init_node(reference value)
{ node_algorithms::init(value_traits::to_node_ptr(value)); }
/*
//! <b>Effects</b>: removes x from a tree of the appropriate type. It has no effect,
//! if x is not in such a tree.
//! <b>Effects</b>: removes "value" from the container.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant time.
//! <b>Complexity</b>: Logarithmic time.
//!
//! <b>Note</b>: This static function is only usable with the "safe mode"
//! hook and non-constant time size lists. Otherwise, the user must use
//! the non-static "erase(reference )" member. If the user calls
//! this function with a non "safe mode" or constant time size list
//! a compilation error will be issued.
template<class T>
static void remove_node(T& value)
//! <b>Note</b>: This static function is only usable with non-constant
//! time size containers that have stateless comparison functors.
//!
//! If the user calls
//! this function with a constant time size container or stateful comparison
//! functor a compilation error will be issued.
static void remove_node(reference value)
{
//This function is only usable for safe mode hooks and non-constant
//time lists.
//BOOST_STATIC_ASSERT((!(safemode_or_autounlink && constant_time_size)));
BOOST_STATIC_ASSERT((!constant_time_size));
BOOST_STATIC_ASSERT((boost::is_convertible<T, value_type>::value));
node_ptr to_remove(value_traits::to_node_ptr(value));
node_algorithms::unlink_and_rebalance(to_remove);
node_algorithms::unlink(to_remove);
if(safemode_or_autounlink)
node_algorithms::init(to_remove);
}
*/
/// @cond
private:
@@ -1233,6 +1248,9 @@ class rbtree_impl
rbtree_impl *rb = detail::parent_from_member<rbtree_impl, data_t>(d, &rbtree_impl::data_);
return *rb;
}
static rbtree_impl &priv_container_from_iterator(const const_iterator &it)
{ return priv_container_from_end_iterator(it.end_iterator_from_it()); }
};
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
@@ -1426,6 +1444,12 @@ class rbtree
static const rbtree &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const rbtree &>(Base::container_from_end_iterator(end_iterator)); }
static rbtree &container_from_it(iterator it)
{ return static_cast<rbtree &>(Base::container_from_iterator(it)); }
static const rbtree &container_from_it(const_iterator it)
{ return static_cast<const rbtree &>(Base::container_from_iterator(it)); }
};
#endif

View File

@@ -54,7 +54,6 @@
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/tree_algorithms.hpp>
@@ -695,6 +694,16 @@ class rbtree_algorithms
rebalance_after_insertion(header, new_value);
}
//! <b>Requires</b>: "n" must be a node inserted in a tree.
//!
//! <b>Effects</b>: Returns a pointer to the header node of the tree.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: Nothing.
static node_ptr get_header(node_ptr n)
{ return tree_algorithms::get_header(n); }
/// @cond
private:

View File

@@ -226,7 +226,7 @@ class set_impl
//! <b>Precondition</b>: end_iterator must be a valid end iterator
//! of set.
//!
//! <b>Effects</b>: Returns a const reference to the set associated to the end iterator
//! <b>Effects</b>: Returns a reference to the set associated to the end iterator
//!
//! <b>Throws</b>: Nothing.
//!
@@ -253,6 +253,34 @@ class set_impl
, &set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of set.
//!
//! <b>Effects</b>: Returns a reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static set_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of set.
//!
//! <b>Effects</b>: Returns a const reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const set_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &set_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the set.
//!
//! <b>Complexity</b>: Constant.
@@ -1086,6 +1114,12 @@ class set
static const set &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const set &>(Base::container_from_end_iterator(end_iterator)); }
static set &container_from_iterator(iterator it)
{ return static_cast<set &>(Base::container_from_iterator(it)); }
static const set &container_from_iterator(const_iterator it)
{ return static_cast<const set &>(Base::container_from_iterator(it)); }
};
#endif
@@ -1318,6 +1352,34 @@ class multiset_impl
, &multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
static multiset_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
static const multiset_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &multiset_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the multiset.
//!
//! <b>Complexity</b>: Constant.
@@ -1932,6 +1994,21 @@ class multiset_impl
void replace_node(iterator replace_this, reference with_this)
{ tree_.replace_node(replace_this, with_this); }
//! <b>Effects</b>: removes "value" from the container.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic time.
//!
//! <b>Note</b>: This static function is only usable with non-constant
//! time size containers that have stateless comparison functors.
//!
//! If the user calls
//! this function with a constant time size container or stateful comparison
//! functor a compilation error will be issued.
static void remove_node(reference value)
{ tree_type::remove_node(value); }
/// @cond
friend bool operator==(const multiset_impl &x, const multiset_impl &y)
{ return x.tree_ == y.tree_; }
@@ -2058,6 +2135,12 @@ class multiset
static const multiset &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const multiset &>(Base::container_from_end_iterator(end_iterator)); }
static multiset &container_from_iterator(iterator it)
{ return static_cast<multiset &>(Base::container_from_iterator(it)); }
static const multiset &container_from_iterator(const_iterator it)
{ return static_cast<const multiset &>(Base::container_from_iterator(it)); }
};
#endif

View File

@@ -252,6 +252,34 @@ class sg_set_impl
, &sg_set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of set.
//!
//! <b>Effects</b>: Returns a reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static sg_set_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<sg_set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &sg_set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of set.
//!
//! <b>Effects</b>: Returns a const reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const sg_set_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<sg_set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &sg_set_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the sg_set.
//!
//! <b>Complexity</b>: Constant.
@@ -1124,6 +1152,12 @@ class sg_set
static const sg_set &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const sg_set &>(Base::container_from_end_iterator(end_iterator)); }
static sg_set &container_from_iterator(iterator it)
{ return static_cast<sg_set &>(Base::container_from_iterator(it)); }
static const sg_set &container_from_iterator(const_iterator it)
{ return static_cast<const sg_set &>(Base::container_from_iterator(it)); }
};
#endif
@@ -1356,6 +1390,34 @@ class sg_multiset_impl
, &sg_multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
static sg_multiset_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<sg_multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &sg_multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
static const sg_multiset_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<sg_multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &sg_multiset_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the sg_multiset.
//!
//! <b>Complexity</b>: Constant.
@@ -2135,6 +2197,12 @@ class sg_multiset
static const sg_multiset &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const sg_multiset &>(Base::container_from_end_iterator(end_iterator)); }
static sg_multiset &container_from_iterator(iterator it)
{ return static_cast<sg_multiset &>(Base::container_from_iterator(it)); }
static const sg_multiset &container_from_iterator(const_iterator it)
{ return static_cast<const sg_multiset &>(Base::container_from_iterator(it)); }
};
#endif

View File

@@ -527,6 +527,28 @@ class sgtree_impl
static const sgtree_impl &container_from_end_iterator(const_iterator end_iterator)
{ return priv_container_from_end_iterator(end_iterator); }
//! <b>Precondition</b>: it must be a valid iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static sgtree_impl &container_from_iterator(iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Precondition</b>: it must be a valid end const_iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const sgtree_impl &container_from_iterator(const_iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Effects</b>: Returns the value_compare object used by the tree.
//!
//! <b>Complexity</b>: Constant.
@@ -1442,6 +1464,9 @@ class sgtree_impl
sgtree_impl *scapegoat = detail::parent_from_member<sgtree_impl, data_t>(d, &sgtree_impl::data_);
return *scapegoat;
}
static sgtree_impl &priv_container_from_iterator(const const_iterator &it)
{ return priv_container_from_end_iterator(it.end_iterator_from_it()); }
};
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED

View File

@@ -22,7 +22,6 @@
#include <cstddef>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/tree_algorithms.hpp>
@@ -640,6 +639,16 @@ class sgtree_algorithms
static node_ptr rebalance_subtree(node_ptr old_root)
{ return tree_algorithms::rebalance_subtree(old_root); }
//! <b>Requires</b>: "n" must be a node inserted in a tree.
//!
//! <b>Effects</b>: Returns a pointer to the header node of the tree.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: Nothing.
static node_ptr get_header(node_ptr n)
{ return tree_algorithms::get_header(n); }
/// @cond
private:

View File

@@ -16,7 +16,6 @@
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/static_assert.hpp>
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/slist_hook.hpp>
@@ -25,6 +24,7 @@
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <iterator>
#include <functional>
#include <algorithm>
@@ -183,10 +183,12 @@ class slist_impl
BOOST_STATIC_ASSERT(!(cache_last && ((int)real_value_traits::link_mode == (int)auto_unlink)));
node_ptr get_end_node()
{ return node_ptr(linear ? 0 : this->get_root_node()); }
{ return node_ptr(linear ? node_ptr(0) : this->get_root_node()); }
const_node_ptr get_end_node() const
{ return const_node_ptr(linear ? 0 : this->get_root_node()); }
{
return const_node_ptr
(linear ? const_node_ptr(0) : this->get_root_node()); }
node_ptr get_root_node()
{ return node_ptr(&data_.root_plus_size_.root_); }
@@ -203,13 +205,10 @@ class slist_impl
void set_last_node(node_ptr n)
{ return this->set_last_node(n, detail::bool_<cache_last>()); }
node_ptr get_last_node(detail::bool_<false>)
static node_ptr get_last_node(detail::bool_<false>)
{ return node_ptr(0); }
const_node_ptr get_last_node(detail::bool_<false>) const
{ return const_node_ptr(0); }
void set_last_node(node_ptr, detail::bool_<false>)
static void set_last_node(node_ptr, detail::bool_<false>)
{}
node_ptr get_last_node(detail::bool_<true>)
@@ -667,18 +666,14 @@ class slist_impl
void clone_from(const slist_impl &src, Cloner cloner, Disposer disposer)
{
this->clear_and_dispose(disposer);
BOOST_INTRUSIVE_TRY{
iterator prev(this->before_begin());
const_iterator b(src.begin()), e(src.end());
for(; b != e; ++b){
prev = this->insert_after(prev, *cloner(*b));
}
detail::exception_disposer<slist_impl, Disposer>
rollback(*this, disposer);
iterator prev(this->before_begin());
const_iterator b(src.begin()), e(src.end());
for(; b != e; ++b){
prev = this->insert_after(prev, *cloner(*b));
}
BOOST_INTRUSIVE_CATCH(...){
this->clear_and_dispose(disposer);
BOOST_INTRUSIVE_RETHROW;
}
BOOST_INTRUSIVE_CATCH_END
rollback.release();
}
//! <b>Requires</b>: value must be an lvalue and prev_p must point to an element
@@ -849,13 +844,36 @@ class slist_impl
if(cache_last && (to_erase == this->get_last_node())){
this->set_last_node(prev_n);
}
this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
disposer(get_real_value_traits().to_value_ptr(to_erase));
this->priv_size_traits().decrement();
return it;
}
/// @cond
template<class Disposer>
static iterator s_erase_after_and_dispose(iterator prev, Disposer disposer)
{
BOOST_STATIC_ASSERT(((!cache_last)&&(!constant_time_size)&&(!stateful_value_traits)));
iterator it(prev);
++it;
node_ptr to_erase(it.pointed_node());
++it;
node_ptr prev_n(prev.pointed_node());
node_algorithms::unlink_after(prev_n);
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
disposer(real_value_traits::to_value_ptr(to_erase));
return it;
}
static iterator s_erase_after(iterator prev)
{ return s_erase_after_and_dispose(prev, detail::null_disposer()); }
/// @endcond
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
//! <b>Effects</b>: Erases the range (before_first, last) from

View File

@@ -252,6 +252,34 @@ class splay_set_impl
, &splay_set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of set.
//!
//! <b>Effects</b>: Returns a reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
static splay_set_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<splay_set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &splay_set_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of set.
//!
//! <b>Effects</b>: Returns a const reference to the set associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const splay_set_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<splay_set_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &splay_set_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the splay_set.
//!
//! <b>Complexity</b>: Constant.
@@ -1161,6 +1189,12 @@ class splay_set
static const splay_set &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const splay_set &>(Base::container_from_end_iterator(end_iterator)); }
static splay_set &container_from_iterator(iterator it)
{ return static_cast<splay_set &>(Base::container_from_iterator(it)); }
static const splay_set &container_from_iterator(const_iterator it)
{ return static_cast<const splay_set &>(Base::container_from_iterator(it)); }
};
#endif
@@ -1393,6 +1427,34 @@ class splay_multiset_impl
, &splay_multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static splay_multiset_impl &container_from_iterator(iterator it)
{
return *detail::parent_from_member<splay_multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &splay_multiset_impl::tree_);
}
//! <b>Precondition</b>: it must be a valid const_iterator of multiset.
//!
//! <b>Effects</b>: Returns a const reference to the multiset associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
static const splay_multiset_impl &container_from_iterator(const_iterator it)
{
return *detail::parent_from_member<splay_multiset_impl, tree_type>
( &tree_type::container_from_iterator(it)
, &splay_multiset_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the splay_multiset.
//!
//! <b>Complexity</b>: Constant.
@@ -2209,6 +2271,12 @@ class splay_multiset
static const splay_multiset &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const splay_multiset &>(Base::container_from_end_iterator(end_iterator)); }
static splay_multiset &container_from_iterator(iterator it)
{ return static_cast<splay_multiset &>(Base::container_from_iterator(it)); }
static const splay_multiset &container_from_iterator(const_iterator it)
{ return static_cast<const splay_multiset &>(Base::container_from_iterator(it)); }
};
#endif

View File

@@ -387,6 +387,28 @@ class splaytree_impl
static const splaytree_impl &container_from_end_iterator(const_iterator end_iterator)
{ return priv_container_from_end_iterator(end_iterator); }
//! <b>Precondition</b>: it must be a valid iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static splaytree_impl &container_from_iterator(iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Precondition</b>: it must be a valid end const_iterator
//! of rbtree.
//!
//! <b>Effects</b>: Returns a const reference to the tree associated to the iterator
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Logarithmic.
static const splaytree_impl &container_from_iterator(const_iterator it)
{ return priv_container_from_iterator(it); }
//! <b>Effects</b>: Returns the value_compare object used by the tree.
//!
//! <b>Complexity</b>: Constant.
@@ -1312,6 +1334,9 @@ class splaytree_impl
splaytree_impl *rb = detail::parent_from_member<splaytree_impl, data_t>(d, &splaytree_impl::data_);
return *rb;
}
static splaytree_impl &priv_container_from_iterator(const const_iterator &it)
{ return priv_container_from_end_iterator(it.end_iterator_from_it()); }
};
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED

View File

@@ -50,13 +50,48 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <cstddef>
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/tree_algorithms.hpp>
namespace boost {
namespace intrusive {
/// @cond
namespace detail {
template<class NodeTraits>
struct splaydown_rollback
{
typedef typename NodeTraits::node_ptr node_ptr;
splaydown_rollback( const node_ptr *pcur_subtree, node_ptr header
, node_ptr leftmost , node_ptr rightmost)
: pcur_subtree_(pcur_subtree) , header_(header)
, leftmost_(leftmost) , rightmost_(rightmost)
{}
void release()
{ pcur_subtree_ = 0; }
~splaydown_rollback()
{
if(pcur_subtree_){
//Exception can only be thrown by comp, but
//tree invariants still hold. *pcur_subtree is the current root
//so link it to the header.
NodeTraits::set_parent(*pcur_subtree_, header_);
NodeTraits::set_parent(header_, *pcur_subtree_);
//Recover leftmost/rightmost pointers
NodeTraits::set_left (header_, leftmost_);
NodeTraits::set_right(header_, rightmost_);
}
}
const node_ptr *pcur_subtree_;
node_ptr header_, leftmost_, rightmost_;
};
} //namespace detail {
/// @endcond
//! A splay tree is an implementation of a binary search tree. The tree is
//! self balancing using the splay algorithm as described in
//!
@@ -656,7 +691,8 @@ class splaytree_algorithms
node_ptr leftmost = NodeTraits::get_left(header);
node_ptr rightmost = NodeTraits::get_right(header);
try{
{
detail::splaydown_rollback<NodeTraits> rollback(&t, header, leftmost, rightmost);
node_ptr null = header;
node_ptr l = null;
node_ptr r = null;
@@ -712,18 +748,9 @@ class splaytree_algorithms
}
assemble(t, l, r, null);
rollback.release();
}
catch(...){
//Exception can only be thrown by comp, but
//tree invariants still hold. t is the current root
//so link it to the header.
NodeTraits::set_parent(t, header);
NodeTraits::set_parent(header, t);
//Recover leftmost/rightmost pointers
NodeTraits::set_left (header, leftmost);
NodeTraits::set_right(header, rightmost);
throw;
}
//t is the current root
NodeTraits::set_parent(header, t);
NodeTraits::set_parent(t, header);
@@ -755,6 +782,17 @@ class splaytree_algorithms
static node_ptr rebalance_subtree(node_ptr old_root)
{ return tree_algorithms::rebalance_subtree(old_root); }
//! <b>Requires</b>: "n" must be a node inserted in a tree.
//!
//! <b>Effects</b>: Returns a pointer to the header node of the tree.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: Nothing.
static node_ptr get_header(node_ptr n)
{ return tree_algorithms::get_header(n); }
private:
/// @cond

View File

@@ -38,7 +38,8 @@ namespace intrusive {
//!
//! The container supports the following options:
//! \c base_hook<>/member_hook<>/value_traits<>,
//! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<> .
//! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<>
//! \c bucket_traits<>, power_2_buckets<> and cache_begin<>.
//!
//! unordered_set only provides forward iterators but it provides 4 iterator types:
//! iterator and const_iterator to navigate through the whole container and
@@ -167,8 +168,8 @@ class unordered_set_impl
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_set.
//!
//! <b>Complexity</b>: Amortized constant time.
//! Worst case (empty unordered_set): O(this->bucket_count())
//! <b>Complexity</b>: Constant time if `cache_begin<>` is true. Amortized
//! constant time with worst case (empty unordered_set) O(this->bucket_count())
//!
//! <b>Throws</b>: Nothing.
iterator begin()
@@ -177,8 +178,8 @@ class unordered_set_impl
//! <b>Effects</b>: Returns a const_iterator pointing to the beginning
//! of the unordered_set.
//!
//! <b>Complexity</b>: Amortized constant time.
//! Worst case (empty unordered_set): O(this->bucket_count())
//! <b>Complexity</b>: Constant time if `cache_begin<>` is true. Amortized
//! constant time with worst case (empty unordered_set) O(this->bucket_count())
//!
//! <b>Throws</b>: Nothing.
const_iterator begin() const
@@ -187,8 +188,8 @@ class unordered_set_impl
//! <b>Effects</b>: Returns a const_iterator pointing to the beginning
//! of the unordered_set.
//!
//! <b>Complexity</b>: Amortized constant time.
//! Worst case (empty unordered_set): O(this->bucket_count())
//! <b>Complexity</b>: Constant time if `cache_begin<>` is true. Amortized
//! constant time with worst case (empty unordered_set) O(this->bucket_count())
//!
//! <b>Throws</b>: Nothing.
const_iterator cbegin() const
@@ -236,8 +237,8 @@ class unordered_set_impl
//! <b>Effects</b>: Returns true is the container is empty.
//!
//! <b>Complexity</b>: if constant-time size option is disabled, average constant time
//! (worst case, with empty() == true): O(this->bucket_count()).
//! <b>Complexity</b>: if constant-time size and cache_last options are disabled,
//! average constant time (worst case, with empty() == true: O(this->bucket_count()).
//! Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
@@ -959,7 +960,7 @@ template<class T, class ...Options>
template<class T, class O1 = none, class O2 = none
, class O3 = none, class O4 = none
, class O5 = none, class O6 = none
, class O7 = none
, class O7 = none, class O8 = none
>
#endif
struct make_unordered_set
@@ -967,19 +968,19 @@ struct make_unordered_set
/// @cond
typedef unordered_set_impl
< typename make_hashtable_opt
<T, O1, O2, O3, O4, O5, O6, O7>::type
<T, true, O1, O2, O3, O4, O5, O6, O7, O8>::type
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7>
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8>
class unordered_set
: public make_unordered_set<T, O1, O2, O3, O4, O5, O6, O7>::type
: public make_unordered_set<T, O1, O2, O3, O4, O5, O6, O7, O8>::type
{
typedef typename make_unordered_set
<T, O1, O2, O3, O4, O5, O6, O7>::type Base;
<T, O1, O2, O3, O4, O5, O6, O7, O8>::type Base;
//Assert if passed value traits are compatible with the type
BOOST_STATIC_ASSERT((detail::is_same<typename Base::value_traits::value_type, T>::value));
@@ -1032,7 +1033,8 @@ class unordered_set
//!
//! The container supports the following options:
//! \c base_hook<>/member_hook<>/value_traits<>,
//! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<> .
//! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<>
//! \c bucket_traits<>, power_2_buckets<> and cache_begin<>.
//!
//! unordered_multiset only provides forward iterators but it provides 4 iterator types:
//! iterator and const_iterator to navigate through the whole container and
@@ -1161,8 +1163,8 @@ class unordered_multiset_impl
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_multiset.
//!
//! <b>Complexity</b>: Amortized constant time.
//! Worst case (empty unordered_multiset): O(this->bucket_count())
//! <b>Complexity</b>: Constant time if `cache_begin<>` is true. Amortized
//! constant time with worst case (empty unordered_set) O(this->bucket_count())
//!
//! <b>Throws</b>: Nothing.
iterator begin()
@@ -1171,8 +1173,8 @@ class unordered_multiset_impl
//! <b>Effects</b>: Returns a const_iterator pointing to the beginning
//! of the unordered_multiset.
//!
//! <b>Complexity</b>: Amortized constant time.
//! Worst case (empty unordered_multiset): O(this->bucket_count())
//! <b>Complexity</b>: Constant time if `cache_begin<>` is true. Amortized
//! constant time with worst case (empty unordered_set) O(this->bucket_count())
//!
//! <b>Throws</b>: Nothing.
const_iterator begin() const
@@ -1181,8 +1183,8 @@ class unordered_multiset_impl
//! <b>Effects</b>: Returns a const_iterator pointing to the beginning
//! of the unordered_multiset.
//!
//! <b>Complexity</b>: Amortized constant time.
//! Worst case (empty unordered_multiset): O(this->bucket_count())
//! <b>Complexity</b>: Constant time if `cache_begin<>` is true. Amortized
//! constant time with worst case (empty unordered_set) O(this->bucket_count())
//!
//! <b>Throws</b>: Nothing.
const_iterator cbegin() const
@@ -1230,8 +1232,8 @@ class unordered_multiset_impl
//! <b>Effects</b>: Returns true is the container is empty.
//!
//! <b>Complexity</b>: if constant-time size option is disabled, average constant time
//! (worst case, with empty() == true): O(this->bucket_count()).
//! <b>Complexity</b>: if constant-time size and cache_last options are disabled,
//! average constant time (worst case, with empty() == true: O(this->bucket_count()).
//! Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
@@ -1891,7 +1893,7 @@ template<class T, class ...Options>
template<class T, class O1 = none, class O2 = none
, class O3 = none, class O4 = none
, class O5 = none, class O6 = none
, class O7 = none
, class O7 = none, class O8 = none
>
#endif
struct make_unordered_multiset
@@ -1899,19 +1901,19 @@ struct make_unordered_multiset
/// @cond
typedef unordered_multiset_impl
< typename make_hashtable_opt
<T, O1, O2, O3, O4, O5, O6, O7>::type
<T, false, O1, O2, O3, O4, O5, O6, O7, O8>::type
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7>
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8>
class unordered_multiset
: public make_unordered_multiset<T, O1, O2, O3, O4, O5, O6, O7>::type
: public make_unordered_multiset<T, O1, O2, O3, O4, O5, O6, O7, O8>::type
{
typedef typename make_unordered_multiset
<T, O1, O2, O3, O4, O5, O6, O7>::type Base;
<T, O1, O2, O3, O4, O5, O6, O7, O8>::type Base;
//Assert if passed value traits are compatible with the type
BOOST_STATIC_ASSERT((detail::is_same<typename Base::value_traits::value_type, T>::value));

View File

@@ -17,6 +17,7 @@
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/slist_hook.hpp>
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/generic_hook.hpp>
@@ -26,35 +27,69 @@ namespace intrusive {
/// @cond
template<class VoidPointer>
struct slist_node_plus_hash
template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
struct unordered_node
: public slist_node<VoidPointer>
{
typedef typename boost::pointer_to_other
<VoidPointer, slist_node_plus_hash>::type node_ptr;
node_ptr next_;
< VoidPointer
, unordered_node<VoidPointer, StoreHash, OptimizeMultiKey>
>::type node_ptr;
// node_ptr next_;
node_ptr prev_in_group_;
std::size_t hash_;
};
// slist_node_traits can be used with circular_slist_algorithms and supplies
// a slist_node holding the pointers needed for a singly-linked list
// it is used by slist_base_hook and slist_member_hook
template<class VoidPointer>
struct slist_node_traits_plus_hash
struct unordered_node<VoidPointer, false, true>
: public slist_node<VoidPointer>
{
typedef slist_node_plus_hash<VoidPointer> node;
typedef typename boost::pointer_to_other
< VoidPointer
, unordered_node<VoidPointer, false, true>
>::type node_ptr;
// node_ptr next_;
node_ptr prev_in_group_;
};
template<class VoidPointer>
struct unordered_node<VoidPointer, true, false>
: public slist_node<VoidPointer>
{
typedef typename boost::pointer_to_other
< VoidPointer
, unordered_node<VoidPointer, true, false>
>::type node_ptr;
// node_ptr next_;
std::size_t hash_;
};
template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
struct unordered_node_traits
: public slist_node_traits<VoidPointer>
{
typedef slist_node_traits<VoidPointer> reduced_slist_node_traits;
typedef unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
static const bool store_hash = true;
static const bool store_hash = StoreHash;
static const bool optimize_multikey = OptimizeMultiKey;
static node_ptr get_next(const_node_ptr n)
{ return n->next_; }
{ return node_ptr(&static_cast<node &>(*n->next_)); }
static void set_next(node_ptr n, node_ptr next)
{ n->next_ = next; }
static node_ptr get_prev_in_group(const_node_ptr n)
{ return n->prev_in_group_; }
static void set_prev_in_group(node_ptr n, node_ptr prev)
{ n->prev_in_group_ = prev; }
static std::size_t get_hash(const_node_ptr n)
{ return n->hash_; }
@@ -62,15 +97,68 @@ struct slist_node_traits_plus_hash
{ n->hash_ = h; }
};
template<class VoidPointer, bool StoreHash>
template<class VoidPointer, class Node>
struct unordered_group_node_traits
{
typedef Node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
static node_ptr get_next(const_node_ptr n)
{ return n->prev_in_group_; }
static void set_next(node_ptr n, node_ptr next)
{ n->prev_in_group_ = next; }
};
template<class NodeTraits>
struct unordered_algorithms
: public circular_slist_algorithms<NodeTraits>
{
typedef circular_slist_algorithms<NodeTraits> base_type;
typedef unordered_group_node_traits
< typename boost::pointer_to_other
< typename NodeTraits::node_ptr
, void
>::type
, typename NodeTraits::node
> group_traits;
typedef circular_slist_algorithms<group_traits> group_algorithms;
static void init(typename base_type::node_ptr n)
{
base_type::init(n);
group_algorithms::init(n);
}
static void init_header(typename base_type::node_ptr n)
{
base_type::init_header(n);
group_algorithms::init_header(n);
}
static void unlink(typename base_type::node_ptr n)
{
base_type::unlink(n);
group_algorithms::unlink(n);
}
};
template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
struct get_uset_node_algo
{
typedef typename detail::if_c
< StoreHash
, slist_node_traits_plus_hash<VoidPointer>
< (StoreHash || OptimizeMultiKey)
, unordered_node_traits<VoidPointer, StoreHash, OptimizeMultiKey>
, slist_node_traits<VoidPointer>
>::type node_traits_type;
typedef circular_slist_algorithms<node_traits_type> type;
typedef typename detail::if_c
< OptimizeMultiKey
, unordered_algorithms<node_traits_type>
, circular_slist_algorithms<node_traits_type>
>::type type;
};
/// @endcond
@@ -90,6 +178,7 @@ struct make_unordered_set_base_hook
typedef detail::generic_hook
< get_uset_node_algo<typename packed_options::void_pointer
, packed_options::store_hash
, packed_options::optimize_multikey
>
, typename packed_options::tag
, packed_options::link_mode
@@ -104,7 +193,7 @@ struct make_unordered_set_base_hook
//! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
//!
//! The hook admits the following options: \c tag<>, \c void_pointer<>,
//! \c link_mode<> and \c store_hash<>.
//! \c link_mode<>, \c store_hash<> and \c optimize_multikey<>.
//!
//! \c tag<> defines a tag to identify the node.
//! The same tag value can be used in different classes, but if a class is
@@ -119,6 +208,10 @@ struct make_unordered_set_base_hook
//!
//! \c store_hash<> will tell the hook to store the hash of the value
//! to speed up rehashings.
//!
//! \c optimize_multikey<> will tell the hook to store a link to form a group
//! with other value with the same value to speed up searches and insertions
//! in unordered_multisets with a great number of with equivalent keys.
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class ...Options>
#else
@@ -211,6 +304,7 @@ struct make_unordered_set_member_hook
typedef detail::generic_hook
< get_uset_node_algo< typename packed_options::void_pointer
, packed_options::store_hash
, packed_options::optimize_multikey
>
, member_tag
, packed_options::link_mode

View File

@@ -4,6 +4,6 @@
</head>
<body>
Automatic redirection failed, please go to
<a href="../../doc/html/intrusive.html">../../doc/html/intrusive.html</a>
<a href="../../doc/html/intrusive">../../doc/html/intrusive</a>
</body>
</html>

View File

@@ -23,7 +23,7 @@ using namespace boost::posix_time;
//[perf_list_value_type
//Iteration and element count defines
const int NumIter = 100;
const int NumElements = 100000;
const int NumElements = 50000;
using namespace boost::intrusive;

View File

@@ -154,10 +154,7 @@
RelativePath="..\..\..\..\..\boost\intrusive\options.hpp">
</File>
<File
RelativePath="..\..\..\..\..\boost\intrusive\pointer_plus_2_bits.hpp">
</File>
<File
RelativePath="..\..\..\..\..\boost\intrusive\pointer_plus_bit.hpp">
RelativePath="..\..\..\..\..\boost\intrusive\pointer_plus_bits.hpp">
</File>
<File
RelativePath="..\..\..\..\..\boost\intrusive\rbtree.hpp">
@@ -240,9 +237,6 @@
<File
RelativePath="..\..\..\..\..\boost\intrusive\detail\mpl.hpp">
</File>
<File
RelativePath="..\..\..\..\..\boost\intrusive\detail\no_exceptions_support.hpp">
</File>
<File
RelativePath="..\..\..\..\..\boost\intrusive\detail\parent_from_member.hpp">
</File>

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

@@ -0,0 +1,11 @@
Add resize() to list
Implement incremental hashing
Add invariants to slist and test them after every operation
Create a generic hook that will work with all containers
Take advantage of store_hash in lookups: Instead of comparing objects, just
compare hashes. This will improve equality for expensive objects.
Improve the use of cache_begin to unordered containers:
-> Speed up rehash

View File

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

View File

@@ -52,8 +52,37 @@ struct test_generic_assoc
static void test_rebalance(std::vector<value_type>& values);
static void test_rebalance(std::vector<value_type>& values, boost::intrusive::detail::true_type);
static void test_rebalance(std::vector<value_type>& values, boost::intrusive::detail::false_type);
static void test_container_from_iterator(std::vector<value_type>& values);
};
template<class ValueTraits, template <class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none> class ContainerDefiner>
void test_generic_assoc<ValueTraits, ContainerDefiner>::
test_container_from_iterator(std::vector<value_type>& values)
{
typedef typename ContainerDefiner
< value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
>::type assoc_type;
assoc_type testset(values.begin(), values.end());
typedef typename assoc_type::iterator it_type;
typedef typename assoc_type::const_iterator cit_type;
typedef typename assoc_type::size_type sz_type;
sz_type sz = testset.size();
for(it_type b(testset.begin()), e(testset.end()); b != e; ++b)
{
assoc_type &s = assoc_type::container_from_iterator(b);
const assoc_type &cs = assoc_type::container_from_iterator(cit_type(b));
BOOST_TEST(&s == &cs);
BOOST_TEST(&s == &testset);
s.erase(b);
BOOST_TEST(testset.size() == (sz-1));
s.insert(*b);
BOOST_TEST(testset.size() == sz);
}
}
template<class ValueTraits, template <class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none> class ContainerDefiner>
void test_generic_assoc<ValueTraits, ContainerDefiner>::test_insert_erase_burst()
{
@@ -103,12 +132,14 @@ void test_generic_assoc<ValueTraits, ContainerDefiner>::test_insert_erase_burst(
template<class ValueTraits, template <class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none> class ContainerDefiner>
void test_generic_assoc<ValueTraits, ContainerDefiner>::test_all(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
test_clone(values);
test_container_from_end(values);
test_splay_up(values);
test_splay_down(values);
test_rebalance(values);
test_insert_erase_burst();
test_container_from_iterator(values);
}
template<class ValueTraits, template <class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none> class ContainerDefiner>

View File

@@ -35,6 +35,7 @@ struct test_generic_set
static void test_impl();
};
template<class ValueTraits, template <class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none, class = ::boost::intrusive::none> class ContainerDefiner>
void test_generic_set<ValueTraits, ContainerDefiner>::test_all()
{

View File

@@ -126,20 +126,30 @@ template<class VoidPointer>
struct uset_auto_base_hook_type
{
typedef unordered_set_base_hook
< link_mode<auto_unlink>, void_pointer<VoidPointer>
, tag<my_tag>, store_hash<true> > type;
< link_mode<auto_unlink>
, void_pointer<VoidPointer>
, tag<my_tag>
, store_hash<true>
> type;
};
template<class VoidPointer>
struct uset_member_hook_type
{ typedef unordered_set_member_hook<void_pointer<VoidPointer> > type; };
{
typedef unordered_set_member_hook
< void_pointer<VoidPointer>
, optimize_multikey<true>
> type;
};
template<class VoidPointer>
struct uset_auto_member_hook_type
{
typedef unordered_set_member_hook
< link_mode<auto_unlink>, void_pointer<VoidPointer>
, store_hash<true> > type;
, store_hash<true>
, optimize_multikey<true>
> type;
};
template<class VoidPointer, bool ConstantTimeSize>
@@ -318,6 +328,49 @@ struct testvalue
slist_auto_node_.swap_nodes(other.slist_auto_node_);
}
bool is_linked() const
{
//Set
return set_base_hook_t::is_linked() ||
set_auto_base_hook_t::is_linked() ||
set_node_.is_linked() ||
set_auto_node_.is_linked() ||
//SplaySet
splay_set_base_hook_t::is_linked() ||
splay_set_auto_base_hook_t::is_linked() ||
splay_set_node_.is_linked() ||
splay_set_auto_node_.is_linked() ||
//ScapeoatSet
bs_set_base_hook_t::is_linked() ||
sg_set_node_.is_linked() ||
//AvlSet
avl_set_base_hook_t::is_linked() ||
avl_set_auto_base_hook_t::is_linked() ||
avl_set_node_.is_linked() ||
avl_set_auto_node_.is_linked() ||
//Unordered set
unordered_set_base_hook_t::is_linked() ||
unordered_set_auto_base_hook_t::is_linked() ||
unordered_set_node_.is_linked() ||
unordered_set_auto_node_.is_linked() ||
//List
list_base_hook_t::is_linked() ||
list_auto_base_hook_t::is_linked() ||
list_node_.is_linked() ||
list_auto_node_.is_linked() ||
//Slist
slist_base_hook_t::is_linked() ||
slist_auto_base_hook_t::is_linked() ||
slist_node_.is_linked() ||
slist_auto_node_.is_linked();
}
~testvalue()
{}

View File

@@ -12,8 +12,7 @@
#define BOOST_INTRUSIVE_SMART_PTR_HPP
#include <boost/iterator.hpp>
#include <boost/intrusive/pointer_plus_bit.hpp>
#include <boost/intrusive/pointer_plus_2_bits.hpp>
#include <boost/intrusive/pointer_plus_bits.hpp>
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -109,7 +108,7 @@ class smart_ptr
public: //Public Functions
//!Constructor from raw pointer (allows "0" pointer conversion). Never throws.
smart_ptr(pointer ptr = 0)
explicit smart_ptr(pointer ptr = 0)
: m_ptr(ptr)
{}
@@ -351,67 +350,34 @@ namespace boost{
//for intrusive containers, saving space
namespace intrusive {
template<std::size_t N>
struct has_pointer_plus_bit<smart_ptr<void>, N>
template<std::size_t Alignment>
struct max_pointer_plus_bits<smart_ptr<void>, Alignment>
{
static const bool value = has_pointer_plus_bit<void*, N>::value;
static const std::size_t value = max_pointer_plus_bits<void*, Alignment>::value;
};
//Specialization
template<class T>
struct pointer_plus_bit<smart_ptr<T> >
template<class T, std::size_t NumBits>
struct pointer_plus_bits<smart_ptr<T>, NumBits>
{
typedef smart_ptr<T> pointer;
static pointer get_pointer(const pointer &n)
{ return pointer_plus_bit<T*>::get_pointer(n.get()); }
{ return pointer_plus_bits<T*, NumBits>::get_pointer(n.get()); }
static void set_pointer(pointer &n, pointer p)
{
T *raw_n = n.get();
pointer_plus_bit<T*>::set_pointer(raw_n, p.get());
n = raw_n;
}
static bool get_bit(const pointer &n)
{ return pointer_plus_bit<T*>::get_bit(n.get()); }
static void set_bit(pointer &n, bool c)
{
T *raw_n = n.get();
pointer_plus_bit<T*>::set_bit(raw_n, c);
n = raw_n;
}
};
template<std::size_t N>
struct has_pointer_plus_2_bits<smart_ptr<void>, N>
{
static const bool value = has_pointer_plus_2_bits<void*, N>::value;
};
template<class T>
struct pointer_plus_2_bits<smart_ptr<T> >
{
typedef smart_ptr<T> pointer;
static pointer get_pointer(const pointer &n)
{ return pointer_plus_2_bits<T*>::get_pointer(n.get()); }
static void set_pointer(pointer &n, pointer p)
{
T *raw_n = n.get();
pointer_plus_2_bits<T*>::set_pointer(raw_n, p.get());
pointer_plus_bits<T*, NumBits>::set_pointer(raw_n, p.get());
n = raw_n;
}
static std::size_t get_bits(const pointer &n)
{ return pointer_plus_2_bits<T*>::get_bits(n.get()); }
{ return pointer_plus_bits<T*, NumBits>::get_bits(n.get()); }
static void set_bits(pointer &n, std::size_t c)
{
T *raw_n = n.get();
pointer_plus_2_bits<T*>::set_bits(raw_n, c);
pointer_plus_bits<T*, NumBits>::set_bits(raw_n, c);
n = raw_n;
}
};

View File

@@ -18,6 +18,7 @@
#include "smart_ptr.hpp"
#include "common_functors.hpp"
#include <vector>
#include <algorithm> //std::sort std::find
#include <set>
#include <boost/detail/lightweight_test.hpp>
#include "test_macros.hpp"
@@ -27,7 +28,7 @@ using namespace boost::intrusive;
static const std::size_t BucketSize = 11;
template<class ValueTraits>
template<class ValueTraits, bool CacheBegin>
struct test_unordered_multiset
{
typedef typename ValueTraits::value_type value_type;
@@ -41,14 +42,15 @@ struct test_unordered_multiset
static void test_clone(std::vector<value_type>& values);
};
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>::test_all (std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>::test_all (std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
< value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
{
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -76,14 +78,15 @@ void test_unordered_multiset<ValueTraits>::test_all (std::vector<typename ValueT
}
//test case due to an error in tree implementation:
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>::test_impl()
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>::test_impl()
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -106,14 +109,15 @@ void test_unordered_multiset<ValueTraits>::test_impl()
}
//test: constructor, iterator, clear, reverse_iterator, front, back, size:
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>::test_sort(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>::test_sort(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -127,104 +131,187 @@ void test_unordered_multiset<ValueTraits>::test_sort(std::vector<typename ValueT
}
//test: insert, const_iterator, const_reverse_iterator, erase, iterator_to:
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>::test_insert(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>::test_insert(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
typedef typename unordered_multiset_type::iterator iterator;
{
typename unordered_multiset_type::bucket_type buckets [BucketSize];
unordered_multiset_type testset(bucket_traits(buckets, BucketSize));
typename unordered_multiset_type::bucket_type buckets [BucketSize];
unordered_multiset_type testset(bucket_traits(buckets, BucketSize));
testset.insert(&values[0] + 2, &values[0] + 5);
testset.insert(&values[0] + 2, &values[0] + 5);
const unordered_multiset_type& const_testset = testset;
{ int init_values [] = { 1, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
const unordered_multiset_type& const_testset = testset;
{ int init_values [] = { 1, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
typename unordered_multiset_type::iterator i = testset.begin();
BOOST_TEST (i->value_ == 1);
typename unordered_multiset_type::iterator i = testset.begin();
BOOST_TEST (i->value_ == 1);
i = testset.insert (values[0]);
BOOST_TEST (&*i == &values[0]);
i = testset.iterator_to (values[2]);
BOOST_TEST (&*i == &values[2]);
testset.erase(i);
i = testset.insert (values[0]);
BOOST_TEST (&*i == &values[0]);
i = testset.iterator_to (values[2]);
BOOST_TEST (&*i == &values[2]);
testset.erase(i);
{ int init_values [] = { 1, 3, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
testset.clear();
testset.insert(&values[0], &values[0] + values.size());
{ int init_values [] = { 1, 3, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
testset.clear();
testset.insert(&values[0], &values[0] + values.size());
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE( init_values, const_testset.begin() ); }
BOOST_TEST (testset.erase(1) == 1);
BOOST_TEST (testset.erase(2) == 2);
BOOST_TEST (testset.erase(3) == 1);
BOOST_TEST (testset.erase(4) == 1);
BOOST_TEST (testset.erase(5) == 1);
BOOST_TEST (testset.empty() == true);
BOOST_TEST (testset.erase(1) == 1);
BOOST_TEST (testset.erase(2) == 2);
BOOST_TEST (testset.erase(3) == 1);
BOOST_TEST (testset.erase(4) == 1);
BOOST_TEST (testset.erase(5) == 1);
BOOST_TEST (testset.empty() == true);
//Now with a single bucket
typename unordered_multiset_type::bucket_type single_bucket[1];
unordered_multiset_type testset2(bucket_traits(single_bucket, 1));
testset2.insert(&values[0], &values[0] + values.size());
BOOST_TEST (testset2.erase(5) == 1);
BOOST_TEST (testset2.erase(2) == 2);
BOOST_TEST (testset2.erase(1) == 1);
BOOST_TEST (testset2.erase(4) == 1);
BOOST_TEST (testset2.erase(3) == 1);
BOOST_TEST (testset2.empty() == true);
}
{
//Now erase just one per loop
const int random_init[] = { 3, 2, 4, 1, 5, 2, 2 };
const unsigned int random_size = sizeof(random_init)/sizeof(random_init[0]);
typename unordered_multiset_type::bucket_type single_bucket[1];
for(unsigned int i = 0, max = random_size; i != max; ++i){
std::vector<typename ValueTraits::value_type> data (random_size);
for (unsigned int j = 0; j < random_size; ++j)
data[j].value_ = random_init[j];
unordered_multiset_type testset_new(bucket_traits(single_bucket, 1));
testset_new.insert(&data[0], &data[max]);
testset_new.erase(testset_new.iterator_to(data[i]));
BOOST_TEST (testset_new.size() == (max -1));
}
}
{
typename unordered_multiset_type::bucket_type buckets [BucketSize];
const unsigned int NumBucketSize = BucketSize;
const unsigned int LoadFactor = 3;
const unsigned int NumIterations = NumBucketSize*LoadFactor;
std::vector<value_type> random_init(NumIterations);//Preserve memory
std::vector<value_type> set_tester;
set_tester.reserve(NumIterations);
//Now with a single bucket
typename unordered_multiset_type::bucket_type single_bucket[1];
unordered_multiset_type testset2(bucket_traits(single_bucket, 1));
testset2.insert(&values[0], &values[0] + values.size());
BOOST_TEST (testset2.erase(5) == 1);
BOOST_TEST (testset2.erase(2) == 2);
BOOST_TEST (testset2.erase(1) == 1);
BOOST_TEST (testset2.erase(4) == 1);
BOOST_TEST (testset2.erase(3) == 1);
BOOST_TEST (testset2.empty() == true);
//Initialize values
for (unsigned int i = 0; i < NumIterations; ++i){
random_init[i].value_ = i*2;//(i/LoadFactor)*LoadFactor;
}
for(unsigned int initial_pos = 0; initial_pos != (NumIterations+1); ++initial_pos){
for(unsigned int final_pos = initial_pos; final_pos != (NumIterations+1); ++final_pos){
//Create intrusive container inserting values
unordered_multiset_type testset
( &random_init[0]
, &random_init[0] + random_init.size()
, bucket_traits(buckets, NumBucketSize));
BOOST_TEST (testset.size() == random_init.size());
//Obtain the iterator range to erase
iterator it_beg_pos = testset.begin();
for(unsigned int it_beg_pos_num = 0; it_beg_pos_num != initial_pos; ++it_beg_pos_num){
++it_beg_pos;
}
iterator it_end_pos(it_beg_pos);
for(unsigned int it_end_pos_num = 0; it_end_pos_num != (final_pos - initial_pos); ++it_end_pos_num){
++it_end_pos;
}
//Erase the same values in both the intrusive and original vector
std::size_t erased_cnt = std::distance(it_beg_pos, it_end_pos);
//Erase values from the intrusive container
testset.erase(it_beg_pos, it_end_pos);
BOOST_TEST (testset.size() == (random_init.size()-(final_pos - initial_pos)));
//Now test...
BOOST_TEST ((random_init.size() - erased_cnt) == testset.size());
//Create an ordered copy of the intrusive container
set_tester.insert(set_tester.end(), testset.begin(), testset.end());
std::sort(set_tester.begin(), set_tester.end());
{
typename std::vector<value_type>::iterator it = set_tester.begin(), itend = set_tester.end();
typename std::vector<value_type>::iterator random_init_it(random_init.begin());
for( ; it != itend; ++it){
while(!random_init_it->is_linked())
++random_init_it;
BOOST_TEST(*it == *random_init_it);
++random_init_it;
}
}
set_tester.clear();
}
}
}
}
//test: insert (seq-version), swap, erase (seq-version), size:
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>::test_swap(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>::test_swap(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
typename unordered_multiset_type::bucket_type buckets [BucketSize];
typename unordered_multiset_type::bucket_type buckets2 [BucketSize];
unordered_multiset_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets, BucketSize));
unordered_multiset_type testset2(bucket_traits(buckets2, BucketSize));
{
typename unordered_multiset_type::bucket_type buckets2 [BucketSize];
unordered_multiset_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets, BucketSize));
unordered_multiset_type testset2(bucket_traits(buckets2, BucketSize));
testset2.insert (&values[0] + 2, &values[0] + 6);
testset1.swap (testset2);
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 [] = { 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]);
{ 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: rehash:
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>::test_rehash(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>::test_rehash(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -261,14 +348,15 @@ void test_unordered_multiset<ValueTraits>::test_rehash(std::vector<typename Valu
}
//test: find, equal_range (lower_bound, upper_bound):
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>::test_find(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>::test_find(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_multiset
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
@@ -293,8 +381,8 @@ void test_unordered_multiset<ValueTraits>::test_find(std::vector<typename ValueT
}
template<class ValueTraits>
void test_unordered_multiset<ValueTraits>
template<class ValueTraits, bool CacheBegin>
void test_unordered_multiset<ValueTraits, CacheBegin>
::test_clone(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
@@ -302,6 +390,7 @@ void test_unordered_multiset<ValueTraits>
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_multiset_type;
typedef typename unordered_multiset_type::bucket_traits bucket_traits;
{
@@ -373,6 +462,7 @@ class test_main_template
< value_type
, typename value_type::unordered_set_base_hook_t
>::type
, true
>::test_all(data);
test_unordered_multiset < typename detail::get_member_value_traits
@@ -382,6 +472,7 @@ class test_main_template
, &value_type::unordered_set_node_
>
>::type
, false
>::test_all(data);
return 0;
@@ -404,6 +495,7 @@ class test_main_template<VoidPointer, false>
< value_type
, typename value_type::unordered_set_base_hook_t
>::type
, true
>::test_all(data);
test_unordered_multiset < typename detail::get_member_value_traits
@@ -413,12 +505,14 @@ class test_main_template<VoidPointer, false>
, &value_type::unordered_set_node_
>
>::type
, false
>::test_all(data);
test_unordered_multiset < typename detail::get_base_value_traits
< value_type
, typename value_type::unordered_set_auto_base_hook_t
>::type
, true
>::test_all(data);
test_unordered_multiset < typename detail::get_member_value_traits
@@ -428,6 +522,7 @@ class test_main_template<VoidPointer, false>
, &value_type::unordered_set_auto_node_
>
>::type
, false
>::test_all(data);
return 0;
}

View File

@@ -26,7 +26,7 @@ using namespace boost::intrusive;
static const std::size_t BucketSize = 11;
template<class ValueTraits>
template<class ValueTraits, bool CacheBegin>
struct test_unordered_set
{
typedef typename ValueTraits::value_type value_type;
@@ -40,14 +40,15 @@ struct test_unordered_set
static void test_clone(std::vector<value_type>& values);
};
template<class ValueTraits>
void test_unordered_set<ValueTraits>::test_all(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>::test_all(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
{
@@ -75,14 +76,15 @@ void test_unordered_set<ValueTraits>::test_all(std::vector<typename ValueTraits:
}
//test case due to an error in tree implementation:
template<class ValueTraits>
void test_unordered_set<ValueTraits>::test_impl()
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>::test_impl()
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -103,14 +105,15 @@ void test_unordered_set<ValueTraits>::test_impl()
}
//test: constructor, iterator, clear, reverse_iterator, front, back, size:
template<class ValueTraits>
void test_unordered_set<ValueTraits>::test_sort(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>::test_sort(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -126,14 +129,15 @@ void test_unordered_set<ValueTraits>::test_sort(std::vector<typename ValueTraits
}
//test: insert, const_iterator, const_reverse_iterator, erase, iterator_to:
template<class ValueTraits>
void test_unordered_set<ValueTraits>::test_insert(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>::test_insert(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -161,14 +165,15 @@ void test_unordered_set<ValueTraits>::test_insert(std::vector<typename ValueTrai
}
//test: insert (seq-version), swap, erase (seq-version), size:
template<class ValueTraits>
void test_unordered_set<ValueTraits>::test_swap(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>::test_swap(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -192,14 +197,15 @@ void test_unordered_set<ValueTraits>::test_swap(std::vector<typename ValueTraits
}
//test: rehash:
template<class ValueTraits>
void test_unordered_set<ValueTraits>::test_rehash(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>::test_rehash(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -237,14 +243,15 @@ void test_unordered_set<ValueTraits>::test_rehash(std::vector<typename ValueTrai
//test: find, equal_range (lower_bound, upper_bound):
template<class ValueTraits>
void test_unordered_set<ValueTraits>::test_find(std::vector<typename ValueTraits::value_type>& values)
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>::test_find(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
typedef unordered_set
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
@@ -267,8 +274,8 @@ void test_unordered_set<ValueTraits>::test_find(std::vector<typename ValueTraits
BOOST_TEST (testset.find (cmp_val) == testset.end());
}
template<class ValueTraits>
void test_unordered_set<ValueTraits>
template<class ValueTraits, bool CacheBegin>
void test_unordered_set<ValueTraits, CacheBegin>
::test_clone(std::vector<typename ValueTraits::value_type>& values)
{
typedef typename ValueTraits::value_type value_type;
@@ -276,6 +283,7 @@ void test_unordered_set<ValueTraits>
<value_type
, value_traits<ValueTraits>
, constant_time_size<value_type::constant_time_size>
, cache_begin<CacheBegin>
> unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
{
@@ -347,6 +355,7 @@ class test_main_template
< value_type
, typename value_type::unordered_set_base_hook_t
>::type
, true
>::test_all(data);
test_unordered_set < typename detail::get_member_value_traits
< value_type
@@ -355,6 +364,7 @@ class test_main_template
, &value_type::unordered_set_node_
>
>::type
, false
>::test_all(data);
return 0;
@@ -377,6 +387,7 @@ class test_main_template<VoidPointer, false>
< value_type
, typename value_type::unordered_set_base_hook_t
>::type
, true
>::test_all(data);
test_unordered_set < typename detail::get_member_value_traits
@@ -386,12 +397,14 @@ class test_main_template<VoidPointer, false>
, &value_type::unordered_set_node_
>
>::type
, false
>::test_all(data);
test_unordered_set < typename detail::get_base_value_traits
< value_type
, typename value_type::unordered_set_auto_base_hook_t
>::type
, true
>::test_all(data);
test_unordered_set < typename detail::get_member_value_traits
@@ -401,6 +414,7 @@ class test_main_template<VoidPointer, false>
, &value_type::unordered_set_auto_node_
>
>::type
, false
>::test_all(data);
return 0;
}