|
Boost-Commit : |
From: igaztanaga_at_[hidden]
Date: 2007-09-26 11:26:38
Author: igaztanaga
Date: 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
New Revision: 39548
URL: http://svn.boost.org/trac/boost/changeset/39548
Log:
Changes introduced by the new intrusive version.
Added:
trunk/boost/intrusive/detail/generic_hook.hpp (contents, props changed)
trunk/boost/intrusive/detail/no_exceptions_support.hpp (contents, props changed)
trunk/boost/intrusive/detail/transform_iterator.hpp (contents, props changed)
trunk/boost/intrusive/link_mode.hpp (contents, props changed)
trunk/boost/intrusive/options.hpp (contents, props changed)
Removed:
trunk/boost/intrusive/linking_policy.hpp
trunk/boost/intrusive/tag.hpp
Text files modified:
trunk/boost/intrusive/circular_slist_algorithms.hpp | 1
trunk/boost/intrusive/derivation_value_traits.hpp | 7
trunk/boost/intrusive/detail/config_begin.hpp | 6
trunk/boost/intrusive/detail/ebo_functor_holder.hpp | 2
trunk/boost/intrusive/detail/hashtable_node.hpp | 296 +++-------
trunk/boost/intrusive/detail/list_node.hpp | 220 ++----
trunk/boost/intrusive/detail/mpl.hpp | 128 ++++
trunk/boost/intrusive/detail/parent_from_member.hpp | 13
trunk/boost/intrusive/detail/rbtree_node.hpp | 209 ++----
trunk/boost/intrusive/detail/slist_node.hpp | 206 ++----
trunk/boost/intrusive/detail/utilities.hpp | 435 ++++++++++----
trunk/boost/intrusive/hashtable.hpp | 1172 ++++++++++++++++++++++++++++-----------
trunk/boost/intrusive/intrusive_fwd.hpp | 203 ++++--
trunk/boost/intrusive/list.hpp | 574 ++++++++++++++-----
trunk/boost/intrusive/list_hook.hpp | 393 ++++--------
trunk/boost/intrusive/member_value_traits.hpp | 7
trunk/boost/intrusive/pointer_plus_bit.hpp | 4
trunk/boost/intrusive/rbtree.hpp | 704 +++++++++++++++++------
trunk/boost/intrusive/rbtree_algorithms.hpp | 547 ++++++++++++++++--
trunk/boost/intrusive/set.hpp | 691 +++++++++++++++++------
trunk/boost/intrusive/set_hook.hpp | 392 ++++--------
trunk/boost/intrusive/slist.hpp | 570 +++++++++++++-----
trunk/boost/intrusive/slist_hook.hpp | 386 ++++---------
trunk/boost/intrusive/trivial_value_traits.hpp | 12
trunk/boost/intrusive/unordered_set.hpp | 616 +++++++++++++-------
trunk/boost/intrusive/unordered_set_hook.hpp | 348 +++++------
26 files changed, 4994 insertions(+), 3148 deletions(-)
Modified: trunk/boost/intrusive/circular_slist_algorithms.hpp
==============================================================================
--- trunk/boost/intrusive/circular_slist_algorithms.hpp (original)
+++ trunk/boost/intrusive/circular_slist_algorithms.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -48,6 +48,7 @@
public:
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
+ typedef NodeTraits node_traits;
//! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
//!
Modified: trunk/boost/intrusive/derivation_value_traits.hpp
==============================================================================
--- trunk/boost/intrusive/derivation_value_traits.hpp (original)
+++ trunk/boost/intrusive/derivation_value_traits.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -13,7 +13,7 @@
#ifndef BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/link_mode.hpp>
#include <iterator>
namespace boost {
@@ -22,7 +22,7 @@
//!This value traits template is used to create value traits
//!from user defined node traits where value_traits::value_type will
//!derive from node_traits::node
-template<class T, class NodeTraits, linking_policy Policy>
+template<class T, class NodeTraits, link_mode_type LinkMode = safe_link>
struct derivation_value_traits
{
public:
@@ -35,8 +35,7 @@
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference;
-
- enum { linking_policy = Policy };
+ static const link_mode_type link_mode = LinkMode;
static node_ptr to_node_ptr(reference value)
{ return node_ptr(&value); }
Modified: trunk/boost/intrusive/detail/config_begin.hpp
==============================================================================
--- trunk/boost/intrusive/detail/config_begin.hpp (original)
+++ trunk/boost/intrusive/detail/config_begin.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -10,12 +10,10 @@
//
/////////////////////////////////////////////////////////////////////////////
-#ifndef BOOST_INTRUSIVE_SELECT_COMPILER_INCLUDED
-#ifndef BOOST_COMPILER_CONFIG
+#ifndef BOOST_INTRUSIVE_CONFIG_INCLUDED
+#define BOOST_INTRUSIVE_CONFIG_INCLUDED
#include <boost/config.hpp>
#endif
-#define BOOST_INTRUSIVE_SELECT_COMPILER_INCLUDED
-#endif
#ifdef BOOST_MSVC
Modified: trunk/boost/intrusive/detail/ebo_functor_holder.hpp
==============================================================================
--- trunk/boost/intrusive/detail/ebo_functor_holder.hpp (original)
+++ trunk/boost/intrusive/detail/ebo_functor_holder.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -35,7 +35,7 @@
template<typename T>
class ebo_functor_holder_impl<T, false>
- : private T
+ : public T
{
public:
ebo_functor_holder_impl(){}
Added: trunk/boost/intrusive/detail/generic_hook.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/intrusive/detail/generic_hook.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -0,0 +1,185 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// (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_GENERIC_HOOK_HPP
+#define BOOST_INTRUSIVE_GENERIC_HOOK_HPP
+
+#include <boost/intrusive/detail/config_begin.hpp>
+#include <boost/intrusive/intrusive_fwd.hpp>
+#include <boost/intrusive/detail/pointer_to_other.hpp>
+#include <boost/intrusive/link_mode.hpp>
+#include <boost/intrusive/detail/utilities.hpp>
+#include <boost/static_assert.hpp>
+
+namespace boost {
+namespace intrusive {
+namespace detail {
+
+/// @cond
+
+enum
+{ NoBaseHook
+, ListBaseHook
+, SlistBaseHook
+, SetBaseHook
+, UsetBaseHook
+};
+
+struct no_default_definer{};
+
+template <class Hook, unsigned int>
+struct default_definer;
+
+template <class Hook>
+struct default_definer<Hook, ListBaseHook>
+{ typedef Hook default_list_hook; };
+
+template <class Hook>
+struct default_definer<Hook, SlistBaseHook>
+{ typedef Hook default_slist_hook; };
+
+template <class Hook>
+struct default_definer<Hook, SetBaseHook>
+{ typedef Hook default_set_hook; };
+
+template <class Hook>
+struct default_definer<Hook, UsetBaseHook>
+{ typedef Hook default_uset_hook; };
+
+template <class Hook, unsigned int BaseHookType>
+struct make_default_definer
+{
+ typedef typename detail::if_c
+ < BaseHookType != 0
+ , default_definer<Hook, BaseHookType>
+ , no_default_definer>::type type;
+};
+
+template
+ < class GetNodeAlgorithms
+ , class Tag
+ , link_mode_type LinkMode
+ , int HookType
+ >
+struct make_node_holder
+{
+ typedef typename detail::if_c
+ <!detail::is_same<Tag, member_tag>::value
+ , detail::node_holder
+ < typename GetNodeAlgorithms::type::node_traits::node
+ , Tag
+ , LinkMode
+ , HookType>
+ , typename GetNodeAlgorithms::type::node_traits::node
+ >::type type;
+};
+
+/// @endcond
+
+template
+ < class GetNodeAlgorithms
+ , class Tag
+ , link_mode_type LinkMode
+ , int HookType
+ >
+class generic_hook
+ /// @cond
+
+ //If the hook is a base hook, derive generic hook from detail::node_holder
+ //so that a unique base class is created to convert from the node
+ //to the type. This mechanism will be used by base_hook_traits.
+ //
+ //If the hook is a member hook, generic hook will directly derive
+ //from the hook.
+ : public make_default_definer
+ < generic_hook<GetNodeAlgorithms, Tag, LinkMode, HookType>
+ , detail::is_same<Tag, default_tag>::value*HookType
+ >::type
+ , public make_node_holder<GetNodeAlgorithms, Tag, LinkMode, HookType>::type
+ /// @endcond
+{
+ public:
+ /// @cond
+ struct boost_intrusive_tags
+ {
+ static const int hook_type = HookType;
+ static const link_mode_type link_mode = LinkMode;
+ typedef Tag tag;
+ typedef typename GetNodeAlgorithms::type node_algorithms;
+ typedef typename node_algorithms::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename node_traits::const_node_ptr const_node_ptr;
+ static const bool is_base_hook = !detail::is_same<Tag, member_tag>::value;
+ enum { safemode_or_autounlink =
+ (int)link_mode == (int)auto_unlink ||
+ (int)link_mode == (int)safe_link };
+ };
+ /// @endcond
+
+ generic_hook()
+ {
+ if(boost_intrusive_tags::safemode_or_autounlink){
+ boost_intrusive_tags::node_algorithms::init
+ (static_cast<typename boost_intrusive_tags::node*>(this));
+ }
+ }
+
+ generic_hook(const generic_hook& )
+ {
+ if(boost_intrusive_tags::safemode_or_autounlink){
+ boost_intrusive_tags::node_algorithms::init
+ (static_cast<typename boost_intrusive_tags::node*>(this));
+ }
+ }
+
+ generic_hook& operator=(const generic_hook& )
+ { return *this; }
+
+ ~generic_hook()
+ {
+ destructor_impl
+ (*this, detail::link_dispatch<boost_intrusive_tags::link_mode>());
+ }
+
+ void swap_nodes(generic_hook &other)
+ {
+ boost_intrusive_tags::node_algorithms::swap_nodes
+ ( static_cast<typename boost_intrusive_tags::node*>(this)
+ , static_cast<typename boost_intrusive_tags::node*>(&other));
+ }
+
+ bool is_linked() const
+ {
+ //is_linked() can be only used in safe-mode or auto-unlink
+ BOOST_STATIC_ASSERT(( boost_intrusive_tags::safemode_or_autounlink ));
+ return !boost_intrusive_tags::node_algorithms::unique
+ (static_cast<const typename boost_intrusive_tags::node*>(this));
+ }
+
+ void unlink()
+ {
+ BOOST_STATIC_ASSERT(( (int)boost_intrusive_tags::link_mode == (int)auto_unlink ));
+ boost_intrusive_tags::node_algorithms::unlink
+ (static_cast<typename boost_intrusive_tags::node*>(this));
+ boost_intrusive_tags::node_algorithms::init
+ (static_cast<typename boost_intrusive_tags::node*>(this));
+ }
+};
+
+} //namespace detail
+} //namespace intrusive
+} //namespace boost
+
+#include <boost/intrusive/detail/config_end.hpp>
+
+#endif //BOOST_INTRUSIVE_GENERIC_HOOK_HPP
Modified: trunk/boost/intrusive/detail/hashtable_node.hpp
==============================================================================
--- trunk/boost/intrusive/detail/hashtable_node.hpp (original)
+++ trunk/boost/intrusive/detail/hashtable_node.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -18,14 +18,9 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp>
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-#include <boost/iterator/iterator_facade.hpp>
-#endif
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
-#include <boost/utility/enable_if.hpp>
-#include <boost/type_traits/is_convertible.hpp>
-#endif
#include <boost/intrusive/detail/mpl.hpp>
+#include <boost/intrusive/detail/utilities.hpp>
+#include <boost/intrusive/detail/slist_node.hpp> //remove-me
#include <cstddef>
namespace boost {
@@ -52,27 +47,34 @@
const std::size_t prime_list_holder<Dummy>::prime_list_size
= sizeof(prime_list)/sizeof(std::size_t);
-template <class SlistImpl>
-struct bucket_type_impl
- : public SlistImpl
+template <class Slist>
+struct bucket_impl : public Slist
{
- bucket_type_impl()
+ bucket_impl()
{}
- bucket_type_impl(const bucket_type_impl &)
+ bucket_impl(const bucket_impl &)
{}
- bucket_type_impl &operator=(const bucket_type_impl&)
- { SlistImpl::clear(); }
+ ~bucket_impl()
+ {
+ //This bucket is still being used!
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
+ }
+
+ bucket_impl &operator=(const bucket_impl&)
+ {
+ //This bucket is still in use!
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
+ //Slist::clear();
+ }
- static typename std::iterator_traits
- <typename SlistImpl::const_iterator>::difference_type
- get_bucket_num
- ( typename SlistImpl::const_iterator it
- , const bucket_type_impl<SlistImpl> &first_bucket
- , const bucket_type_impl<SlistImpl> &last_bucket)
+ 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 SlistImpl::const_iterator
+ typename Slist::const_iterator
first(first_bucket.cend()), last(last_bucket.cend());
//The end node is embedded in the singly linked list:
@@ -81,252 +83,130 @@
it.pointed_node() <= last.pointed_node())){
++it;
}
- //Now get the bucket_type_impl from the iterator
- const bucket_type_impl &b = static_cast<const bucket_type_impl&>
- (SlistImpl::container_from_end_iterator(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;
}
-
- static SlistImpl &bucket_to_slist(bucket_type_impl<SlistImpl> &b)
- { return static_cast<SlistImpl &>(b); }
-
- static const SlistImpl &bucket_to_slist(const bucket_type_impl<SlistImpl> &b)
- { return static_cast<const SlistImpl &>(b); }
-};
-
-template<class SlistImpl>
-struct bucket_info_impl
-{
- typedef typename boost::pointer_to_other
- < typename SlistImpl::pointer
- , bucket_type_impl<SlistImpl> >::type bucket_ptr;
- typedef typename SlistImpl::size_type size_type;
- bucket_ptr buckets_;
- size_type buckets_len_;
};
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-
-template<class Value, class SlistImpl>
-class hashtable_iterator
- : public boost::iterator_facade
- < hashtable_iterator<Value, SlistImpl>
- , Value
- , boost::forward_traversal_tag
- , Value&
- , typename std::iterator_traits<typename SlistImpl::iterator>::difference_type
- >
+template<class Slist>
+struct bucket_traits_impl
{
- typedef typename SlistImpl::iterator local_iterator;
- typedef typename SlistImpl::const_iterator const_local_iterator;
- typedef typename SlistImpl::value_traits::node_ptr node_ptr;
- typedef typename SlistImpl::value_traits::const_node_ptr const_node_ptr;
-
- typedef bucket_type_impl<SlistImpl> bucket_type;
+ /// @cond
typedef typename boost::pointer_to_other
- < typename SlistImpl::pointer, bucket_type>::type bucket_ptr;
- typedef typename boost::pointer_to_other
- < typename SlistImpl::pointer, const bucket_type>::type const_bucket_ptr;
- typedef detail::bucket_info_impl<SlistImpl> bucket_info_t;
- typedef typename boost::pointer_to_other
- <bucket_ptr, bucket_info_t>::type bucket_info_ptr;
- typedef typename boost::pointer_to_other
- <bucket_ptr, const bucket_info_t>::type const_bucket_info_ptr;
- typedef typename SlistImpl::size_type size_type;
- struct enabler {};
+ < typename Slist::pointer, bucket_impl<Slist> >::type bucket_ptr;
+ typedef typename Slist::size_type size_type;
+ /// @endcond
- public:
- hashtable_iterator ()
- {}
-
- explicit hashtable_iterator(local_iterator ptr, const_bucket_info_ptr bucket_info)
- : local_it_ (ptr), bucket_info_ (bucket_info)
- {}
-
-
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,Value*>
- , enabler
- >::type = enabler()
- )
- : local_it_(other.local_it_), bucket_info_(other.bucket_info_)
- {}
- #else
- template <class OtherValue>
- hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other,
- typename enable_if<
- is_convertible<OtherValue*,T*>
- >::type* = 0)
- : local_it_(other.local_it_), bucket_info_(other.bucket_info_)
+ bucket_traits_impl(bucket_ptr buckets, size_type len)
+ : buckets_(buckets), buckets_len_(len)
{}
- #endif
- const local_iterator &local() const
- { return local_it_; }
+ bucket_ptr bucket_begin() const
+ { return buckets_; }
- const_node_ptr pointed_node() const
- { return local_it_.pointed_node(); }
-
- const const_bucket_info_ptr &bucket_info() const
- { return bucket_info_; }
+ size_type bucket_count() const
+ { return buckets_len_; }
private:
- friend class boost::iterator_core_access;
- template <class, class> friend class hashtable_iterator;
-
- template <class OtherValue>
- bool equal(hashtable_iterator<OtherValue, SlistImpl> const& other) const
- { return other.local() == local_it_; }
-
- void increment()
- {
- size_type buckets_len = bucket_info_->buckets_len_;
- const_bucket_ptr buckets = bucket_info_->buckets_;
- const_local_iterator first = bucket_type::bucket_to_slist(buckets[0]).cend();
- const_local_iterator last = bucket_type::bucket_to_slist(buckets[buckets_len]).cend();
-
- ++local_it_;
- if(first.pointed_node() <= local_it_.pointed_node() &&
- local_it_.pointed_node() <= last.pointed_node()){
- size_type n_bucket = (size_type)
- bucket_type::get_bucket_num(local_it_, buckets[0], buckets[buckets_len]);
- do{
- if (++n_bucket == buckets_len){
- local_it_ = bucket_info_->buckets_->end();
- break;
- }
- local_it_ = bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).begin();
- }
- while (local_it_ == bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).end());
- }
- }
-
- Value& dereference() const
- { return *local_it_; }
-
- local_iterator local_it_;
- const_bucket_info_ptr bucket_info_;
+ bucket_ptr buckets_;
+ size_type buckets_len_;
};
-#else
-
-template<class T, class SlistImpl>
+template<class Container, bool IsConst>
class hashtable_iterator
- : public std::iterator<std::forward_iterator_tag, T>
+ : public std::iterator
+ < std::forward_iterator_tag
+ , typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>::type
+ >
{
- typedef typename SlistImpl::iterator local_iterator;
- typedef typename SlistImpl::const_iterator const_local_iterator;
- typedef typename SlistImpl::value_traits::node_ptr node_ptr;
- typedef typename SlistImpl::value_traits::const_node_ptr const_node_ptr;
-
- typedef bucket_type_impl<SlistImpl> bucket_type;
- typedef typename boost::pointer_to_other
- < typename SlistImpl::pointer, bucket_type>::type bucket_ptr;
- typedef typename boost::pointer_to_other
- < typename SlistImpl::pointer, const bucket_type>::type const_bucket_ptr;
- typedef detail::bucket_info_impl<SlistImpl> bucket_info_t;
- typedef typename boost::pointer_to_other
- <bucket_ptr, bucket_info_t>::type bucket_info_ptr;
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename Container::siterator siterator;
+ typedef typename Container::const_siterator const_siterator;
+ typedef typename Container::bucket_type bucket_type;
typedef typename boost::pointer_to_other
- <bucket_ptr, const bucket_info_t>::type const_bucket_info_ptr;
- typedef typename SlistImpl::size_type size_type;
- struct enabler {};
+ < typename Container::pointer, const Container>::type const_cont_ptr;
+ typedef typename Container::size_type size_type;
public:
- typedef T & reference;
- typedef T * pointer;
+ typedef typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>::type value_type;
hashtable_iterator ()
{}
- explicit hashtable_iterator(local_iterator ptr, const_bucket_info_ptr bucket_info)
- : local_it_ (ptr), bucket_info_ (bucket_info)
+ explicit hashtable_iterator(siterator ptr, const Container *cont)
+ : slist_it_ (ptr), cont_ (cont)
{}
-
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,T*>
- , enabler
- >::type = enabler()
- )
- : local_it_(other.local_it_), bucket_info_(other.bucket_info_)
- {}
- #else
- template <class OtherValue>
- hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other,
- typename enable_if<is_convertible<OtherValue*, T*> >::type* = 0)
- : local_it_(other.local_it_), bucket_info_(other.bucket_info_)
+ hashtable_iterator(const hashtable_iterator<Container, false> &other)
+ : slist_it_(other.slist_it()), cont_(other.get_container())
{}
- #endif
-
- const local_iterator &local() const
- { return local_it_; }
-
- const_node_ptr pointed_node() const
- { return local_it_.pointed_node(); }
- const const_bucket_info_ptr &bucket_info() const
- { return bucket_info_; }
+ const siterator &slist_it() const
+ { return slist_it_; }
public:
hashtable_iterator& operator++()
- { increment(); return *this; }
+ { this->increment(); return *this; }
hashtable_iterator operator++(int)
{
hashtable_iterator result (*this);
- increment();
+ this->increment();
return result;
}
friend bool operator== (const hashtable_iterator& i, const hashtable_iterator& i2)
- { return i.pointed_node() == i2.pointed_node(); }
+ { return i.slist_it_ == i2.slist_it_; }
friend bool operator!= (const hashtable_iterator& i, const hashtable_iterator& i2)
{ return !(i == i2); }
- T& operator*() const
- { return *local_it_; }
+ value_type& operator*() const
+ { return *this->operator ->(); }
- pointer operator->() const
- { return &(*local_it_); }
+ value_type* operator->() const
+ { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(slist_it_.pointed_node())); }
+
+ const Container *get_container() const
+ { return detail::get_pointer(cont_); }
+
+ const real_value_traits *get_real_value_traits() const
+ { return &this->get_container()->get_real_value_traits(); }
private:
void increment()
{
- size_type buckets_len = bucket_info_->buckets_len_;
- const_bucket_ptr buckets = bucket_info_->buckets_;
- const_local_iterator first = bucket_type::bucket_to_slist(buckets[0]).cend();
- const_local_iterator last = bucket_type::bucket_to_slist(buckets[buckets_len]).cend();
-
- ++local_it_;
- if(first.pointed_node() <= local_it_.pointed_node() &&
- local_it_.pointed_node() <= last.pointed_node()){
+ 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(local_it_, buckets[0], buckets[buckets_len]);
+ bucket_type::get_bucket_num(slist_it_, buckets[0], buckets[buckets_len]);
do{
if (++n_bucket == buckets_len){
- local_it_ = bucket_info_->buckets_->end();
+ slist_it_ = buckets->end();
break;
}
- local_it_ = bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).begin();
+ slist_it_ = buckets[n_bucket].begin();
}
- while (local_it_ == bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).end());
+ while (slist_it_ == buckets[n_bucket].end());
}
}
- local_iterator local_it_;
- const_bucket_info_ptr bucket_info_;
+ siterator slist_it_;
+ const_cont_ptr cont_;
};
-#endif
} //namespace detail {
} //namespace intrusive {
Modified: trunk/boost/intrusive/detail/list_node.hpp
==============================================================================
--- trunk/boost/intrusive/detail/list_node.hpp (original)
+++ trunk/boost/intrusive/detail/list_node.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -19,35 +19,31 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp>
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-#include <boost/iterator/iterator_facade.hpp>
-#endif
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
-#include <boost/utility/enable_if.hpp>
-#include <boost/type_traits/is_convertible.hpp>
-#endif
namespace boost {
namespace intrusive {
-namespace detail {
// list_node_traits can be used with circular_list_algorithms and supplies
// a list_node holding the pointers needed for a double-linked list
// it is used by list_derived_node and list_member_node
+
+template<class VoidPointer>
+struct list_node
+{
+ typedef typename boost::pointer_to_other
+ <VoidPointer, list_node>::type node_ptr;
+ node_ptr prev_, next_;
+};
+
template<class VoidPointer>
struct list_node_traits
{
- struct node;
+ typedef list_node<VoidPointer> 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;
- struct node
- {
- node_ptr prev_, next_;
- };
-
static node_ptr get_previous(const_node_ptr n)
{ return n->prev_; }
@@ -61,178 +57,126 @@
{ n->next_ = next; }
};
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-
-// list_iterator provides some basic functions for a
-// node oriented forward iterator:
-template<class T, class ValueTraits>
-class list_iterator
- : public boost::iterator_facade
- < list_iterator<T, ValueTraits>
- , T
- , boost::bidirectional_traversal_tag
- , T&
- , typename std::iterator_traits<typename ValueTraits::node_ptr>::difference_type
- >
-{
- typedef typename ValueTraits::node_traits node_traits;
- typedef typename node_traits::node node;
- typedef typename node_traits::node_ptr node_ptr;
- typedef typename node_traits::const_node_ptr const_node_ptr;
- struct enabler{};
-
- public:
- typedef typename pointer_to_other<typename ValueTraits::node_ptr, T>::type pointer;
- typedef typename std::iterator_traits<node_ptr>::difference_type difference_type;
-
- list_iterator ()
- : node_ (0)
- {}
-
- explicit list_iterator(node_ptr node)
- : node_ (node)
- {}
-
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- list_iterator(list_iterator<OtherValue, ValueTraits> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,T*>
- , enabler
- >::type = enabler()
- )
- : node_(other.pointed_node())
- {}
- #else
- template <class OtherValue>
- list_iterator(list_iterator<OtherValue, ValueTraits> const& other,
- typename enable_if<
- is_convertible<OtherValue*,T*>
- >::type* = 0)
- : node_(other.pointed_node())
- {}
- #endif
-
- const node_ptr &pointed_node() const
- { return node_; }
-
- private:
- friend class boost::iterator_core_access;
- template <class, class> friend class list_iterator;
-
- template <class OtherValue>
- bool equal(list_iterator<OtherValue, ValueTraits> const& other) const
- { return other.pointed_node() == node_; }
-
- void increment()
- { node_ = node_traits::get_next(node_); }
-
- void decrement()
- { node_ = node_traits::get_previous(node_); }
-
- T& dereference() const
- { return *ValueTraits::to_value_ptr(node_); }
-
- node_ptr node_;
-};
-
-#else //BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-
// list_iterator provides some basic functions for a
// node oriented bidirectional iterator:
-template<class T, class ValueTraits>
+template<class Container, bool IsConst>
class list_iterator
- : public std::iterator<std::bidirectional_iterator_tag, T>
+ : public std::iterator
+ < std::bidirectional_iterator_tag
+ , typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>::type
+ >
{
- struct enabler{};
protected:
- typedef typename ValueTraits::node_traits node_traits;
- typedef typename node_traits::node node;
- typedef typename node_traits::node_ptr node_ptr;
-
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename real_value_traits::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename boost::pointer_to_other
+ <node_ptr, void>::type void_pointer;
+ static const bool store_container_ptr =
+ detail::store_cont_ptr_on_it<Container>::value;
+
public:
- typedef T & reference;
- typedef T * pointer;
+ typedef typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>
+ ::type value_type;
+ typedef value_type & reference;
+ typedef value_type * pointer;
list_iterator()
- : node_ (0)
+ : members_ (0, 0)
{}
- explicit list_iterator(node_ptr node)
- : node_ (node)
+ explicit list_iterator(node_ptr node, const Container *cont_ptr)
+ : members_ (node, cont_ptr)
{}
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- list_iterator(list_iterator<OtherValue, ValueTraits> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,T*>
- , enabler
- >::type = enabler()
- )
- : node_(other.pointed_node())
- {}
- #else
- template <class OtherValue>
- list_iterator(list_iterator<OtherValue, ValueTraits> const& other,
- typename enable_if<
- is_convertible<OtherValue*,T*>
- >::type* = 0)
- : node_(other.pointed_node())
+
+ list_iterator(list_iterator<Container, false> const& other)
+ : members_(other.pointed_node(), other.get_container())
{}
- #endif
const node_ptr &pointed_node() const
- { return node_; }
+ { return members_.nodeptr_; }
list_iterator &operator=(const node_ptr &node)
- { node_ = node; return static_cast<list_iterator&>(*this); }
+ { members_.nodeptr_ = node; return static_cast<list_iterator&>(*this); }
public:
list_iterator& operator++()
{
- node_ = node_traits::get_next(node_);
+ members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return static_cast<list_iterator&> (*this);
}
list_iterator operator++(int)
{
- list_iterator result (node_);
- node_ = node_traits::get_next(node_);
+ list_iterator result (*this);
+ members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return result;
}
list_iterator& operator--()
{
- node_ = node_traits::get_previous(node_);
+ members_.nodeptr_ = node_traits::get_previous(members_.nodeptr_);
return static_cast<list_iterator&> (*this);
}
list_iterator operator--(int)
{
- list_iterator result (node_);
- node_ = node_traits::get_previous(node_);
+ list_iterator result (*this);
+ members_.nodeptr_ = node_traits::get_previous(members_.nodeptr_);
return result;
}
bool operator== (const list_iterator& i) const
- { return node_ == i.pointed_node(); }
+ { return members_.nodeptr_ == i.pointed_node(); }
bool operator!= (const list_iterator& i) const
- { return !operator== (i); }
+ { return !operator== (i); }
- T& operator*() const
- { return *ValueTraits::to_value_ptr(node_); }
+ value_type& operator*() const
+ { return *operator->(); }
pointer operator->() const
- { return detail::get_pointer(ValueTraits::to_value_ptr(node_)); }
+ { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(members_.nodeptr_)); }
+
+ const Container *get_container() const
+ {
+ if(store_container_ptr){
+ const Container* c = static_cast<const Container*>(members_.get_ptr());
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(c != 0);
+ return c;
+ }
+ else{
+ return 0;
+ }
+ }
+
+ const real_value_traits *get_real_value_traits() const
+ {
+ if(store_container_ptr)
+ return &this->get_container()->get_real_value_traits();
+ else
+ return 0;
+ }
private:
- node_ptr node_;
-};
+ struct members
+ : public detail::select_constptr
+ <void_pointer, store_container_ptr>::type
+ {
+ typedef typename detail::select_constptr
+ <void_pointer, store_container_ptr>::type Base;
+
+ members(const node_ptr &n_ptr, const void *cont)
+ : Base(cont), nodeptr_(n_ptr)
+ {}
-#endif
+ node_ptr nodeptr_;
+ } members_;
+};
-} //namespace detail
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/detail/mpl.hpp
==============================================================================
--- trunk/boost/intrusive/detail/mpl.hpp (original)
+++ trunk/boost/intrusive/detail/mpl.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -17,6 +17,9 @@
namespace intrusive {
namespace detail {
+typedef char one;
+struct two {one _[2];};
+
template< bool C_ >
struct bool_
{
@@ -55,7 +58,61 @@
static false_t dispatch(...);
static T trigger();
public:
- enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) };
+ static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t);
+};
+
+template<
+ bool C
+ , typename T1
+ , typename T2
+ >
+struct if_c
+{
+ typedef T1 type;
+};
+
+template<
+ typename T1
+ , typename T2
+ >
+struct if_c<false,T1,T2>
+{
+ typedef T2 type;
+};
+
+template<
+ typename C
+ , typename T1
+ , typename T2
+ >
+struct if_
+{
+ typedef typename if_c<0 != C::value, T1, T2>::type type;
+};
+
+template<
+ bool C
+ , typename F1
+ , typename F2
+ >
+struct eval_if_c
+ : if_c<C,F1,F2>::type
+{};
+
+template<
+ typename C
+ , typename T1
+ , typename T2
+ >
+struct eval_if
+ : if_<C,T1,T2>::type
+{};
+
+// identity is an extension: it is not part of the standard.
+template <class T>
+struct identity
+{
+ typedef T type;
};
#if defined(BOOST_MSVC) || defined(__BORLANDC_)
@@ -130,18 +187,20 @@
template <typename T>
struct is_unary_or_binary_function_impl
{
- static T* t;
- enum{ value = sizeof(is_function_ptr_tester(t)) == sizeof(yes_type) };
+ static T* t;
+ static const bool value = sizeof(is_function_ptr_tester(t)) == sizeof(yes_type);
};
template <typename T>
struct is_unary_or_binary_function_impl<T&>
-{ enum {value = false }; };
+{
+ static const bool value = false;
+};
template<typename T>
struct is_unary_or_binary_function
{
- enum{ value = is_unary_or_binary_function_impl<T>::value };
+ static const bool value = is_unary_or_binary_function_impl<T>::value;
};
//boost::alignment_of yields to 10K lines of preprocessed code, so we
@@ -159,15 +218,68 @@
template <unsigned A, unsigned S>
struct alignment_logic
{
- enum{ value = A < S ? A : S };
+ static const std::size_t value = A < S ? A : S;
};
template< typename T >
struct alignment_of
{
- enum{ value = alignment_logic
+ static const std::size_t value = alignment_logic
< sizeof(alignment_of_hack<T>) - sizeof(T)
- , sizeof(T)>::value };
+ , sizeof(T)
+ >::value;
+};
+
+template <typename T, typename U>
+struct is_same
+{
+ typedef char yes_type;
+ struct no_type
+ {
+ char padding[8];
+ };
+
+ template <typename V>
+ static yes_type is_same_tester(V*, V*);
+ static no_type is_same_tester(...);
+
+ static T *t;
+ static U *u;
+
+ static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
+};
+
+template<typename T>
+struct add_const
+{ typedef const T type; };
+
+template<class T>
+struct remove_reference
+{
+ typedef T type;
+};
+
+template<class T>
+struct remove_reference<T&>
+{
+ typedef T type;
+};
+
+template<class Class>
+class is_empty_class
+{
+ template <typename T>
+ struct empty_helper_t1 : public T
+ {
+ empty_helper_t1();
+ int i[256];
+ };
+
+ struct empty_helper_t2
+ { int i[256]; };
+
+ public:
+ static const bool value = sizeof(empty_helper_t1<Class>) == sizeof(empty_helper_t2);
};
} //namespace detail
Added: trunk/boost/intrusive/detail/no_exceptions_support.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/intrusive/detail/no_exceptions_support.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -0,0 +1,28 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// (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
Modified: trunk/boost/intrusive/detail/parent_from_member.hpp
==============================================================================
--- trunk/boost/intrusive/detail/parent_from_member.hpp (original)
+++ trunk/boost/intrusive/detail/parent_from_member.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -13,6 +13,7 @@
#define BOOST_INTRUSIVE_PARENT_FROM_MEMBER_HPP
#include <boost/intrusive/detail/config_begin.hpp>
+#include <boost/static_assert.hpp>
#include <cstddef>
namespace boost {
@@ -22,14 +23,18 @@
template<class Parent, class Member>
inline std::size_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member)
{
+ //BOOST_STATIC_ASSERT(( sizeof(std::ptrdiff_t) == sizeof(ptr_to_member) ));
//The implementation of a pointer to member is compiler dependent.
- #if (defined(_MSC_VER) || defined(__GNUC__) || \
- defined(BOOST_INTEL) || defined(__HP_aCC))
- //This works with gcc, msvc, ac++
+ #if defined(BOOST_MSVC) || (defined (BOOST_WINDOWS) && defined(BOOST_INTEL))
+ //This works with gcc, msvc, ac++, ibmcpp
return *(const std::ptrdiff_t*)(void*)&ptr_to_member;
+ #elif defined(__GNUC__) || defined(__HP_aCC) || defined(BOOST_INTEL) || defined (__IBMCPP__)
+ const Parent * const parent = 0;
+ const char *const member = reinterpret_cast<const char*>(&(parent->*ptr_to_member));
+ return std::size_t(member - reinterpret_cast<const char*>(parent));
#else
//This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC
- return *(const std::ptrdiff_t*)(void*)&ptr_to_member - 1;
+ return (*(const std::ptrdiff_t*)(void*)&ptr_to_member) - 1;
#endif
}
Modified: trunk/boost/intrusive/detail/rbtree_node.hpp
==============================================================================
--- trunk/boost/intrusive/detail/rbtree_node.hpp (original)
+++ trunk/boost/intrusive/detail/rbtree_node.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -18,19 +18,11 @@
#include <iterator>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/rbtree_algorithms.hpp>
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-#include <boost/iterator/iterator_facade.hpp>
-#endif
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
-#include <boost/utility/enable_if.hpp>
-#include <boost/type_traits/is_convertible.hpp>
-#endif
#include <boost/intrusive/pointer_plus_bit.hpp>
#include <boost/intrusive/detail/mpl.hpp>
namespace boost {
namespace intrusive {
-namespace detail {
/////////////////////////////////////////////////////////////////////////////
// //
@@ -164,14 +156,14 @@
: public compact_rbtree_node_traits_impl<VoidPointer>
{};
-//Inherit from the dispatcher depending on the embedding capabilities
+//Inherit from the detail::link_dispatch depending on the embedding capabilities
template<class VoidPointer>
struct rbtree_node_traits
: public rbtree_node_traits_dispatch
- <VoidPointer
- ,has_pointer_plus_bit
- <VoidPointer, detail::alignment_of<compact_rbtree_node<VoidPointer>
- >::value
+ < VoidPointer
+ , has_pointer_plus_bit
+ < VoidPointer
+ , detail::alignment_of<compact_rbtree_node<VoidPointer> >::value
>::value
>
{};
@@ -182,179 +174,124 @@
// //
/////////////////////////////////////////////////////////////////////////////
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-
-template<class T, class ValueTraits>
-class rbtree_iterator
- : public boost::iterator_facade
- < rbtree_iterator<T, ValueTraits>
- , T
- , boost::bidirectional_traversal_tag
- , T&
- , typename std::iterator_traits<typename ValueTraits::node_ptr>::difference_type
- >
-{
- typedef typename ValueTraits::node_traits node_traits;
- typedef typename node_traits::node node;
- typedef typename node_traits::node_ptr node_ptr;
- typedef typename node_traits::const_node_ptr const_node_ptr;
- typedef rbtree_algorithms<node_traits> node_algorithms;
- struct enabler{};
-
- public:
- typedef typename pointer_to_other<typename ValueTraits::node_ptr, T>::type pointer;
- typedef typename std::iterator_traits<node_ptr>::difference_type difference_type;
-
- rbtree_iterator ()
- : node_ (0)
- {}
-
- explicit rbtree_iterator(node_ptr node)
- : node_ (node)
- {}
-
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,T*>
- , enabler
- >::type = enabler()
- )
- : node_(other.pointed_node())
- {}
- #else
- template <class OtherValue>
- rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other,
- typename enable_if<
- is_convertible<OtherValue*,T*>
- >::type* = 0)
- : node_(other.pointed_node())
- {}
- #endif
-
- const node_ptr &pointed_node() const
- { return node_; }
-
- private:
- friend class boost::iterator_core_access;
- template <class, class> friend class rbtree_iterator;
-
- template <class OtherValue>
- bool equal(rbtree_iterator<OtherValue, ValueTraits> const& other) const
- { return other.pointed_node() == node_; }
-
- void increment()
- { node_ = node_algorithms::next_node(node_); }
-
- void decrement()
- { node_ = node_algorithms::prev_node(node_); }
-
- T& dereference() const
- { return *ValueTraits::to_value_ptr(node_); }
-
- node_ptr node_;
-};
-
-#else
-
// rbtree_iterator provides some basic functions for a
// node oriented bidirectional iterator:
-template<class T, class ValueTraits>
+template<class Container, bool IsConst>
class rbtree_iterator
- : public std::iterator<std::bidirectional_iterator_tag, T>
+ : public std::iterator
+ < std::bidirectional_iterator_tag
+ , typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>::type
+ >
{
- struct enabler{};
protected:
- typedef typename ValueTraits::node_traits node_traits;
- typedef typename node_traits::node node;
- typedef typename node_traits::node_ptr node_ptr;
- typedef rbtree_algorithms<node_traits> node_algorithms;
-
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename real_value_traits::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef rbtree_algorithms<node_traits> node_algorithms;
+ typedef typename boost::pointer_to_other
+ <node_ptr, void>::type void_pointer;
+ static const bool store_container_ptr =
+ detail::store_cont_ptr_on_it<Container>::value;
+
public:
- typedef T & reference;
- typedef T * pointer;
+ public:
+ typedef typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>
+ ::type value_type;
+ typedef value_type & reference;
+ typedef value_type * pointer;
rbtree_iterator()
- : node_ (0)
+ : members_ (0, 0)
{}
- explicit rbtree_iterator(node_ptr node)
- : node_ (node)
+ explicit rbtree_iterator(node_ptr node, const Container *cont_ptr)
+ : members_ (node, cont_ptr)
{}
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,T*>
- , enabler
- >::type = enabler()
- )
- : node_(other.pointed_node())
- {}
- #else
- template <class OtherValue>
- rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other,
- typename enable_if<
- is_convertible<OtherValue*,T*>
- >::type* = 0)
- : node_(other.pointed_node())
+ rbtree_iterator(rbtree_iterator<Container, false> const& other)
+ : members_(other.pointed_node(), other.get_container())
{}
- #endif
const node_ptr &pointed_node() const
- { return node_; }
+ { return members_.nodeptr_; }
rbtree_iterator &operator=(const node_ptr &node)
- { node_ = node; return static_cast<rbtree_iterator&>(*this); }
+ { members_.nodeptr_ = node; return static_cast<rbtree_iterator&>(*this); }
public:
rbtree_iterator& operator++()
{
- node_ = node_algorithms::next_node(node_);
+ members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_);
return static_cast<rbtree_iterator&> (*this);
}
rbtree_iterator operator++(int)
{
- rbtree_iterator result (node_);
- node_ = node_algorithms::next_node(node_);
+ rbtree_iterator result (*this);
+ members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_);
return result;
}
rbtree_iterator& operator--()
{
- node_ = node_algorithms::prev_node(node_);
+ members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_);
return static_cast<rbtree_iterator&> (*this);
}
rbtree_iterator operator--(int)
{
- rbtree_iterator result (node_);
- node_ = node_algorithms::prev_node(node_);
+ rbtree_iterator result (*this);
+ members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_);
return result;
}
bool operator== (const rbtree_iterator& i) const
- { return node_ == i.pointed_node(); }
+ { return members_.nodeptr_ == i.pointed_node(); }
bool operator!= (const rbtree_iterator& i) const
{ return !operator== (i); }
- T& operator*() const
- { return *ValueTraits::to_value_ptr(node_); }
+ value_type& operator*() const
+ { return *operator->(); }
pointer operator->() const
- { return detail::get_pointer(ValueTraits::to_value_ptr(node_)); }
+ { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(members_.nodeptr_)); }
+
+ const Container *get_container() const
+ {
+ if(store_container_ptr)
+ return static_cast<const Container*>(members_.get_ptr());
+ else
+ return 0;
+ }
+
+ const real_value_traits *get_real_value_traits() const
+ {
+ if(store_container_ptr)
+ return &this->get_container()->get_real_value_traits();
+ else
+ return 0;
+ }
private:
- node_ptr node_;
-};
+ struct members
+ : public detail::select_constptr
+ <void_pointer, store_container_ptr>::type
+ {
+ typedef typename detail::select_constptr
+ <void_pointer, store_container_ptr>::type Base;
-#endif
+ members(const node_ptr &n_ptr, const void *cont)
+ : Base(cont), nodeptr_(n_ptr)
+ {}
+
+ node_ptr nodeptr_;
+ } members_;
+};
-} //namespace detail
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/detail/slist_node.hpp
==============================================================================
--- trunk/boost/intrusive/detail/slist_node.hpp (original)
+++ trunk/boost/intrusive/detail/slist_node.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -19,17 +19,17 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/circular_slist_algorithms.hpp>
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-#include <boost/iterator/iterator_facade.hpp>
-#endif
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
-#include <boost/utility/enable_if.hpp>
-#include <boost/type_traits/is_convertible.hpp>
-#endif
namespace boost {
namespace intrusive {
-namespace detail {
+
+template<class VoidPointer>
+struct slist_node
+{
+ typedef typename boost::pointer_to_other
+ <VoidPointer, slist_node>::type node_ptr;
+ node_ptr next_;
+};
// slist_node_traits can be used with circular_slist_algorithms and supplies
// a slist_node holding the pointers needed for a singly-linked list
@@ -37,18 +37,12 @@
template<class VoidPointer>
struct slist_node_traits
{
- struct node;
-
+ typedef slist_node<VoidPointer> 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;
- struct node
- {
- node_ptr next_;
- };
-
static node_ptr get_next(const_node_ptr n)
{ return n->next_; }
@@ -56,163 +50,109 @@
{ n->next_ = next; }
};
-#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
-
-// slist_iterator provides some basic functions for a
-// node oriented forward iterator:
-template<class T, class ValueTraits>
-class slist_iterator
- : public boost::iterator_facade
- < slist_iterator<T, ValueTraits>
- , T
- , boost::forward_traversal_tag
- , T&
- , typename std::iterator_traits<typename ValueTraits::node_ptr>::difference_type
- >
-{
- typedef typename ValueTraits::node_traits node_traits;
- typedef typename node_traits::node node;
- typedef typename node_traits::node_ptr node_ptr;
- typedef typename node_traits::const_node_ptr const_node_ptr;
- struct enabler{};
-
- public:
- typedef typename pointer_to_other<typename ValueTraits::node_ptr, T>::type pointer;
- typedef typename std::iterator_traits<node_ptr>::difference_type difference_type;
-
- slist_iterator ()
- : node_ (0)
- {}
-
- explicit slist_iterator(node_ptr node)
- : node_ (node)
- {}
-
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,T*>
- , enabler
- >::type = enabler()
- )
- : node_(other.pointed_node())
- {}
- #else
- template <class OtherValue>
- slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other,
- typename enable_if<
- is_convertible<OtherValue*,T*>
- >::type* = 0)
- : node_(other.pointed_node())
- {}
- #endif
-
- const node_ptr &pointed_node() const
- { return node_; }
-
- private:
- friend class boost::iterator_core_access;
- template <class, class> friend class slist_iterator;
-
- template <class OtherValue>
- bool equal(slist_iterator<OtherValue, ValueTraits> const& other) const
- { return other.pointed_node() == node_; }
-
- void increment()
- { node_ = node_traits::get_next(node_); }
-
- T& dereference() const
- { return *ValueTraits::to_value_ptr(node_); }
-
- node_ptr node_;
-};
-
-#else
-
// slist_iterator provides some basic functions for a
// node oriented bidirectional iterator:
-template<class T, class ValueTraits>
+template<class Container, bool IsConst>
class slist_iterator
- : public std::iterator<std::forward_iterator_tag, T>
+ : public std::iterator
+ < std::forward_iterator_tag
+ , typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>::type
+ >
{
- struct enabler{};
protected:
- typedef typename ValueTraits::node_traits node_traits;
- typedef typename node_traits::node node;
- typedef typename node_traits::node_ptr node_ptr;
-
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename real_value_traits::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename boost::pointer_to_other
+ <node_ptr, void>::type void_pointer;
+ static const bool store_container_ptr =
+ detail::store_cont_ptr_on_it<Container>::value;
+
public:
- typedef T & reference;
- typedef T * pointer;
+ typedef typename detail::add_const_if_c
+ <typename Container::value_type, IsConst>
+ ::type value_type;
+ typedef value_type & reference;
+ typedef value_type * pointer;
slist_iterator()
- : node_ (0)
+ : members_ (0, 0)
{}
- explicit slist_iterator(node_ptr node)
- : node_ (node)
+ explicit slist_iterator(node_ptr node, const Container *cont_ptr)
+ : members_ (node, cont_ptr)
{}
- #ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
- template <class OtherValue>
- slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other
- ,typename boost::enable_if<
- boost::is_convertible<OtherValue*,T*>
- , enabler
- >::type = enabler()
- )
- : node_(other.pointed_node())
+ slist_iterator(slist_iterator<Container, false> const& other)
+ : members_(other.pointed_node(), other.get_container())
{}
- #else
- template <class OtherValue>
- slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other,
- typename enable_if<
- is_convertible<OtherValue*,T*>
- >::type* = 0)
- : node_(other.pointed_node())
- {}
- #endif
const node_ptr &pointed_node() const
- { return node_; }
+ { return members_.nodeptr_; }
slist_iterator &operator=(const node_ptr &node)
- { node_ = node; return static_cast<slist_iterator&>(*this); }
+ { members_.nodeptr_ = node; return static_cast<slist_iterator&>(*this); }
public:
slist_iterator& operator++()
{
- node_ = node_traits::get_next(node_);
+ members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return static_cast<slist_iterator&> (*this);
}
slist_iterator operator++(int)
{
- slist_iterator result (node_);
- node_ = node_traits::get_next(node_);
+ slist_iterator result (*this);
+ members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return result;
}
bool operator== (const slist_iterator& i) const
- { return node_ == i.pointed_node(); }
+ { return members_.nodeptr_ == i.pointed_node(); }
bool operator!= (const slist_iterator& i) const
- { return !operator== (i); }
+ { return !operator== (i); }
- T& operator*() const
- { return *ValueTraits::to_value_ptr(node_); }
+ value_type& operator*() const
+ { return *operator->(); }
pointer operator->() const
- { return detail::get_pointer(ValueTraits::to_value_ptr(node_)); }
+ { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(members_.nodeptr_)); }
+
+ const Container *get_container() const
+ {
+ if(store_container_ptr)
+ return static_cast<const Container*>(members_.get_ptr());
+ else
+ return 0;
+ }
+
+ const real_value_traits *get_real_value_traits() const
+ {
+ if(store_container_ptr)
+ return &this->get_container()->get_real_value_traits();
+ else
+ return 0;
+ }
private:
- node_ptr node_;
-};
+ struct members
+ : public detail::select_constptr
+ <void_pointer, store_container_ptr>::type
+ {
+ typedef typename detail::select_constptr
+ <void_pointer, store_container_ptr>::type Base;
-#endif
+ members(const node_ptr &n_ptr, const void *cont)
+ : Base(cont), nodeptr_(n_ptr)
+ {}
+
+ node_ptr nodeptr_;
+ } members_;
+};
-} //namespace detail
} //namespace intrusive
} //namespace boost
Added: trunk/boost/intrusive/detail/transform_iterator.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/intrusive/detail/transform_iterator.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -0,0 +1,173 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// (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_DETAIL_TRANSFORM_ITERATOR_HPP
+#define BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP
+
+#include <boost/intrusive/detail/config_begin.hpp>
+#include <iterator>
+#include <boost/intrusive/detail/mpl.hpp>
+
+namespace boost {
+namespace intrusive {
+namespace detail {
+
+template <class PseudoReference>
+struct operator_arrow_proxy
+{
+ operator_arrow_proxy(const PseudoReference &px)
+ : m_value(px)
+ {}
+
+ PseudoReference* operator->() const { return &m_value; }
+ // This function is needed for MWCW and BCC, which won't call operator->
+ // again automatically per 13.3.1.2 para 8
+// operator T*() const { return &m_value; }
+ mutable PseudoReference m_value;
+};
+
+template <class T>
+struct operator_arrow_proxy<T&>
+{
+ operator_arrow_proxy(T &px)
+ : m_value(px)
+ {}
+
+ T* operator->() const { return &m_value; }
+ // This function is needed for MWCW and BCC, which won't call operator->
+ // again automatically per 13.3.1.2 para 8
+// operator T*() const { return &m_value; }
+ mutable T &m_value;
+};
+
+template <class Iterator, class UnaryFunction>
+class transform_iterator
+ : public std::iterator
+ < typename Iterator::iterator_category
+ , typename detail::remove_reference<typename UnaryFunction::result_type>::type
+ , typename Iterator::difference_type
+ , operator_arrow_proxy<typename UnaryFunction::result_type>
+ , typename UnaryFunction::result_type>
+{
+ public:
+ explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction())
+ : members_(it, f)
+ {}
+
+ explicit transform_iterator()
+ : members_()
+ {}
+
+ Iterator get_it() const
+ { return members_.m_it; }
+
+ //Constructors
+ transform_iterator& operator++()
+ { increment(); return *this; }
+
+ transform_iterator operator++(int)
+ {
+ transform_iterator result (*this);
+ increment();
+ return result;
+ }
+
+ friend bool operator== (const transform_iterator& i, const transform_iterator& i2)
+ { return i.equal(i2); }
+
+ friend bool operator!= (const transform_iterator& i, const transform_iterator& i2)
+ { return !(i == i2); }
+
+/*
+ friend bool operator> (const transform_iterator& i, const transform_iterator& i2)
+ { return i2 < i; }
+
+ friend bool operator<= (const transform_iterator& i, const transform_iterator& i2)
+ { return !(i > i2); }
+
+ friend bool operator>= (const transform_iterator& i, const transform_iterator& i2)
+ { return !(i < i2); }
+*/
+ friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
+ { return i2.distance_to(i); }
+
+ //Arithmetic
+ transform_iterator& operator+=(typename Iterator::difference_type off)
+ { this->advance(off); return *this; }
+
+ transform_iterator operator+(typename Iterator::difference_type off) const
+ {
+ transform_iterator other(*this);
+ other.advance(off);
+ return other;
+ }
+
+ friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right)
+ { return right + off; }
+
+ transform_iterator& operator-=(typename Iterator::difference_type off)
+ { this->advance(-off); return *this; }
+
+ transform_iterator operator-(typename Iterator::difference_type off) const
+ { return *this + (-off); }
+
+ typename UnaryFunction::result_type operator*() const
+ { return dereference(); }
+
+ operator_arrow_proxy<typename UnaryFunction::result_type>
+ operator->() const
+ { return operator_arrow_proxy<typename UnaryFunction::result_type>(dereference()); }
+
+ private:
+ struct members
+ : UnaryFunction
+ {
+ members(const Iterator &it, const UnaryFunction &f)
+ : UnaryFunction(f), m_it(it)
+ {}
+
+ members()
+ {}
+
+ Iterator m_it;
+ } members_;
+
+
+ void increment()
+ { ++members_.m_it; }
+
+ void decrement()
+ { --members_.m_it; }
+
+ bool equal(const transform_iterator &other) const
+ { return members_.m_it == other.members_.m_it; }
+
+ bool less(const transform_iterator &other) const
+ { return other.members_.m_it < members_.m_it; }
+
+ typename UnaryFunction::result_type dereference() const
+ { return members_(*members_.m_it); }
+
+ void advance(typename Iterator::difference_type n)
+ { std::advance(members_.m_it, n); }
+
+ typename Iterator::difference_type distance_to(const transform_iterator &other)const
+ { return std::distance(other.members_.m_it, members_.m_it); }
+};
+
+} //namespace detail
+} //namespace intrusive
+} //namespace boost
+
+#include <boost/intrusive/detail/config_end.hpp>
+
+#endif //BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP
Modified: trunk/boost/intrusive/detail/utilities.hpp
==============================================================================
--- trunk/boost/intrusive/detail/utilities.hpp (original)
+++ trunk/boost/intrusive/detail/utilities.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -17,7 +17,7 @@
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/detail/parent_from_member.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp>
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <cstddef>
#include <iterator>
@@ -26,6 +26,64 @@
namespace intrusive {
namespace detail {
+template <class T>
+struct internal_member_value_traits
+{
+ template <class U> static detail::one test(...);
+ template <class U> static detail::two test(typename U::member_value_traits* = 0);
+ static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
+};
+
+template <class T>
+struct internal_base_hook_bool
+{
+ template<bool Add>
+ struct two_or_three {one _[2 + Add];};
+ template <class U> static one test(...);
+ template <class U> static two_or_three<U::boost_intrusive_tags::is_base_hook>
+ test (detail::bool_<U::boost_intrusive_tags::is_base_hook>* = 0);
+ static const int value = sizeof(test<T>(0));
+};
+
+template <class T>
+struct internal_base_hook_bool_is_true
+{
+ static const bool value = internal_base_hook_bool<T>::value == 3;
+};
+
+template <class T>
+struct external_value_traits_bool
+{
+ template<bool Add>
+ struct two_or_three {one _[2 + Add];};
+ template <class U> static one test(...);
+ template <class U> static two_or_three<U::external_value_traits>
+ test (detail::bool_<U::external_value_traits>* = 0);
+ static const int value = sizeof(test<T>(0));
+};
+
+template <class T>
+struct external_bucket_traits_bool
+{
+ template<bool Add>
+ struct two_or_three {one _[2 + Add];};
+ template <class U> static one test(...);
+ template <class U> static two_or_three<U::external_bucket_traits>
+ test (detail::bool_<U::external_bucket_traits>* = 0);
+ static const int value = sizeof(test<T>(0));
+};
+
+template <class T>
+struct external_value_traits_is_true
+{
+ static const bool value = external_value_traits_bool<T>::value == 3;
+};
+
+template<class Node, class Tag, link_mode_type LinkMode, int>
+struct node_holder
+ : public Node
+{};
+
template<class SmartPtr>
struct smart_ptr_type
{
@@ -49,7 +107,6 @@
inline typename smart_ptr_type<Ptr>::pointer
get_pointer(const Ptr &ptr)
{ return smart_ptr_type<Ptr>::get(ptr); }
-//{ using boost::get_pointer; return get_pointer(ptr); }
//This functor compares a stored value
//and the one passed as an argument
@@ -75,10 +132,20 @@
{}
};
+template<class NodeAlgorithms>
+class init_disposer
+{
+ typedef typename NodeAlgorithms::node_ptr node_ptr;
+
+ public:
+ void operator()(node_ptr p)
+ { NodeAlgorithms::init(p); }
+};
+
template<bool ConstantSize, class SizeType>
struct size_holder
{
- enum { constant_time_size = ConstantSize };
+ static const bool constant_time_size = ConstantSize;
typedef SizeType size_type;
SizeType get_size() const
@@ -99,7 +166,7 @@
template<class SizeType>
struct size_holder<false, SizeType>
{
- enum { constant_time_size = false };
+ static const bool constant_time_size = false;
typedef SizeType size_type;
size_type get_size() const
@@ -115,185 +182,297 @@
{}
};
-template<class T, class DerivationHookType, typename Tag>
-struct derivation_hook_value_traits
+template<class KeyValueCompare, class Container>
+struct key_nodeptr_comp
+ : private detail::ebo_functor_holder<KeyValueCompare>
{
- public:
- typedef typename DerivationHookType::node_traits node_traits;
- typedef T value_type;
- typedef typename node_traits::node_ptr node_ptr;
- typedef typename node_traits::const_node_ptr const_node_ptr;
- typedef typename boost::pointer_to_other<node_ptr, T>::type pointer;
- typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- enum { linking_policy = DerivationHookType::linking_policy };
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename real_value_traits::node_ptr node_ptr;
+ typedef detail::ebo_functor_holder<KeyValueCompare> base_t;
+ key_nodeptr_comp(KeyValueCompare kcomp, const Container *cont)
+ : base_t(kcomp), cont_(cont)
+ {}
- static node_ptr to_node_ptr(reference value)
- { return static_cast<DerivationHookType &>(value).to_node_ptr(); }
+ template<class KeyType>
+ bool operator()(node_ptr node, const KeyType &key) const
+ { return base_t::get()(*cont_->get_real_value_traits().to_value_ptr(node), key); }
- static const_node_ptr to_node_ptr(const_reference value)
- { return static_cast<const DerivationHookType &>(value).to_node_ptr(); }
+ template<class KeyType>
+ bool operator()(const KeyType &key, node_ptr node) const
+ { return base_t::get()(key, *cont_->get_real_value_traits().to_value_ptr(node)); }
- static pointer to_value_ptr(node_ptr n)
- {
- return static_cast<T*>(detail::get_pointer(DerivationHookType::to_hook_ptr(n)));
+ bool operator()(node_ptr node1, node_ptr node2) const
+ {
+ return base_t::get()
+ ( *cont_->get_real_value_traits().to_value_ptr(node1)
+ , *cont_->get_real_value_traits().to_value_ptr(node2)
+ );
}
- static const_pointer to_value_ptr(const_node_ptr n)
- {
- return static_cast<const T*>(detail::get_pointer(DerivationHookType::to_hook_ptr(n)));
- }
+ const Container *cont_;
};
-
-template<class T, class MemberHookType, MemberHookType T::* P>
-struct member_hook_value_traits
+template<class F, class Container>
+struct node_cloner
+ : private detail::ebo_functor_holder<F>
{
- public:
- typedef typename MemberHookType::node_traits node_traits;
- typedef T value_type;
- typedef typename node_traits::node_ptr node_ptr;
- typedef typename node_traits::const_node_ptr const_node_ptr;
- typedef typename boost::pointer_to_other<node_ptr, T>::type pointer;
- typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
- typedef value_type & reference;
- typedef const value_type & const_reference;
- enum { linking_policy = MemberHookType::linking_policy };
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename Container::node_algorithms node_algorithms;
+ typedef typename real_value_traits::value_type value_type;
+ typedef typename real_value_traits::pointer pointer;
+ typedef typename real_value_traits::node_traits::node node;
+ typedef typename real_value_traits::node_ptr node_ptr;
+ typedef typename real_value_traits::const_node_ptr const_node_ptr;
+ typedef detail::ebo_functor_holder<F> base_t;
+ enum { safemode_or_autounlink =
+ (int)real_value_traits::link_mode == (int)auto_unlink ||
+ (int)real_value_traits::link_mode == (int)safe_link };
- public:
- static node_ptr to_node_ptr(reference value)
+ node_cloner(F f, const Container *cont)
+ : base_t(f), cont_(cont)
+ {}
+
+ node_ptr operator()(node_ptr p)
{
- MemberHookType* result = &(value.*P);
- return result->to_node_ptr();
+ 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;
}
- static const_node_ptr to_node_ptr(const_reference value)
+ node_ptr operator()(const node &to_clone)
{
- const MemberHookType* result = &(value.*P);
- return result->to_node_ptr();
+ const value_type &v =
+ *cont_->get_real_value_traits().to_value_ptr(const_node_ptr(&to_clone));
+ node_ptr n = cont_->get_real_value_traits().to_node_ptr(*base_t::get()(v));
+ //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;
}
- static pointer to_value_ptr(node_ptr n)
- {
- return pointer
- (
- parent_from_member<value_type, MemberHookType>
- (detail::get_pointer(MemberHookType::to_hook_ptr(n)), P)
- );
- }
+ const Container *cont_;
+};
- static const_pointer to_value_ptr(const_node_ptr n)
+template<class F, class Container>
+struct node_disposer
+ : private detail::ebo_functor_holder<F>
+{
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename real_value_traits::node_ptr node_ptr;
+ typedef detail::ebo_functor_holder<F> base_t;
+ typedef typename Container::node_algorithms node_algorithms;
+ enum { safemode_or_autounlink =
+ (int)real_value_traits::link_mode == (int)auto_unlink ||
+ (int)real_value_traits::link_mode == (int)safe_link };
+
+ node_disposer(F f, const Container *cont)
+ : base_t(f), cont_(cont)
+ {}
+
+ void operator()(node_ptr p)
{
- return const_pointer
- (
- parent_from_member<value_type, MemberHookType>
- (detail::get_pointer(MemberHookType::to_hook_ptr(n)), P)
- );
+ if(safemode_or_autounlink)
+ node_algorithms::init(p);
+ base_t::get()(cont_->get_real_value_traits().to_value_ptr(p));
}
+ const Container *cont_;
};
-template<class KeyValueCompare, class ValueTraits>
-struct key_node_ptr_compare
- : private detail::ebo_functor_holder<KeyValueCompare>
+struct dummy_constptr
{
- typedef typename ValueTraits::node_ptr node_ptr;
- typedef detail::ebo_functor_holder<KeyValueCompare> base_t;
- key_node_ptr_compare(KeyValueCompare kcomp)
- : base_t(kcomp)
+ dummy_constptr(const void *)
{}
- template<class KeyType>
- bool operator()(node_ptr node, const KeyType &key) const
- { return base_t::get()(*ValueTraits::to_value_ptr(node), key); }
-
- template<class KeyType>
- bool operator()(const KeyType &key, node_ptr node) const
- { return base_t::get()(key, *ValueTraits::to_value_ptr(node)); }
-
- bool operator()(node_ptr node1, node_ptr node2) const
- {
- return base_t::get()
- (*ValueTraits::to_value_ptr(node1), *ValueTraits::to_value_ptr(node2));
- }
+ const void *get_ptr() const
+ { return 0; }
};
-template<class F, class ValueTraits>
-struct value_to_node_cloner
- : private detail::ebo_functor_holder<F>
+template<class VoidPointer>
+struct constptr
{
- typedef typename ValueTraits::node_ptr node_ptr;
- typedef detail::ebo_functor_holder<F> base_t;
+ typedef typename boost::pointer_to_other
+ <VoidPointer, const void>::type ConstVoidPtr;
- value_to_node_cloner(F f)
- : base_t(f)
+ constptr(const void *ptr)
+ : const_void_ptr_(ptr)
{}
-
- node_ptr operator()(node_ptr p)
- { return ValueTraits::to_node_ptr(*base_t::get()(*ValueTraits::to_value_ptr(p))); }
+
+ const void *get_ptr() const
+ { return detail::get_pointer(const_void_ptr_); }
+
+ ConstVoidPtr const_void_ptr_;
};
-template<class F, class ValueTraits>
-struct value_to_node_disposer
- : private detail::ebo_functor_holder<F>
+template <class VoidPointer, bool store_ptr>
+struct select_constptr
{
- typedef typename ValueTraits::node_ptr node_ptr;
- typedef detail::ebo_functor_holder<F> base_t;
- value_to_node_disposer(F f)
- : base_t(f)
+ typedef typename detail::if_c
+ < store_ptr
+ , constptr<VoidPointer>
+ , dummy_constptr
+ >::type type;
+};
+
+template <class Container>
+struct store_cont_ptr_on_it
+{
+ typedef typename Container::value_traits value_traits;
+ static const bool value =
+ !detail::is_empty_class<value_traits>::value
+ || detail::external_value_traits_is_true<value_traits>::value
+ ;
+};
+
+template<class T, bool Add>
+struct add_const_if_c
+{
+ typedef typename detail::if_c
+ < Add
+ , typename detail::add_const<T>::type
+ , T
+ >::type type;
+};
+
+template<class Container, bool IsConst>
+struct node_to_value
+ : public detail::select_constptr
+ < typename boost::pointer_to_other
+ <typename Container::pointer, void>::type
+ , detail::store_cont_ptr_on_it<Container>::value
+ >::type
+{
+ static const bool store_container_ptr =
+ detail::store_cont_ptr_on_it<Container>::value;
+
+ typedef typename Container::real_value_traits real_value_traits;
+ typedef typename real_value_traits::value_type value_type;
+ typedef typename detail::select_constptr
+ < typename boost::pointer_to_other
+ <typename Container::pointer, void>::type
+ , store_container_ptr >::type Base;
+ typedef typename real_value_traits::node_traits::node node;
+ typedef typename detail::add_const_if_c
+ <value_type, IsConst>::type vtype;
+ typedef typename detail::add_const_if_c
+ <node, IsConst>::type ntype;
+ typedef typename boost::pointer_to_other
+ <typename Container::pointer, ntype>::type npointer;
+
+ node_to_value(const Container *cont)
+ : Base(cont)
{}
- void operator()(node_ptr p)
- { base_t::get()(ValueTraits::to_value_ptr(p)); }
+ typedef vtype & result_type;
+ typedef ntype & first_argument_type;
+
+ const Container *get_container() const
+ {
+ if(store_container_ptr)
+ return static_cast<const Container*>(Base::get_ptr());
+ else
+ return 0;
+ }
+
+ const real_value_traits *get_real_value_traits() const
+ {
+ if(store_container_ptr)
+ return &this->get_container()->get_real_value_traits();
+ else
+ return 0;
+ }
+
+ result_type operator()(first_argument_type arg) const
+ { return *(this->get_real_value_traits()->to_value_ptr(npointer(&arg))); }
};
-template <linking_policy Policy>
-struct dispatcher
+template <link_mode_type LinkMode>
+struct link_dispatch
{};
template<class Container>
-void destructor_impl(Container &cont, dispatcher<safe_link>)
+void destructor_impl(Container &cont, detail::link_dispatch<safe_link>)
{ (void)cont; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!cont.is_linked()); }
template<class Container>
-void destructor_impl(Container &cont, dispatcher<auto_unlink>)
+void destructor_impl(Container &cont, detail::link_dispatch<auto_unlink>)
{ cont.unlink(); }
template<class Container>
-void destructor_impl(Container &, dispatcher<normal_link>)
+void destructor_impl(Container &, detail::link_dispatch<normal_link>)
{}
-template<class Node, class MaybeClass>
-struct node_plus_pred
- : public ebo_functor_holder<MaybeClass>
- , public Node
+template<class T, class NodeTraits, link_mode_type LinkMode, class Tag, int HookType>
+struct base_hook_traits
{
- node_plus_pred()
- {}
+ public:
+ typedef detail::node_holder
+ <typename NodeTraits::node, Tag, LinkMode, HookType> node_holder;
+ typedef NodeTraits node_traits;
+ typedef T value_type;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename node_traits::const_node_ptr const_node_ptr;
+ typedef typename boost::pointer_to_other<node_ptr, T>::type pointer;
+ typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
+ typedef typename std::iterator_traits<pointer>::reference reference;
+ typedef typename std::iterator_traits<const_pointer>::reference const_reference;
+ static const link_mode_type link_mode = LinkMode;
- node_plus_pred(const Node &x, const MaybeClass &y)
- : Node(x), ebo_functor_holder<MaybeClass>(y) {}
+ static node_ptr to_node_ptr(reference value)
+ { return static_cast<node_holder*>(&value); }
+
+ static const_node_ptr to_node_ptr(const_reference value)
+ { return static_cast<const node_holder*>(&value); }
+
+ static pointer to_value_ptr(node_ptr n)
+ { return static_cast<T*>(static_cast<node_holder*>(&*n)); }
+
+ static const_pointer to_value_ptr(const_node_ptr n)
+ { return static_cast<const T*>(static_cast<const node_holder*>(&*n)); }
+};
+
+template<class T, class Hook, Hook T::* P>
+struct member_hook_traits
+{
+ public:
+ typedef Hook hook_type;
+ typedef typename hook_type::boost_intrusive_tags::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef T value_type;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename node_traits::const_node_ptr const_node_ptr;
+ typedef typename boost::pointer_to_other<node_ptr, T>::type pointer;
+ typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
+ typedef typename std::iterator_traits<pointer>::reference reference;
+ typedef typename std::iterator_traits<const_pointer>::reference const_reference;
+ static const link_mode_type link_mode = Hook::boost_intrusive_tags::link_mode;
- node_plus_pred(const MaybeClass &y)
- : ebo_functor_holder<MaybeClass>(y) {}
+ static node_ptr to_node_ptr(reference value)
+ {
+ return reinterpret_cast<node*>(&(value.*P));
+ }
- Node &first()
- { return *this; }
- const Node &first() const
- { return *this; }
- MaybeClass &second()
- { return ebo_functor_holder<MaybeClass>::get(); }
- const MaybeClass &second() const
- { return ebo_functor_holder<MaybeClass>::get(); }
+ static const_node_ptr to_node_ptr(const_reference value)
+ {
+ return static_cast<const node*>(&(value.*P));
+ }
- static node_plus_pred *this_from_node(Node *n)
- { return static_cast<node_plus_pred*>(n); }
+ static pointer to_value_ptr(node_ptr n)
+ {
+ return detail::parent_from_member<T, Hook>
+ (static_cast<Hook*>(detail::get_pointer(n)), P);
+ }
- static node_plus_pred *this_from_node(const Node *n)
- { return static_cast<const node_plus_pred*>(n); }
+ static const_pointer to_value_ptr(const_node_ptr n)
+ {
+ return detail::parent_from_member<T, Hook>
+ (static_cast<const Hook*>(detail::get_pointer(n)), P);
+ }
};
-} //namespace detail
+} //namespace detail
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/hashtable.hpp
==============================================================================
--- trunk/boost/intrusive/hashtable.hpp (original)
+++ trunk/boost/intrusive/hashtable.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -22,156 +22,390 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/functional/hash.hpp>
-#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
-#include <boost/detail/no_exceptions_support.hpp>
-#endif
+#include <boost/intrusive/detail/no_exceptions_support.hpp>
//General intrusive utilities
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/detail/hashtable_node.hpp>
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/detail/transform_iterator.hpp>
+#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp>
//Implementation utilities
+#include <boost/intrusive/trivial_value_traits.hpp>
#include <boost/intrusive/unordered_set_hook.hpp>
#include <boost/intrusive/slist.hpp>
namespace boost {
namespace intrusive {
+/// @cond
+
+namespace detail{
+
+template<class Config>
+struct bucket_plus_size
+ : public detail::size_holder
+ < Config::constant_time_size
+ , typename Config::size_type>
+{
+ typedef detail::size_holder
+ < Config::constant_time_size
+ , typename Config::size_type> size_traits;
+ typedef typename Config::bucket_traits bucket_traits;
+
+ bucket_plus_size(const bucket_traits &b_traits)
+ : bucket_traits_(b_traits)
+ {}
+ bucket_traits bucket_traits_;
+};
+
+template<class Config>
+struct bucket_hash_t : public detail::ebo_functor_holder<typename Config::hash>
+{
+ typedef typename Config::hash hasher;
+ typedef detail::size_holder
+ < Config::constant_time_size
+ , typename Config::size_type> size_traits;
+ typedef typename Config::bucket_traits bucket_traits;
+
+ bucket_hash_t(const bucket_traits &b_traits, const hasher & h)
+ : detail::ebo_functor_holder<hasher>(h), bucket_plus_size_(b_traits)
+ {}
+
+ bucket_plus_size<Config> bucket_plus_size_;
+};
+
+template<class Config>
+struct bucket_hash_equal_t : public detail::ebo_functor_holder<typename Config::equal>
+{
+ typedef typename Config::equal equal;
+ typedef typename Config::hash hasher;
+ typedef typename Config::bucket_traits bucket_traits;
+
+ bucket_hash_equal_t(const bucket_traits &b_traits, const hasher & h, const equal &e)
+ : detail::ebo_functor_holder<typename Config::equal>(e), bucket_hash(b_traits, h)
+ {}
+ bucket_hash_t<Config> bucket_hash;
+};
+
+template<class Config>
+struct data_t : public Config::value_traits
+{
+ typedef typename Config::value_traits value_traits;
+ typedef typename Config::equal equal;
+ typedef typename Config::hash hasher;
+ typedef typename Config::bucket_traits bucket_traits;
+
+ data_t( const bucket_traits &b_traits, const hasher & h
+ , const equal &e, const value_traits &val_traits)
+ : Config::value_traits(val_traits), bucket_hash_equal_(b_traits, h, e)
+ {}
+ bucket_hash_equal_t<Config> bucket_hash_equal_;
+};
+
+} //namespace detail {
+
+template <class T>
+struct internal_default_uset_hook
+{
+ template <class U> static detail::one test(...);
+ template <class U> static detail::two test(typename U::default_uset_hook* = 0);
+ static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
+};
+
+template <class T>
+struct get_default_uset_hook
+{
+ typedef typename T::default_uset_hook type;
+};
+
+template < class ValueTraits
+ , class Hash
+ , class Equal
+ , class SizeType
+ , bool ConstantTimeSize
+ , class BucketTraits
+ , bool Power2Buckets
+ >
+struct usetopt
+{
+ typedef ValueTraits value_traits;
+ typedef Hash hash;
+ typedef Equal equal;
+ typedef SizeType size_type;
+ typedef BucketTraits bucket_traits;
+ static const bool constant_time_size = ConstantTimeSize;
+ static const bool power_2_buckets = Power2Buckets;
+};
+
+struct default_bucket_traits;
+
+template <class T>
+struct uset_defaults
+ : pack_options
+ < none
+ , base_hook
+ < typename detail::eval_if_c
+ < internal_default_uset_hook<T>::value
+ , get_default_uset_hook<T>
+ , detail::identity<none>
+ >::type
+ >
+ , constant_time_size<true>
+ , size_type<std::size_t>
+ , equal<std::equal_to<T> >
+ , hash<boost::hash<T> >
+ , bucket_traits<default_bucket_traits>
+ , power_2_buckets<false>
+ >::type
+{};
+
+template<class NodeTraits>
+struct get_slist_impl
+{
+ typedef trivial_value_traits<NodeTraits, normal_link> trivial_traits;
+
+ //Reducing symbol length
+ struct type : make_slist
+ < typename NodeTraits::node
+ , boost::intrusive::value_traits<trivial_traits>
+ , boost::intrusive::constant_time_size<false>
+ , boost::intrusive::size_type<std::size_t>
+ >::type
+ {};
+};
+
+/// @endcond
+
+template<class ValueTraitsOrHookOption>
+struct unordered_bucket
+{
+ /// @cond
+ typedef typename ValueTraitsOrHookOption::
+ template pack<none>::value_traits supposed_value_traits;
+
+ typedef typename detail::eval_if_c
+ < detail::external_value_traits_is_true
+ <supposed_value_traits>::value
+ , detail::eval_value_traits
+ <supposed_value_traits>
+ , detail::identity
+ <supposed_value_traits>
+ >::type real_value_traits;
+
+ typedef typename detail::get_node_traits
+ <real_value_traits>::type node_traits;
+ typedef typename get_slist_impl
+ <node_traits>::type slist_impl;
+ typedef detail::bucket_impl<slist_impl> implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
+template<class ValueTraitsOrHookOption>
+struct unordered_bucket_ptr
+{
+ /// @cond
+ typedef typename ValueTraitsOrHookOption::
+ template pack<none>::value_traits supposed_value_traits;
+ typedef typename detail::eval_if_c
+ < detail::external_value_traits_is_true
+ <supposed_value_traits>::value
+ , detail::eval_value_traits
+ <supposed_value_traits>
+ , detail::identity
+ <supposed_value_traits>
+ >::type real_value_traits;
+ typedef typename detail::get_node_traits
+ <supposed_value_traits>::type::node_ptr node_ptr;
+ typedef typename unordered_bucket
+ <ValueTraitsOrHookOption>::type bucket_type;
+ typedef typename boost::pointer_to_other
+ <node_ptr, bucket_type>::type implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
//! The class template hashtable is an intrusive hash table container, that
//! is used to construct intrusive unordered_set and unordered_multiset containers. The
//! no-throw guarantee holds only, if the Equal object and Hasher don't throw.
-template< class ValueTraits
- , class Hash //= boost::hash<typename ValueTraits::value_type>
- , class Equal //= std::equal_to<typename ValueTraits::value_type>
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class hashtable
- : private detail::size_holder<ConstantTimeSize, SizeType>
+//!
+//! hashtable is a pseudo-intrusive container: each object to be stored in the
+//! container must contain a proper hook, but the container also needs
+//! additional auxiliary memory to work: hashtable needs a pointer to an array
+//! of type `bucket_type` to be passed in the constructor. This bucket array must
+//! have at least the same lifetime as the container. This makes the use of
+//! hashtable more complicated than purely intrusive containers.
+//! `bucket_type` is default-constructible, copyable and assignable
+//!
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
+//!
+//! 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<> .
+//!
+//! hashtable only provides forward iterators but it provides 4 iterator types:
+//! iterator and const_iterator to navigate through the whole container and
+//! local_iterator and const_local_iterator to navigate through the values
+//! stored in a single bucket. Local iterators are faster and smaller.
+//!
+//! It's not recommended to use non constant-time size hashtables because several
+//! key functions, like "empty()", become non-constant time functions. Non
+//! constant_time size hashtables are mainly provided to support auto-unlink hooks.
+//!
+//! hashtables, does not make automatic rehashings nor
+//! offers functions related to a load factor. Rehashing can be explicitly requested
+//! and the user must provide a new bucket array that will be used from that moment.
+//!
+//! Since no automatic rehashing is done, iterators are never invalidated when
+//! inserting or erasing elements. Iterators are only invalidated when rehashing.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class hashtable_impl
+ : private detail::data_t<Config>
{
+ public:
+ typedef typename Config::value_traits value_traits;
+
/// @cond
- private:
- typedef slist<ValueTraits, false, SizeType> slist_impl;
- typedef hashtable<ValueTraits, Hash, Equal
- ,ConstantTimeSize, SizeType> this_type;
- typedef typename ValueTraits::node_traits node_traits;
- typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;
- //noncopyable
- hashtable (const hashtable&);
- hashtable operator =(const hashtable&);
+ static const bool external_value_traits =
+ detail::external_value_traits_is_true<value_traits>::value;
+ typedef typename detail::eval_if_c
+ < external_value_traits
+ , detail::eval_value_traits<value_traits>
+ , detail::identity<value_traits>
+ >::type real_value_traits;
+ typedef typename Config::bucket_traits bucket_traits;
+ static const bool external_bucket_traits =
+ detail::external_bucket_traits_is_true<bucket_traits>::value;
+ typedef typename detail::eval_if_c
+ < external_bucket_traits
+ , detail::eval_bucket_traits<bucket_traits>
+ , detail::identity<bucket_traits>
+ >::type real_bucket_traits;
+ typedef typename get_slist_impl
+ <typename real_value_traits::node_traits>::type slist_impl;
/// @endcond
- public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef value_type key_type;
- typedef Hash hasher;
- typedef Equal key_equal;
- typedef detail::bucket_type_impl<slist_impl> bucket_type;
+ typedef typename real_value_traits::pointer pointer;
+ typedef typename real_value_traits::const_pointer const_pointer;
+ typedef typename std::iterator_traits<pointer>::value_type value_type;
+ typedef typename std::iterator_traits<pointer>::reference reference;
+ typedef typename std::iterator_traits<const_pointer>::reference const_reference;
+ typedef typename std::iterator_traits<pointer>::difference_type difference_type;
+ typedef typename Config::size_type size_type;
+ typedef value_type key_type;
+ typedef typename Config::equal key_equal;
+ typedef typename Config::hash hasher;
+ typedef detail::bucket_impl<slist_impl> bucket_type;
+ typedef typename boost::pointer_to_other
+ <pointer, bucket_type>::type bucket_ptr;
+ typedef typename slist_impl::iterator siterator;
+ typedef typename slist_impl::const_iterator const_siterator;
+ typedef detail::hashtable_iterator<hashtable_impl, false> iterator;
+ typedef detail::hashtable_iterator<hashtable_impl, true> const_iterator;
+ typedef typename real_value_traits::node_traits node_traits;
+ typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
- <pointer, bucket_type>::type bucket_ptr;
- typedef typename slist_impl::iterator local_iterator;
- typedef typename slist_impl::const_iterator const_local_iterator;
+ <pointer, node>::type node_ptr;
+ typedef typename boost::pointer_to_other
+ <node_ptr, const node>::type const_node_ptr;
+ typedef typename slist_impl::node_algorithms node_algorithms;
- typedef detail::hashtable_iterator<value_type, slist_impl> iterator;
- typedef detail::hashtable_iterator<value_type, slist_impl> const_iterator;
+ static const bool constant_time_size = Config::constant_time_size;
+ static const bool stateful_value_traits = detail::store_cont_ptr_on_it<hashtable_impl>::value;
/// @cond
private:
- typedef typename node_traits::node node;
- typedef typename boost::pointer_to_other
- <pointer, node>::type node_ptr;
- typedef typename boost::pointer_to_other
- <node_ptr, const node>::type const_node_ptr;
+ typedef detail::size_holder<constant_time_size, size_type> size_traits;
+ typedef detail::data_t<Config> base_type;
+ typedef detail::transform_iterator
+ < typename slist_impl::iterator
+ , detail::node_to_value<hashtable_impl, false> > local_iterator_impl;
+ typedef detail::transform_iterator
+ < typename slist_impl::iterator
+ , detail::node_to_value<hashtable_impl, true> > const_local_iterator_impl;
+
+ //noncopyable
+ hashtable_impl (const hashtable_impl&);
+ hashtable_impl operator =(const hashtable_impl&);
enum { safemode_or_autounlink =
- (int)ValueTraits::linking_policy == (int)auto_unlink ||
- (int)ValueTraits::linking_policy == (int)safe_link };
+ (int)real_value_traits::link_mode == (int)auto_unlink ||
+ (int)real_value_traits::link_mode == (int)safe_link };
//Constant-time size is incompatible with auto-unlink hooks!
- BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));
+ BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink)));
- typedef detail::bucket_info_impl<slist_impl> bucket_info_t;
- typedef typename boost::pointer_to_other
- <pointer, bucket_info_t>::type bucket_info_ptr;
- typedef typename boost::pointer_to_other
- <pointer, const bucket_info_t>::type const_bucket_info_ptr;
+ static const bool power_2_buckets = Config::power_2_buckets;
- //User scattered boost::compressed pair to get EBO all compilers
-// boost::compressed_pair
-// <boost::compressed_pair<bucket_info_t, Hash>
-// ,Equal> members_;
- struct bucket_hash_t
- : public detail::ebo_functor_holder<Hash>
- {
- bucket_hash_t(const Hash & h)
- : detail::ebo_functor_holder<Hash>(h)
- {}
- bucket_info_t bucket_info;
- };
+ std::size_t from_hash_to_bucket(std::size_t hash_value) const
+ { return from_hash_to_bucket(hash_value, detail::bool_<power_2_buckets>()); }
- struct bucket_hash_equal_t
- : public detail::ebo_functor_holder<Equal>
- {
- bucket_hash_equal_t(const Hash & h, const Equal &e)
- : detail::ebo_functor_holder<Equal>(e), bucket_hash(h)
- {}
- bucket_hash_t bucket_hash;
- } bucket_hash_equal_;
+ std::size_t from_hash_to_bucket(std::size_t hash_value, detail::bool_<false>) const
+ { return hash_value % this->get_real_bucket_traits().bucket_count(); }
+
+ std::size_t from_hash_to_bucket(std::size_t hash_value, detail::bool_<true>) const
+ { return hash_value & (this->get_real_bucket_traits().bucket_count() - 1); }
+
+ const key_equal &priv_equal() const
+ { return static_cast<const key_equal&>(this->bucket_hash_equal_.get()); }
+
+ key_equal &priv_equal()
+ { return static_cast<key_equal&>(this->bucket_hash_equal_.get()); }
- const Equal &priv_equal() const
- { return static_cast<const Equal&>(bucket_hash_equal_.get()); }
+ const real_bucket_traits &get_real_bucket_traits(detail::bool_<false>) const
+ { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; }
- Equal &priv_equal()
- { return static_cast<Equal&>(bucket_hash_equal_.get()); }
+ const real_bucket_traits &get_real_bucket_traits(detail::bool_<true>) const
+ { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); }
- const bucket_info_t &priv_bucket_info() const
- { return bucket_hash_equal_.bucket_hash.bucket_info; }
+ real_bucket_traits &get_real_bucket_traits(detail::bool_<false>)
+ { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; }
- bucket_info_t &priv_bucket_info()
- { return bucket_hash_equal_.bucket_hash.bucket_info; }
+ real_bucket_traits &get_real_bucket_traits(detail::bool_<true>)
+ { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); }
- const Hash &priv_hasher() const
- { return static_cast<const Hash&>(bucket_hash_equal_.bucket_hash.get()); }
+ const real_bucket_traits &get_real_bucket_traits() const
+ { return this->get_real_bucket_traits(detail::bool_<external_bucket_traits>()); }
- Hash &priv_hasher()
- { return static_cast<Hash&>(bucket_hash_equal_.bucket_hash.get()); }
+ real_bucket_traits &get_real_bucket_traits()
+ { return this->get_real_bucket_traits(detail::bool_<external_bucket_traits>()); }
- const bucket_ptr &priv_buckets() const
- { return priv_bucket_info().buckets_; }
+ const hasher &priv_hasher() const
+ { return static_cast<const hasher&>(this->bucket_hash_equal_.bucket_hash.get()); }
- bucket_ptr &priv_buckets()
- { return priv_bucket_info().buckets_; }
+ hasher &priv_hasher()
+ { return static_cast<hasher&>(this->bucket_hash_equal_.bucket_hash.get()); }
- const size_type &priv_buckets_len() const
- { return priv_bucket_info().buckets_len_; }
+ bucket_ptr priv_buckets() const
+ { return this->get_real_bucket_traits().bucket_begin(); }
- size_type &priv_buckets_len()
- { return priv_bucket_info().buckets_len_; }
+ size_type priv_buckets_len() const
+ { return this->get_real_bucket_traits().bucket_count(); }
static node_ptr uncast(const_node_ptr ptr)
{
return node_ptr(const_cast<node*>(detail::get_pointer(ptr)));
}
-// static bucket_info_ptr uncast(const_bucket_info_ptr ptr)
-// {
-// return bucket_info_ptr(const_cast<bucket_info_t*>(detail::get_pointer(ptr)));
-// }
+ node &from_value_to_node(value_type &v)
+ { return *this->get_real_value_traits().to_node_ptr(v); }
- static slist_impl &bucket_to_slist(bucket_type &b)
- { return static_cast<slist_impl &>(b); }
+ const node &from_value_to_node(const value_type &v) const
+ { return *this->get_real_value_traits().to_node_ptr(v); }
- static const slist_impl &bucket_to_slist(const bucket_type &b)
- { return static_cast<const slist_impl &>(b); }
+ size_traits &priv_size_traits()
+ { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_; }
+
+ const size_traits &priv_size_traits() const
+ { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_; }
struct insert_commit_data_impl
{
@@ -180,33 +414,82 @@
/// @endcond
public:
+
+ class local_iterator
+ : public local_iterator_impl
+ {
+ public:
+ local_iterator()
+ {}
+
+ local_iterator(siterator sit, const hashtable_impl *cont)
+ : local_iterator_impl(sit, cont)
+ {}
+ };
+
+ class const_local_iterator
+ : public const_local_iterator_impl
+ {
+ public:
+ const_local_iterator()
+ {}
+
+ const_local_iterator(siterator sit, const hashtable_impl *cont)
+ : const_local_iterator_impl(sit, cont)
+ {}
+ };
+
typedef insert_commit_data_impl insert_commit_data;
+ /// @cond
+
+ const real_value_traits &get_real_value_traits(detail::bool_<false>) const
+ { return *this; }
+
+ const real_value_traits &get_real_value_traits(detail::bool_<true>) const
+ { return base_type::get_value_traits(*this); }
+
+ real_value_traits &get_real_value_traits(detail::bool_<false>)
+ { return *this; }
+
+ real_value_traits &get_real_value_traits(detail::bool_<true>)
+ { return base_type::get_value_traits(*this); }
+
+ /// @endcond
+
+ public:
+
+ const real_value_traits &get_real_value_traits() const
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
+ real_value_traits &get_real_value_traits()
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
//! <b>Requires</b>: buckets must not be being used by any other resource.
//!
//! <b>Effects</b>: Constructs an empty unordered_set, storing a reference
- //! to the bucket array and copies of the hasher and equal functors.
+ //! to the bucket array and copies of the key_hasher and equal_func functors.
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
- //! or the copy constructor or invocation of Hash or Equal throws.
+ //! or the copy constructor or invocation of hash_func or equal_func throws.
//!
//! <b>Notes</b>: buckets array must be disposed only after
- //! *this is disposed.
- hashtable( bucket_ptr buckets
- , size_type buckets_len
- , const Hash & hasher = Hash()
- , const Equal &equal = Equal())
- : bucket_hash_equal_(hasher, equal)
+ //! *this is disposed.
+ hashtable_impl ( const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : base_type(b_traits, hash_func, equal_func, v_traits)
{
-
- BOOST_INTRUSIVE_INVARIANT_ASSERT(buckets_len != 0);
- priv_buckets() = buckets;
- priv_buckets_len() = buckets_len;
priv_clear_buckets();
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(this->priv_buckets_len() != 0);
+ //Check power of two bucket array if the option is activated
+ BOOST_INTRUSIVE_INVARIANT_ASSERT
+ (!power_2_buckets || (0 == (this->priv_buckets_len() & (this->priv_buckets_len()-1))));
}
//! <b>Effects</b>: Detaches all elements from this. The objects in the unordered_set
@@ -216,7 +499,7 @@
//! it's a safe-mode or auto-unlink value. Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
- ~hashtable()
+ ~hashtable_impl()
{ this->clear(); }
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_set.
@@ -228,8 +511,7 @@
iterator begin()
{
size_type bucket_num;
- local_iterator local_it = priv_begin(bucket_num);
- return iterator(local_it, const_bucket_info_ptr(&this->priv_bucket_info()));
+ return iterator(this->priv_begin(bucket_num), this);
}
//! <b>Effects</b>: Returns a const_iterator pointing to the beginning
@@ -240,7 +522,7 @@
//!
//! <b>Throws</b>: Nothing.
const_iterator begin() const
- { return cbegin(); }
+ { return this->cbegin(); }
//! <b>Effects</b>: Returns a const_iterator pointing to the beginning
//! of the unordered_set.
@@ -252,8 +534,7 @@
const_iterator cbegin() const
{
size_type bucket_num;
- local_iterator local_it = priv_begin(bucket_num);
- return const_iterator( local_it, const_bucket_info_ptr(&this->priv_bucket_info()));
+ return const_iterator(this->priv_begin(bucket_num), this);
}
//! <b>Effects</b>: Returns an iterator pointing to the end of the unordered_set.
@@ -262,7 +543,7 @@
//!
//! <b>Throws</b>: Nothing.
iterator end()
- { return iterator(invalid_local_it(this->priv_bucket_info()), 0); }
+ { return iterator(invalid_local_it(this->get_real_bucket_traits()), 0); }
//! <b>Effects</b>: Returns a const_iterator pointing to the end of the unordered_set.
//!
@@ -270,7 +551,7 @@
//!
//! <b>Throws</b>: Nothing.
const_iterator end() const
- { return cend(); }
+ { return this->cend(); }
//! <b>Effects</b>: Returns a const_iterator pointing to the end of the unordered_set.
//!
@@ -278,7 +559,7 @@
//!
//! <b>Throws</b>: Nothing.
const_iterator cend() const
- { return const_iterator(invalid_local_it(this->priv_bucket_info()), 0); }
+ { return const_iterator(invalid_local_it(this->get_real_bucket_traits()), 0); }
//! <b>Effects</b>: Returns the hasher object used by the unordered_set.
//!
@@ -298,15 +579,15 @@
//! <b>Effects</b>: Returns true is the container is empty.
//!
- //! <b>Complexity</b>: if ConstantTimeSize is false, average constant time
+ //! <b>Complexity</b>: if constant_time_size is false, average constant time
//! (worst case, with empty() == true): O(this->bucket_count()).
//! Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
bool empty() const
{
- if(ConstantTimeSize){
- return !size();
+ if(constant_time_size){
+ return !this->size();
}
else{
size_type buckets_len = this->priv_buckets_len();
@@ -323,13 +604,13 @@
//! <b>Effects</b>: Returns the number of elements stored in the unordered_set.
//!
//! <b>Complexity</b>: Linear to elements contained in *this if
- //! ConstantTimeSize is false. Constant-time otherwise.
+ //! constant_time_size is false. Constant-time otherwise.
//!
//! <b>Throws</b>: Nothing.
size_type size() const
{
- if(ConstantTimeSize)
- return size_traits::get_size();
+ if(constant_time_size)
+ return this->priv_size_traits().get_size();
else{
size_type len = 0;
size_type buckets_len = this->priv_buckets_len();
@@ -351,19 +632,18 @@
//!
//! <b>Throws</b>: If the swap() call for the comparison or hash functors
//! found using ADL throw. Basic guarantee.
- void swap(hashtable& other)
+ void swap(hashtable_impl& other)
{
using std::swap;
//These can throw
swap(this->priv_equal(), other.priv_equal());
swap(this->priv_hasher(), other.priv_hasher());
//These can't throw
- swap(this->priv_buckets(), other.priv_buckets());
- swap(this->priv_buckets_len(), other.priv_buckets_len());
- if(ConstantTimeSize){
- size_type backup = size_traits::get_size();
- size_traits::set_size(other.get_size());
- other.set_size(backup);
+ swap(this->get_real_bucket_traits(), other.get_real_bucket_traits());
+ if(constant_time_size){
+ size_type backup = this->priv_size_traits().get_size();
+ this->priv_size_traits().set_size(other.priv_size_traits().get_size());
+ other.priv_size_traits().set_size(backup);
}
}
@@ -381,12 +661,17 @@
//!
//! <b>Throws</b>: If cloner throws. Basic guarantee.
template <class Cloner, class Disposer>
- void clone_from(const hashtable &src, Cloner cloner, Disposer disposer)
+ void clone_from(const hashtable_impl &src, Cloner cloner, Disposer disposer)
{
this->clear_and_dispose(disposer);
- if(!ConstantTimeSize || !src.empty()){
+ if(!constant_time_size || !src.empty()){
const size_type src_bucket_count = src.bucket_count();
const size_type dst_bucket_count = this->bucket_count();
+ //Check power of two bucket array if the option is activated
+ BOOST_INTRUSIVE_INVARIANT_ASSERT
+ (!power_2_buckets || (0 == (src_bucket_count & (src_bucket_count-1))));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT
+ (!power_2_buckets || (0 == (dst_bucket_count & (dst_bucket_count-1))));
//If src bucket count is bigger or equal, structural copy is possible
if(src_bucket_count >= dst_bucket_count){
@@ -394,72 +679,76 @@
const bucket_ptr src_buckets = src.priv_buckets();
const bucket_ptr dst_buckets = this->priv_buckets();
size_type constructed;
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
- BOOST_TRY{
- #endif
+ BOOST_INTRUSIVE_TRY{
for( constructed = 0
; constructed < dst_bucket_count
; ++constructed){
- dst_buckets[constructed].clone_from(src_buckets[constructed], cloner, disposer);
+ dst_buckets[constructed].clone_from
+ ( src_buckets[constructed]
+ , detail::node_cloner<Cloner, hashtable_impl>(cloner, this)
+ , detail::node_disposer<Disposer, hashtable_impl>(disposer, this)
+ );
}
if(src_bucket_count != dst_bucket_count){
//Now insert the remaining ones using the modulo trick
for(//"constructed" comes from the previous loop
; constructed < src_bucket_count
; ++constructed){
- bucket_type &dst_b = dst_buckets[constructed % dst_bucket_count];
+ bucket_type &dst_b = (power_2_buckets)
+ ? dst_buckets[constructed & (dst_bucket_count-1)]
+ : dst_buckets[constructed % dst_bucket_count];
bucket_type &src_b = src_buckets[constructed];
- for( local_iterator b(src_b.begin()), e(src_b.end())
+ for( siterator b(src_b.begin()), e(src_b.end())
; b != e
; ++b){
- dst_b.push_front(*cloner(*b));
+ dst_b.push_front(*detail::node_cloner<Cloner, hashtable_impl>
+ (cloner, this)(b.pointed_node()));
}
}
}
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
}
- BOOST_CATCH(...){
+ BOOST_INTRUSIVE_CATCH(...){
while(constructed--){
- dst_buckets[constructed].clear_and_dispose(disposer);
+ dst_buckets[constructed].clear_and_dispose
+ (detail::node_disposer<Disposer, hashtable_impl>(disposer, this));
}
- BOOST_RETHROW;
+ BOOST_INTRUSIVE_RETHROW;
}
- BOOST_CATCH_END
- #endif
- size_traits::set_size(src.get_size());
+ BOOST_INTRUSIVE_CATCH_END
+ this->priv_size_traits().set_size(src.priv_size_traits().get_size());
}
else{
//Unlike previous cloning algorithm, this can throw
//if cloner, the hasher or comparison functor throw
const_iterator b(src.begin()), e(src.end());
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
- BOOST_TRY{
- #endif
+ BOOST_INTRUSIVE_TRY{
for(; b != e; ++b){
this->insert_equal(*cloner(*b));
}
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
}
- BOOST_CATCH(...){
+ BOOST_INTRUSIVE_CATCH(...){
this->clear_and_dispose(disposer);
BOOST_RETHROW;
}
- BOOST_CATCH_END
- #endif
+ BOOST_INTRUSIVE_CATCH_END
}
}
}
iterator insert_equal(reference value)
{
- size_type bucket_num, hash;
- local_iterator it = priv_find(value, this->priv_hasher(), this->priv_equal(), bucket_num, hash);
+ size_type bucket_num, hash_func;
+ siterator it = this->priv_find
+ (value, this->priv_hasher(), this->priv_equal(), bucket_num, hash_func);
bucket_type &b = this->priv_buckets()[bucket_num];
- if(it == invalid_local_it(this->priv_bucket_info())){
+ if(it == invalid_local_it(this->get_real_bucket_traits())){
it = b.before_begin();
}
- size_traits::increment();
- return iterator(b.insert_after(it, value), const_bucket_info_ptr(&this->priv_bucket_info()));
+ node_ptr n = node_ptr(&from_value_to_node(value));
+ if(safemode_or_autounlink)
+ BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n));
+ this->priv_size_traits().increment();
+ return iterator(b.insert_after(it, *n), this);
}
template<class Iterator>
@@ -488,10 +777,12 @@
std::pair<iterator, bool> insert_unique(reference value)
{
insert_commit_data commit_data;
- std::pair<iterator, bool> ret = insert_unique_check(value, this->priv_hasher(), this->priv_equal(), commit_data);
+ std::pair<iterator, bool> ret = this->insert_unique_check
+ (value, this->priv_hasher(), this->priv_equal(), commit_data);
if(!ret.second)
return ret;
- return std::pair<iterator, bool> (insert_unique_commit(value, commit_data), true);
+ return std::pair<iterator, bool>
+ (this->insert_unique_commit(value, commit_data), true);
}
//! <b>Requires</b>: Dereferencing iterator must yield an lvalue
@@ -513,13 +804,13 @@
this->insert_unique(*b);
}
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Checks if a value can be inserted in the unordered_set, using
//! a user provided key instead of the value itself.
@@ -532,7 +823,7 @@
//!
//! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or key_value_equal throw. Strong guarantee.
+ //! <b>Throws</b>: If hash_func or equal_func throw. Strong guarantee.
//!
//! <b>Notes</b>: This function is used to improve performance when constructing
//! a value_type is expensive: if there is an equivalent value
@@ -551,20 +842,18 @@
template<class KeyType, class KeyHasher, class KeyValueEqual>
std::pair<iterator, bool> insert_unique_check
( const KeyType &key
- , KeyHasher hasher
- , KeyValueEqual key_value_eq
+ , KeyHasher hash_func
+ , KeyValueEqual equal_func
, insert_commit_data &commit_data)
{
size_type bucket_num;
- local_iterator prev_pos =
- priv_find(key, hasher, key_value_eq, bucket_num, commit_data.hash);
- bool success = prev_pos == invalid_local_it(this->priv_bucket_info());
+ siterator prev_pos =
+ this->priv_find(key, hash_func, equal_func, bucket_num, commit_data.hash);
+ bool success = prev_pos == invalid_local_it(this->get_real_bucket_traits());
if(success){
prev_pos = this->priv_buckets()[bucket_num].before_begin();
}
- return std::pair<iterator, bool>
- (iterator(prev_pos, const_bucket_info_ptr(&this->priv_bucket_info()))
- ,success);
+ return std::pair<iterator, bool>(iterator(prev_pos, this),success);
}
//! <b>Requires</b>: value must be an lvalue of type value_type. commit_data
@@ -588,11 +877,13 @@
//! After a successful rehashing insert_commit_data remains valid.
iterator insert_unique_commit(reference value, const insert_commit_data &commit_data)
{
- size_type bucket_num = commit_data.hash % this->priv_buckets_len();
+ size_type bucket_num = from_hash_to_bucket(commit_data.hash);
bucket_type &b = this->priv_buckets()[bucket_num];
- size_traits::increment();
- return iterator( b.insert_after(b.before_begin(), value)
- , const_bucket_info_ptr(&this->priv_bucket_info()));
+ this->priv_size_traits().increment();
+ node_ptr n = node_ptr(&from_value_to_node(value));
+ if(safemode_or_autounlink)
+ BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n));
+ return iterator( b.insert_after(b.before_begin(), *n), this);
}
//! <b>Effects</b>: Erases the element pointed to by i.
@@ -604,7 +895,7 @@
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased element. No destructors are called.
void erase(const_iterator i)
- { erase_and_dispose(i, detail::null_disposer()); }
+ { this->erase_and_dispose(i, detail::null_disposer()); }
//! <b>Effects</b>: Erases the range pointed to by b end e.
//!
@@ -616,7 +907,7 @@
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
void erase(const_iterator b, const_iterator e)
- { erase_and_dispose(b, e, detail::null_disposer()); }
+ { this->erase_and_dispose(b, e, detail::null_disposer()); }
//! <b>Effects</b>: Erases all the elements with the given value.
//!
@@ -625,20 +916,21 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.
+ //! Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
size_type erase(const_reference value)
{ return this->erase(value, this->priv_hasher(), this->priv_equal()); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Erases all the elements that have the same hash and
//! compare equal with the given key.
@@ -648,13 +940,13 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw. Basic guarantee.
+ //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)
- { return erase_and_dispose(key, hasher, equal, detail::null_disposer()); }
+ size_type erase(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func)
+ { return this->erase_and_dispose(key, hash_func, equal_func, detail::null_disposer()); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
@@ -670,11 +962,12 @@
template<class Disposer>
void erase_and_dispose(const_iterator i, Disposer disposer)
{
- local_iterator to_erase(i.local());
+ siterator to_erase(i.slist_it());
bucket_ptr f(priv_buckets()), l(f + priv_buckets_len());
bucket_type &b = this->priv_buckets()[bucket_type::get_bucket_num(to_erase, *f, *l)];
- b.erase_after_and_dispose(b.previous(to_erase), disposer);
- size_traits::decrement();
+ b.erase_after_and_dispose
+ (b.previous(to_erase), detail::node_disposer<Disposer, hashtable_impl>(disposer, this));
+ this->priv_size_traits().decrement();
}
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
@@ -696,12 +989,12 @@
//Get the bucket number and local iterator for both iterators
bucket_ptr f(priv_buckets()), l(f + priv_buckets_len());
- size_type first_bucket_num = bucket_type::get_bucket_num(b.local(), *f, *l);
+ size_type first_bucket_num = bucket_type::get_bucket_num(b.slist_it(), *f, *l);
- local_iterator before_first_local_it
- = priv_buckets()[first_bucket_num].previous(b.local());
+ siterator before_first_local_it
+ = priv_buckets()[first_bucket_num].previous(b.slist_it());
size_type last_bucket_num;
- local_iterator last_local_it;
+ siterator last_local_it;
//For the end iterator, we will assign the end iterator
//of the last bucket
@@ -710,7 +1003,7 @@
last_local_it = priv_buckets()[last_bucket_num].end();
}
else{
- last_local_it = e.local();
+ last_local_it = e.slist_it();
last_bucket_num = bucket_type::get_bucket_num(last_local_it, *f, *l);
}
@@ -718,11 +1011,13 @@
//First erase the nodes of the first bucket
{
bucket_type &first_b = buckets[first_bucket_num];
- local_iterator nxt(before_first_local_it); ++nxt;
- local_iterator end = first_b.end();
+ siterator nxt(before_first_local_it); ++nxt;
+ siterator end = first_b.end();
while(nxt != end){
- nxt = first_b.erase_after_and_dispose(before_first_local_it, disposer);
- size_traits::decrement();
+ nxt = first_b.erase_after_and_dispose
+ ( before_first_local_it
+ , detail::node_disposer<Disposer, hashtable_impl>(disposer, this));
+ this->priv_size_traits().decrement();
}
}
@@ -731,23 +1026,26 @@
bucket_type &b = buckets[i];
if(b.empty())
continue;
- local_iterator b_begin(b.before_begin());
- local_iterator nxt(b_begin); ++nxt;
- local_iterator end = b.end();
+ siterator b_begin(b.before_begin());
+ siterator nxt(b_begin); ++nxt;
+ siterator end = b.end();
while(nxt != end){
- nxt = b.erase_after_and_dispose(b_begin, disposer);
- size_traits::decrement();
+ nxt = b.erase_after_and_dispose
+ (b_begin, detail::node_disposer<Disposer, hashtable_impl>(disposer, this));
+ this->priv_size_traits().decrement();
}
}
//Now erase nodes from the last bucket
{
bucket_type &last_b = buckets[last_bucket_num];
- local_iterator b_begin(last_b.before_begin());
- local_iterator nxt(b_begin); ++nxt;
+ siterator b_begin(last_b.before_begin());
+ siterator nxt(b_begin); ++nxt;
while(nxt != last_local_it){
- nxt = last_b.erase_after_and_dispose(b_begin, disposer);
- size_traits::decrement();
+ nxt = last_b.erase_after_and_dispose
+ (b_begin, detail::node_disposer<Disposer, hashtable_impl>
+ (disposer, this));
+ this->priv_size_traits().decrement();
}
}
}
@@ -762,18 +1060,19 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.
+ //! <b>Throws</b>: If the internal hasher or the equality functor throws.
+ //! Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
template<class Disposer>
size_type erase_and_dispose(const_reference value, Disposer disposer)
- { return erase_and_dispose(value, priv_hasher(), priv_equal(), disposer); }
+ { return this->erase_and_dispose(value, priv_hasher(), priv_equal(), disposer); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
//! <b>Effects</b>: Erases all the elements with the given key.
- //! according to the comparison functor "equal".
+ //! according to the comparison functor "equal_func".
//! Disposer::operator()(pointer) is called for the removed elements.
//!
//! <b>Returns</b>: The number of erased elements.
@@ -781,28 +1080,30 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or key_value_equal throw. Basic guarantee.
+ //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators
//! to the erased elements.
template<class KeyType, class KeyHasher, class KeyValueEqual, class Disposer>
- size_type erase_and_dispose(const KeyType& key, KeyHasher hasher
- ,KeyValueEqual equal, Disposer disposer)
+ size_type erase_and_dispose(const KeyType& key, KeyHasher hash_func
+ ,KeyValueEqual equal_func, Disposer disposer)
{
size_type count(0);
- if(ConstantTimeSize && this->empty()){
+ if(constant_time_size && this->empty()){
return 0;
}
- bucket_type &b = this->priv_buckets()[hasher(key) % this->priv_buckets_len()];
- local_iterator it = b.begin();
- local_iterator prev = b.before_begin();
+ bucket_type &b = this->priv_buckets()[from_hash_to_bucket(hash_func(key))];
+ siterator it = b.begin();
+ siterator prev = b.before_begin();
bool found = false;
//Find equal value
while(it != b.end()){
- if(equal(key, *it)){
+ const value_type &v =
+ *this->get_real_value_traits().to_value_ptr(it.pointed_node());
+ if(equal_func(key, v)){
found = true;
break;
}
@@ -814,9 +1115,12 @@
return 0;
//If found erase all equal values
- for(local_iterator end = b.end(); it != end && equal(key, *it); ++count){
- it = b.erase_after_and_dispose(prev, disposer);
- size_traits::decrement();
+ for(siterator end = b.end(); it != end &&
+ equal_func(key, *this->get_real_value_traits().to_value_ptr(it.pointed_node()))
+ ; ++count){
+ it = b.erase_after_and_dispose
+ (prev, detail::node_disposer<Disposer, hashtable_impl>(disposer, this));
+ this->priv_size_traits().decrement();
}
return count;
}
@@ -832,10 +1136,8 @@
//! to the erased elements. No destructors are called.
void clear()
{
- if(safemode_or_autounlink){
- priv_clear_buckets();
- }
- size_traits::set_size(size_type(0));
+ priv_clear_buckets();
+ this->priv_size_traits().set_size(size_type(0));
}
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
@@ -852,13 +1154,14 @@
template<class Disposer>
void clear_and_dispose(Disposer disposer)
{
- if(!ConstantTimeSize || !this->empty()){
+ if(!constant_time_size || !this->empty()){
size_type num_buckets = this->bucket_count();
bucket_ptr b = this->priv_buckets();
for(; num_buckets--; ++b){
- b->clear_and_dispose(disposer);
+ b->clear_and_dispose
+ (detail::node_disposer<Disposer, hashtable_impl>(disposer, this));
}
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
}
}
@@ -870,24 +1173,24 @@
size_type count(const_reference value) const
{ return this->count(value, this->priv_hasher(), this->priv_equal()); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Returns the number of contained elements with the given key
//!
//! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw.
+ //! <b>Throws</b>: If hash_func or equal throw.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- size_type count(const KeyType &key, const KeyHasher &hasher, const KeyValueEqual &equal) const
+ size_type count(const KeyType &key, const KeyHasher &hash_func, const KeyValueEqual &equal_func) const
{
size_type bucket_n1, bucket_n2, count;
- priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);
+ this->priv_equal_range(key, hash_func, equal_func, bucket_n1, bucket_n2, count);
return count;
}
@@ -898,34 +1201,33 @@
//!
//! <b>Throws</b>: If the internal hasher or the equality functor throws.
iterator find(const_reference value)
- { return find(value, this->priv_hasher(), this->priv_equal()); }
+ { return this->find(value, this->priv_hasher(), this->priv_equal()); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Finds an iterator to the first element whose key is
- //! "key" according to the given hasher and equality functor or end() if
+ //! "key" according to the given hash and equality functor or end() if
//! that element does not exist.
//!
//! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw.
+ //! <b>Throws</b>: If hash_func or equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- iterator find(const KeyType &key, KeyHasher hasher, KeyValueEqual equal)
+ iterator find(const KeyType &key, KeyHasher hash_func, KeyValueEqual equal_func)
{
size_type bucket_n, hash;
- local_iterator local_it = priv_find(key, hasher, equal, bucket_n, hash);
- return iterator( local_it
- , const_bucket_info_ptr(&this->priv_bucket_info()));
+ siterator local_it = this->priv_find(key, hash_func, equal_func, bucket_n, hash);
+ return iterator(local_it, this);
}
//! <b>Effects</b>: Finds a const_iterator to the first element whose key is
@@ -935,15 +1237,15 @@
//!
//! <b>Throws</b>: If the internal hasher or the equality functor throws.
const_iterator find(const_reference value) const
- { return find(value, this->priv_hasher(), this->priv_equal()); }
+ { return this->find(value, this->priv_hasher(), this->priv_equal()); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Finds an iterator to the first element whose key is
//! "key" according to the given hasher and equality functor or end() if
@@ -951,19 +1253,18 @@
//!
//! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw.
+ //! <b>Throws</b>: If hash_func or equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
const_iterator find
- (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const
+ (const KeyType &key, KeyHasher hash_func, KeyValueEqual equal_func) const
{
size_type bucket_n, hash;
- local_iterator local_it = priv_find(key, hasher, equal, bucket_n, hash);
- return const_iterator( local_it
- , const_bucket_info_ptr(&this->priv_bucket_info()));
+ siterator sit = this->priv_find(key, hash_func, equal_func, bucket_n, hash);
+ return const_iterator(sit, this);
}
//! <b>Effects</b>: Returns a range containing all elements with values equivalent
@@ -976,36 +1277,35 @@
std::pair<iterator,iterator> equal_range(const_reference value)
{ return this->equal_range(value, this->priv_hasher(), this->priv_equal()); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Returns a range containing all elements with equivalent
//! keys. Returns std::make_pair(this->end(), this->end()) if no such
//! elements exist.
//!
- //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).
+ //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
+ //! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or the equal throw.
+ //! <b>Throws</b>: If hash_func or the equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
std::pair<iterator,iterator> equal_range
- (const KeyType &key, KeyHasher hasher, KeyValueEqual equal)
+ (const KeyType &key, KeyHasher hash_func, KeyValueEqual equal_func)
{
size_type bucket_n1, bucket_n2, count;
- std::pair<local_iterator, local_iterator> ret
- = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);
- const_bucket_info_ptr info_ptr (&this->priv_bucket_info());
+ std::pair<siterator, siterator> ret = this->priv_equal_range
+ (key, hash_func, equal_func, bucket_n1, bucket_n2, count);
return std::pair<iterator, iterator>
- ( iterator( ret.first, info_ptr)
- , iterator( ret.second, info_ptr) );
+ (iterator(ret.first, this), iterator(ret.second, this));
}
//! <b>Effects</b>: Returns a range containing all elements with values equivalent
@@ -1019,36 +1319,35 @@
equal_range(const_reference value) const
{ return this->equal_range(value, this->priv_hasher(), this->priv_equal()); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Returns a range containing all elements with equivalent
//! keys. Returns std::make_pair(this->end(), this->end()) if no such
//! elements exist.
//!
- //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).
+ //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
+ //! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If the hasher or equal throw.
+ //! <b>Throws</b>: If the hasher or equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
std::pair<const_iterator,const_iterator> equal_range
- (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const
+ (const KeyType &key, KeyHasher hash_func, KeyValueEqual equal_func) const
{
size_type bucket_n1, bucket_n2, count;
- std::pair<local_iterator, local_iterator> ret
- = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);
- const_bucket_info_ptr info_ptr (&this->priv_bucket_info());
+ std::pair<siterator, siterator> ret =
+ this->priv_equal_range(key, hash_func, equal_func, bucket_n1, bucket_n2, count);
return std::pair<const_iterator, const_iterator>
- ( const_iterator( ret.first, info_ptr)
- , const_iterator( ret.second, info_ptr) );
+ (const_iterator(ret.first, this), const_iterator(ret.second, this));
}
//! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
@@ -1062,8 +1361,7 @@
//! <b>Throws</b>: If the internal hash function throws.
iterator iterator_to(reference value)
{
- return iterator( bucket_type::iterator_to(value)
- , const_bucket_info_ptr(&this->priv_bucket_info()));
+ return iterator(bucket_type::s_iterator_to(from_value_to_node(value)), this);
}
//! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
@@ -1077,10 +1375,12 @@
//! <b>Throws</b>: If the internal hash function throws.
const_iterator iterator_to(const_reference value) const
{
- return const_iterator( bucket_type::iterator_to(const_cast<reference>(value))
- , const_bucket_info_ptr(&this->priv_bucket_info()));
+ return const_iterator(bucket_type::s_iterator_to(from_value_to_node(const_cast<reference>(value))), this);
}
+
+
+
//! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
//! appropriate type. Otherwise the behavior is undefined.
//!
@@ -1090,8 +1390,15 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static local_iterator local_iterator_to(reference value)
- { return bucket_type::iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static local_iterator s_local_iterator_to(reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ siterator sit = bucket_type::s_iterator_to(((hashtable_impl*)0)->from_value_to_node(value));
+ return local_iterator(sit, (hashtable_impl*)0);
+ }
//! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
//! appropriate type. Otherwise the behavior is undefined.
@@ -1102,8 +1409,46 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static const_local_iterator local_iterator_to(const_reference value)
- { return bucket_type::iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_local_iterator s_local_iterator_to(const_reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ siterator sit = bucket_type::s_iterator_to(((hashtable_impl*)0)->from_value_to_node(const_cast<value_type&>(value)));
+ return const_local_iterator(sit, (hashtable_impl*)0);
+ }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
+ //! that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ local_iterator local_iterator_to(reference value)
+ {
+ siterator sit = bucket_type::s_iterator_to(this->from_value_to_node(value));
+ return local_iterator(sit, this);
+ }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
+ //! the unordered_set that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ const_local_iterator local_iterator_to(const_reference value) const
+ {
+ siterator sit = bucket_type::s_iterator_to
+ (const_cast<node &>(this->from_value_to_node(value)));
+ return const_local_iterator(sit, this);
+ }
//! <b>Effects</b>: Returns the number of buckets passed in the constructor
//! or the last rehash function.
@@ -1135,21 +1480,21 @@
size_type bucket(const key_type& k) const
{ return this->bucket(k, this->priv_hasher()); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! <b>Effects</b>: Returns the index of the bucket in which elements
//! with keys equivalent to k would be found, if any such element existed.
//!
//! <b>Complexity</b>: Constant.
//!
- //! <b>Throws</b>: If hasher throws.
+ //! <b>Throws</b>: If hash_func throws.
//!
//! <b>Note</b>: the return value is in the range [0, this->bucket_count()).
template<class KeyType, class KeyHasher>
- size_type bucket(const KeyType& k, const KeyHasher &hasher) const
- { return hasher(k) % this->priv_buckets_len(); }
+ size_type bucket(const KeyType& k, const KeyHasher &hash_func) const
+ { return from_hash_to_bucket(hash_func(k)); }
//! <b>Effects</b>: Returns the bucket array pointer passed in the constructor
//! or the last rehash function.
@@ -1172,7 +1517,7 @@
//! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
//! containing all of the elements in the nth bucket.
local_iterator begin(size_type n)
- { return this->priv_buckets()[n].begin(); }
+ { return local_iterator(this->priv_buckets()[n].begin(), this); }
//! <b>Requires</b>: n is in the range [0, this->bucket_count()).
//!
@@ -1200,7 +1545,10 @@
//! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
//! containing all of the elements in the nth bucket.
const_local_iterator cbegin(size_type n) const
- { return const_cast<const bucket_type&>(this->priv_buckets()[n]).begin(); }
+ {
+ siterator sit = const_cast<bucket_type&>(this->priv_buckets()[n]).begin();
+ return const_local_iterator(sit, this);
+ }
//! <b>Requires</b>: n is in the range [0, this->bucket_count()).
//!
@@ -1214,7 +1562,7 @@
//! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
//! containing all of the elements in the nth bucket.
local_iterator end(size_type n)
- { return this->priv_buckets()[n].end(); }
+ { return local_iterator(this->priv_buckets()[n].end(), this); }
//! <b>Requires</b>: n is in the range [0, this->bucket_count()).
//!
@@ -1242,7 +1590,7 @@
//! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
//! containing all of the elements in the nth bucket.
const_local_iterator cend(size_type n) const
- { return const_cast<const bucket_type&>(this->priv_buckets()[n]).end(); }
+ { return const_local_iterator(const_cast<bucket_type&>(this->priv_buckets()[n]).end(), this); }
//! <b>Requires</b>: new_buckets must be a pointer to a new bucket array
//! or the same as the old bucket array. new_size is the length of the
@@ -1255,19 +1603,23 @@
//! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.
//!
//! <b>Throws</b>: If the hasher functor throws. Basic guarantee.
- void rehash(bucket_ptr new_buckets, size_type new_buckets_len)
+ void rehash(const bucket_traits &new_bucket_traits)
{
+ bucket_ptr new_buckets = new_bucket_traits.bucket_begin();
+ size_type new_buckets_len = new_bucket_traits.bucket_count();
bucket_ptr old_buckets = this->priv_buckets();
size_type old_buckets_len = this->priv_buckets_len();
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
- BOOST_TRY{
- #endif
+ //Check power of two bucket array if the option is activated
+ BOOST_INTRUSIVE_INVARIANT_ASSERT
+ (!power_2_buckets || (0 == (new_buckets_len & (new_buckets_len-1u))));
+
+ BOOST_INTRUSIVE_TRY{
size_type n = 0;
const bool same_buffer = old_buckets == new_buckets;
//If the new bucket length is a common factor
//of the old one we can avoid hash calculations.
const bool fast_shrink = (old_buckets_len > new_buckets_len) &&
- (old_buckets_len % new_buckets_len) == 0;
+ (power_2_buckets ||(old_buckets_len % new_buckets_len) == 0);
//If we are shrinking the same bucket array and it's
//is a fast shrink, just rehash the last nodes
if(same_buffer && fast_shrink){
@@ -1279,11 +1631,15 @@
bucket_type &old_bucket = old_buckets[n];
if(!fast_shrink){
- local_iterator before_i(old_bucket.before_begin());
- local_iterator end(old_bucket.end());
- local_iterator i(old_bucket.begin());
+ siterator before_i(old_bucket.before_begin());
+ siterator end(old_bucket.end());
+ siterator i(old_bucket.begin());
for(;i != end; ++i){
- const size_type new_n = (this->priv_hasher()(*i) % new_buckets_len);
+ const value_type &v = *this->get_real_value_traits().to_value_ptr(i.pointed_node());
+ const std::size_t hash_value = this->priv_hasher()(v);
+ const size_type new_n = (power_2_buckets)
+ ? ( hash_value & (new_buckets_len-1))
+ : ( hash_value % new_buckets_len);
//If this is a buffer expansion don't move if it's not necessary
if(same_buffer && new_n == n){
++before_i;
@@ -1296,26 +1652,33 @@
}
}
else{
- const size_type new_n = n % new_buckets_len;
+ const size_type new_n = (power_2_buckets)
+ ? (n & (new_buckets_len-1))
+ : (n % new_buckets_len);
bucket_type &new_b = new_buckets[new_n];
new_b.splice_after(new_b.before_begin(), old_bucket);
}
}
- this->priv_buckets() = new_buckets;
- this->priv_buckets_len() = new_buckets_len;
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
+ this->get_real_bucket_traits()= new_bucket_traits;
}
- BOOST_CATCH(...){
+ BOOST_INTRUSIVE_CATCH(...){
for(size_type n = 0; n < new_buckets_len; ++n){
- new_buckets[n].clear();
- old_buckets[n].clear();
+ if(safemode_or_autounlink){
+ new_buckets[n].clear_and_dispose
+ (detail::init_disposer<node_algorithms>());
+ old_buckets[n].clear_and_dispose
+ (detail::init_disposer<node_algorithms>());
+ }
+ else{
+ new_buckets[n].clear();
+ old_buckets[n].clear();
+ }
}
- size_traits::set_size(size_type(0));
- BOOST_RETHROW;
+ this->priv_size_traits().set_size(size_type(0));
+ BOOST_INTRUSIVE_RETHROW;
}
- BOOST_CATCH_END
- #endif
+ BOOST_INTRUSIVE_CATCH_END
}
//! <b>Effects</b>: Returns the nearest new bucket count optimized for
@@ -1360,10 +1723,10 @@
/// @cond
private:
- static local_iterator invalid_local_it(const bucket_info_t &b)
- { return b.buckets_->end(); }
+ static siterator invalid_local_it(const real_bucket_traits &b)
+ { return b.bucket_begin()->end(); }
- local_iterator priv_begin(size_type &bucket_num) const
+ siterator priv_begin(size_type &bucket_num) const
{
size_type buckets_len = this->priv_buckets_len();
for (bucket_num = 0; bucket_num < buckets_len; ++bucket_num){
@@ -1371,7 +1734,7 @@
if(!b.empty())
return b.begin();
}
- return invalid_local_it(this->priv_bucket_info());
+ return invalid_local_it(this->get_real_bucket_traits());
}
void priv_clear_buckets()
@@ -1380,41 +1743,46 @@
static void priv_clear_buckets(bucket_ptr buckets_ptr, size_type buckets_len)
{
for(; buckets_len--; ++buckets_ptr){
- buckets_ptr->clear();
+ if(safemode_or_autounlink){
+ buckets_ptr->clear_and_dispose(detail::init_disposer<node_algorithms>());
+ }
+ else{
+ buckets_ptr->clear();
+ }
}
}
template<class KeyType, class KeyHasher, class KeyValueEqual>
- local_iterator priv_find
- ( const KeyType &key, KeyHasher hasher
- , KeyValueEqual equal, size_type &bucket_number, size_type &h) const
- {
- size_type b_len(this->priv_buckets_len());
- h = hasher(key);
- bucket_number = h % b_len;
+ siterator priv_find
+ ( const KeyType &key, KeyHasher hash_func
+ , KeyValueEqual equal_func, size_type &bucket_number, size_type &h) const
+ {
+ bucket_number = from_hash_to_bucket((h = hash_func(key)));
- if(ConstantTimeSize && this->empty()){
- return invalid_local_it(this->priv_bucket_info());
+ if(constant_time_size && this->empty()){
+ return invalid_local_it(this->get_real_bucket_traits());
}
bucket_type &b = this->priv_buckets()[bucket_number];
- local_iterator it = b.begin();
+ siterator it = b.begin();
while(it != b.end()){
- if(equal(key, *it)){
+ const value_type &v =
+ *this->get_real_value_traits().to_value_ptr(it.pointed_node());
+ if(equal_func(key, v)){
return it;
}
++it;
}
- return invalid_local_it(this->priv_bucket_info());
+ return invalid_local_it(this->get_real_bucket_traits());
}
template<class KeyType, class KeyHasher, class KeyValueEqual>
- std::pair<local_iterator, local_iterator> priv_equal_range
+ std::pair<siterator, siterator> priv_equal_range
( const KeyType &key
- , KeyHasher hasher
- , KeyValueEqual equal
+ , KeyHasher hash_func
+ , KeyValueEqual equal_func
, size_type &bucket_number_first
, size_type &bucket_number_second
, size_type &count) const
@@ -1422,9 +1790,9 @@
size_type h;
count = 0;
//Let's see if the element is present
- std::pair<local_iterator, local_iterator> to_return
- ( priv_find(key, hasher, equal, bucket_number_first, h)
- , invalid_local_it(this->priv_bucket_info()));
+ std::pair<siterator, siterator> to_return
+ ( priv_find(key, hash_func, equal_func, bucket_number_first, h)
+ , invalid_local_it(this->get_real_bucket_traits()));
if(to_return.first == to_return.second){
bucket_number_second = bucket_number_first;
return to_return;
@@ -1433,11 +1801,13 @@
//If it's present, find the first that it's not equal in
//the same bucket
bucket_type &b = this->priv_buckets()[bucket_number_first];
- local_iterator it = to_return.first;
+ siterator it = to_return.first;
++it;
while(it != b.end()){
- if(!equal(key, *it)){
+ const value_type &v =
+ *this->get_real_value_traits().to_value_ptr(it.pointed_node());
+ if(!equal_func(key, v)){
to_return.second = it;
bucket_number_second = bucket_number_first;
return to_return;
@@ -1458,12 +1828,116 @@
}
//Otherwise, return the end node
- to_return.second = invalid_local_it(this->priv_bucket_info());
+ to_return.second = invalid_local_it(this->get_real_bucket_traits());
return to_return;
}
/// @endcond
};
+/// @cond
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none
+ , class O5 = none, class O6 = none
+ , class O7 = none
+ >
+struct make_hashtable_opt
+{
+ typedef typename pack_options
+ < uset_defaults<T>, O1, O2, O3, O4, O5, O6, O7>::type packed_options;
+
+ //Real value traits must be calculated from options
+ typedef typename detail::get_value_traits
+ <T, typename packed_options::value_traits>::type value_traits;
+ /// @cond
+ static const bool external_value_traits =
+ detail::external_value_traits_is_true<value_traits>::value;
+ typedef typename detail::eval_if_c
+ < external_value_traits
+ , detail::eval_value_traits<value_traits>
+ , detail::identity<value_traits>
+ >::type real_value_traits;
+ typedef typename packed_options::bucket_traits specified_bucket_traits;
+ /// @endcond
+ //Real bucket traits must be calculated from options and calculated valute_traits
+ typedef typename get_slist_impl
+ <typename real_value_traits::node_traits>::type slist_impl;
+ typedef typename
+ detail::if_c< detail::is_same
+ < specified_bucket_traits
+ , default_bucket_traits
+ >::value
+ , detail::bucket_traits_impl<slist_impl>
+ , specified_bucket_traits
+ >::type real_bucket_traits;
+
+ typedef usetopt
+ < value_traits
+ , typename packed_options::hash
+ , typename packed_options::equal
+ , typename packed_options::size_type
+ , packed_options::constant_time_size
+ , real_bucket_traits
+ , packed_options::power_2_buckets
+ > type;
+};
+/// @endcond
+
+//! Helper metafunction to define a \c hashtable that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none
+ , class O5 = none, class O6 = none
+ , class O7 = none
+ >
+#endif
+struct make_hashtable
+{
+ /// @cond
+ typedef hashtable_impl
+ < typename make_hashtable_opt
+ <T, O1, O2, O3, O4, O5, O6, O7>::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>
+class hashtable
+ : public make_hashtable<T, O1, O2, O3, O4, O5, O6, O7>::type
+{
+ typedef typename make_hashtable
+ <T, O1, O2, O3, O4, O5, O6, O7>::type Base;
+
+ public:
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::real_value_traits real_value_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+ typedef typename Base::bucket_ptr bucket_ptr;
+ typedef typename Base::size_type size_type;
+ typedef typename Base::hasher hasher;
+ typedef typename Base::bucket_traits bucket_traits;
+ typedef typename Base::key_equal key_equal;
+
+ //Assert if passed value traits are compatible with the type
+ BOOST_STATIC_ASSERT((detail::is_same<typename real_value_traits::value_type, T>::value));
+
+ hashtable ( const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : Base(b_traits, hash_func, equal_func, v_traits)
+ {}
+};
+
+#endif
+
+
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/intrusive_fwd.hpp
==============================================================================
--- trunk/boost/intrusive/intrusive_fwd.hpp (original)
+++ trunk/boost/intrusive/intrusive_fwd.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -14,8 +14,9 @@
#define BOOST_INTRUSIVE_FWD_HPP
#include <cstddef>
-#include <boost/intrusive/tag.hpp>
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/link_mode.hpp>
+
+/// @cond
//std predeclarations
namespace std{
@@ -36,6 +37,14 @@
namespace intrusive {
+struct none;
+
+} //namespace intrusive{
+} //namespace boost{
+
+namespace boost {
+namespace intrusive {
+
////////////////////////////
// Node algorithms
////////////////////////////
@@ -55,104 +64,148 @@
////////////////////////////
//slist
-template < class ValueTraits
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t>
+template
+ < class T
+ , class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class slist;
-template< class Tag = tag
- , linking_policy Policy = safe_link
- , class VoidPointer = void *
- >
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class slist_base_hook;
-template< linking_policy Policy = safe_link
- , class VoidPointer = void *>
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class slist_member_hook;
//list
-template< class ValueTraits
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t>
+template
+ < class T
+ , class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class list;
-template< class Tag = tag
- , linking_policy Policy = safe_link
- , class VoidPointer = void *
- >
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class list_base_hook;
-template< linking_policy Policy = safe_link
- , class VoidPointer = void *>
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class list_member_hook;
+//rbtree/set/multiset
+template
+ < class T
+ , class O1 = none
+ , class O2 = none
+ , class O3 = none
+ , class O4 = none
+ >
+class rbtree;
+
+template
+ < class T
+ , class O1 = none
+ , class O2 = none
+ , class O3 = none
+ , class O4 = none
+ >
+class set;
+
+template
+ < class T
+ , class O1 = none
+ , class O2 = none
+ , class O3 = none
+ , class O4 = none
+ >
+class multiset;
+
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
+class set_base_hook;
+
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
+class set_member_hook;
+
//hash/unordered
-template< class ValueTraits
- , class Hash = boost::hash<typename ValueTraits::value_type>
- , class Equal = std::equal_to<typename ValueTraits::value_type>
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t
- >
+//rbtree/set/multiset
+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 hashtable;
-template< class ValueTraits
- , class Hash = boost::hash<typename ValueTraits::value_type>
- , class Equal = std::equal_to<typename ValueTraits::value_type>
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t
- >
+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 unordered_set;
-template< class ValueTraits
- , class Hash = boost::hash<typename ValueTraits::value_type>
- , class Equal = std::equal_to<typename ValueTraits::value_type>
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t
- >
+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 unordered_multiset;
-template< class Tag = tag
- , linking_policy Policy = safe_link
- , class VoidPointer = void *
- >
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class unordered_set_base_hook;
-template< linking_policy Policy = safe_link
- , class VoidPointer = void *>
+template
+ < class O1 = none
+ , class O2 = none
+ , class O3 = none
+ >
class unordered_set_member_hook;
-
-//rbtree/set
-template < class ValueTraits
- , class Compare = std::less<typename ValueTraits::value_type>
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t
- >
-class rbtree;
-
-template < class ValueTraits
- , class Compare = std::less<typename ValueTraits::value_type>
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t>
-class set;
-
-template < class ValueTraits
- , class Compare = std::less<typename ValueTraits::value_type>
- , bool ConstantTimeSize = true
- , class SizeType = std::size_t>
-class multiset;
-
-template< class Tag = tag
- , linking_policy Policy = safe_link
- , class VoidPointer = void *
- >
-class set_base_hook;
-
-template< linking_policy Policy = safe_link
- , class VoidPointer = void *>
-class set_member_hook;
-
} //namespace intrusive {
} //namespace boost {
+/// @endcond
+
#endif //#ifndef BOOST_INTRUSIVE_FWD_HPP
Added: trunk/boost/intrusive/link_mode.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/intrusive/link_mode.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -0,0 +1,46 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2006-2007
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/intrusive for documentation.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP
+#define BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP
+
+namespace boost {
+namespace intrusive {
+
+//!This enumeration defines the type of value_traits that can be defined
+//!for Boost.Intrusive containers
+enum link_mode_type{
+ //!If this linking policy is specified in a value_traits class
+ //!as the link_mode, containers
+ //!configured with such value_traits won't set the hooks
+ //!of the erased values to a default state. Containers also won't
+ //!check that the hooks of the new values are default initialized.
+ normal_link,
+
+ //!If this linking policy is specified in a value_traits class
+ //!as the link_mode, containers
+ //!configured with such value_traits will set the hooks
+ //!of the erased values to a default state. Containers also will
+ //!check that the hooks of the new values are default initialized.
+ safe_link,
+
+ //!Same as "safe_link" but the user type is an auto-unlink
+ //!type, so the containers with constant-time size features won't be
+ //!compatible with value_traits configured with this policy.
+ //!Containers also know that the a value can be silently erased from
+ //!the container without using any function provided by the containers.
+ auto_unlink
+};
+} //namespace intrusive
+} //namespace boost
+
+#endif //BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP
Deleted: trunk/boost/intrusive/linking_policy.hpp
==============================================================================
--- trunk/boost/intrusive/linking_policy.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
+++ (empty file)
@@ -1,46 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////
-//
-// (C) Copyright Ion Gaztanaga 2006-2007
-//
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-//
-// See http://www.boost.org/libs/intrusive for documentation.
-//
-/////////////////////////////////////////////////////////////////////////////
-
-#ifndef BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP
-#define BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP
-
-namespace boost {
-namespace intrusive {
-
-//!This enumeration defines the type of value_traits that can be defined
-//!for Boost.Intrusive containers
-enum linking_policy{
- //!If this linking policy is specified in a value_traits class
- //!as the linking_policy, containers
- //!configured with such value_traits won't set the hooks
- //!of the erased values to a default state. Containers also won't
- //!check that the hooks of the new values are default initialized.
- normal_link,
-
- //!If this linking policy is specified in a value_traits class
- //!as the linking_policy, containers
- //!configured with such value_traits will set the hooks
- //!of the erased values to a default state. Containers also will
- //!check that the hooks of the new values are default initialized.
- safe_link,
-
- //!Same as "safe_link" but the user type is an auto-unlink
- //!type, so the containers with constant-time size features won't be
- //!compatible with value_traits configured with this policy.
- //!Containers also know that the a value can be silently erased from
- //!the container without using any function provided by the containers.
- auto_unlink
-};
-} //namespace intrusive
-} //namespace boost
-
-#endif //BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP
Modified: trunk/boost/intrusive/list.hpp
==============================================================================
--- trunk/boost/intrusive/list.hpp (original)
+++ trunk/boost/intrusive/list.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -20,79 +20,127 @@
#include <boost/intrusive/list_hook.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/detail/mpl.hpp>
+#include <boost/intrusive/link_mode.hpp>
#include <boost/static_assert.hpp>
-#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
-#include <boost/detail/no_exceptions_support.hpp>
-#endif
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <iterator>
#include <algorithm>
#include <functional>
#include <cstddef>
-#include <iterator>
namespace boost {
namespace intrusive {
+/// @cond
+
+template <class T>
+struct internal_default_list_hook
+{
+ template <class U> static detail::one test(...);
+ template <class U> static detail::two test(typename U::default_list_hook* = 0);
+ static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
+};
+
+template <class T>
+struct get_default_list_hook
+{
+ typedef typename T::default_list_hook type;
+};
+
+template <class ValueTraits, class SizeType, bool ConstantTimeSize>
+struct listopt
+{
+ typedef ValueTraits value_traits;
+ typedef SizeType size_type;
+ static const bool constant_time_size = ConstantTimeSize;
+};
+
+template <class T>
+struct list_defaults
+ : pack_options
+ < none
+ , base_hook
+ < typename detail::eval_if_c
+ < internal_default_list_hook<T>::value
+ , get_default_list_hook<T>
+ , detail::identity<none>
+ >::type
+ >
+ , constant_time_size<true>
+ , size_type<std::size_t>
+ >::type
+{};
+
+/// @endcond
+
//! The class template list is an intrusive container that mimics most of the
//! interface of std::list as described in the C++ standard.
//!
-//! The template parameter ValueTraits is called "value traits". It stores
-//! information and operations about the type to be stored in the container.
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
//!
-//! If the user specifies ConstantTimeSize as "true", a member of type SizeType
-//! will be embedded in the class, that will keep track of the number of stored objects.
-//! This will allow constant-time O(1) size() member, instead of default O(N) size.
-template< class ValueTraits
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class list
- : private detail::size_holder<ConstantTimeSize, SizeType>
+//! The container supports the following options:
+//! \c base_hook<>/member_hook<>/value_traits<>,
+//! \c constant_time_size<> and \c size_type<>.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class list_impl
{
- /// @cond
- private:
- typename ValueTraits::node_traits::node root_;
- typedef list<ValueTraits, ConstantTimeSize, SizeType> this_type;
- typedef typename ValueTraits::node_traits node_traits;
- typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;
-
- //! This class is
- //! non-copyable
- list (const list&);
-
- //! This class is
- //! non-assignable
- list &operator =(const list&);
- /// @endcond
-
//Public typedefs
public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
+ typedef typename Config::value_traits value_traits;
+ /// @cond
+ static const bool external_value_traits =
+ detail::external_value_traits_is_true<value_traits>::value;
+ typedef typename detail::eval_if_c
+ < external_value_traits
+ , detail::eval_value_traits<value_traits>
+ , detail::identity<value_traits>
+ >::type real_value_traits;
+ /// @endcond
+ typedef typename real_value_traits::pointer pointer;
+ typedef typename real_value_traits::const_pointer const_pointer;
+ typedef typename std::iterator_traits<pointer>::value_type value_type;
typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference;
typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef detail::list_iterator<value_type, ValueTraits> iterator;
- typedef detail::list_iterator<const value_type, ValueTraits> const_iterator;
+ typedef typename Config::size_type size_type;
+ typedef list_iterator<list_impl, false> iterator;
+ typedef list_iterator<list_impl, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef typename real_value_traits::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename node_traits::node_ptr node_ptr;
+ typedef typename node_traits::const_node_ptr const_node_ptr;
+ typedef circular_list_algorithms<node_traits> node_algorithms;
+
+ static const bool constant_time_size = Config::constant_time_size;
+ static const bool stateful_value_traits = detail::store_cont_ptr_on_it<list_impl>::value;
/// @cond
+
private:
- typedef typename node_traits::node node;
- typedef typename node_traits::node_ptr node_ptr;
- typedef typename node_traits::const_node_ptr const_node_ptr;
- typedef circular_list_algorithms<node_traits> node_algorithms;
+ typedef detail::size_holder<constant_time_size, size_type> size_traits;
+
+ //Non-copyable and non-moveable
+ list_impl (const list_impl&);
+ list_impl &operator =(const list_impl&);
+
enum { safemode_or_autounlink =
- (int)ValueTraits::linking_policy == (int)auto_unlink ||
- (int)ValueTraits::linking_policy == (int)safe_link };
+ (int)real_value_traits::link_mode == (int)auto_unlink ||
+ (int)real_value_traits::link_mode == (int)safe_link };
//Constant-time size is incompatible with auto-unlink hooks!
- BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));
+ BOOST_STATIC_ASSERT(!(constant_time_size &&
+ ((int)real_value_traits::link_mode == (int)auto_unlink)
+ ));
//Const cast emulation for smart pointers
static node_ptr uncast(const_node_ptr ptr)
@@ -102,22 +150,64 @@
}
node_ptr get_root_node()
- { return node_ptr(&root_); }
+ { return node_ptr(&data_.root_plus_size_.root_); }
const_node_ptr get_root_node() const
- { return const_node_ptr(&root_); }
+ { return const_node_ptr(&data_.root_plus_size_.root_); }
+
+ struct root_plus_size : public size_traits
+ {
+ node root_;
+ };
+
+ struct data_t : public value_traits
+ {
+ typedef typename list_impl::value_traits value_traits;
+ data_t(const value_traits &val_traits)
+ : value_traits(val_traits)
+ {}
+
+ root_plus_size root_plus_size_;
+ } data_;
+
+ size_traits &priv_size_traits()
+ { return data_.root_plus_size_; }
+
+ const size_traits &priv_size_traits() const
+ { return data_.root_plus_size_; }
+
+ const real_value_traits &get_real_value_traits(detail::bool_<false>) const
+ { return data_; }
+
+ const real_value_traits &get_real_value_traits(detail::bool_<true>) const
+ { return data_.get_value_traits(*this); }
+
+ real_value_traits &get_real_value_traits(detail::bool_<false>)
+ { return data_; }
+
+ real_value_traits &get_real_value_traits(detail::bool_<true>)
+ { return data_.get_value_traits(*this); }
+
/// @endcond
public:
+
+ const real_value_traits &get_real_value_traits() const
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
+ real_value_traits &get_real_value_traits()
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
//! <b>Effects</b>: constructs an empty list.
//!
//! <b>Complexity</b>: Constant
//!
- //! <b>Throws</b>: If value_traits::node_traits::node
+ //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks).
- list()
+ list_impl(const value_traits &v_traits = value_traits())
+ : data_(v_traits)
{
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
node_algorithms::init(this->get_root_node());
}
@@ -127,12 +217,13 @@
//!
//! <b>Complexity</b>: Linear in std::distance(b, e). No copy constructors are called.
//!
- //! <b>Throws</b>: If value_traits::node_traits::node
+ //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks).
template<class Iterator>
- list(Iterator b, Iterator e)
+ list_impl(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
+ : data_(v_traits)
{
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
node_algorithms::init(this->get_root_node());
this->insert(this->end(), b, e);
}
@@ -146,7 +237,7 @@
//!
//! <b>Complexity</b>: Linear to the number of elements in the list, if
//! it's a safe-mode or auto-unlink value . Otherwise constant.
- ~list()
+ ~list_impl()
{
if(safemode_or_autounlink){
this->clear();
@@ -165,11 +256,11 @@
//! <b>Note</b>: Does not affect the validity of iterators and references.
void push_back(reference value)
{
- node_ptr to_insert = ValueTraits::to_node_ptr(value);
+ node_ptr to_insert = get_real_value_traits().to_node_ptr(value);
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
node_algorithms::link_before(this->get_root_node(), to_insert);
- size_traits::increment();
+ this->priv_size_traits().increment();
}
//! <b>Requires</b>: value must be an lvalue.
@@ -184,11 +275,11 @@
//! <b>Note</b>: Does not affect the validity of iterators and references.
void push_front(reference value)
{
- node_ptr to_insert = ValueTraits::to_node_ptr(value);
+ node_ptr to_insert = get_real_value_traits().to_node_ptr(value);
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
node_algorithms::link_before(node_traits::get_next(this->get_root_node()), to_insert);
- size_traits::increment();
+ this->priv_size_traits().increment();
}
//! <b>Effects</b>: Erases the last element of the list.
@@ -203,7 +294,7 @@
{
node_ptr to_erase = node_traits::get_previous(this->get_root_node());
node_algorithms::unlink(to_erase);
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
}
@@ -224,10 +315,10 @@
{
node_ptr to_erase = node_traits::get_previous(this->get_root_node());
node_algorithms::unlink(to_erase);
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
- disposer(ValueTraits::to_value_ptr(to_erase));
+ disposer(get_real_value_traits().to_value_ptr(to_erase));
}
//! <b>Effects</b>: Erases the first element of the list.
@@ -242,7 +333,7 @@
{
node_ptr to_erase = node_traits::get_next(this->get_root_node());
node_algorithms::unlink(to_erase);
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
}
@@ -263,10 +354,10 @@
{
node_ptr to_erase = node_traits::get_next(this->get_root_node());
node_algorithms::unlink(to_erase);
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
- disposer(ValueTraits::to_value_ptr(to_erase));
+ disposer(get_real_value_traits().to_value_ptr(to_erase));
}
//! <b>Effects</b>: Returns a reference to the first element of the list.
@@ -275,7 +366,7 @@
//!
//! <b>Complexity</b>: Constant.
reference front()
- { return *ValueTraits::to_value_ptr(node_traits::get_next(this->get_root_node())); }
+ { return *get_real_value_traits().to_value_ptr(node_traits::get_next(this->get_root_node())); }
//! <b>Effects</b>: Returns a const_reference to the first element of the list.
//!
@@ -283,7 +374,7 @@
//!
//! <b>Complexity</b>: Constant.
const_reference front() const
- { return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); }
+ { return *get_real_value_traits().to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); }
//! <b>Effects</b>: Returns a reference to the last element of the list.
//!
@@ -291,7 +382,7 @@
//!
//! <b>Complexity</b>: Constant.
reference back()
- { return *ValueTraits::to_value_ptr(node_traits::get_previous(this->get_root_node())); }
+ { return *get_real_value_traits().to_value_ptr(node_traits::get_previous(this->get_root_node())); }
//! <b>Effects</b>: Returns a const_reference to the last element of the list.
//!
@@ -299,7 +390,7 @@
//!
//! <b>Complexity</b>: Constant.
const_reference back() const
- { return *ValueTraits::to_value_ptr(uncast(node_traits::get_previous(this->get_root_node()))); }
+ { return *get_real_value_traits().to_value_ptr(uncast(node_traits::get_previous(this->get_root_node()))); }
//! <b>Effects</b>: Returns an iterator to the first element contained in the list.
//!
@@ -307,7 +398,7 @@
//!
//! <b>Complexity</b>: Constant.
iterator begin()
- { return iterator(node_traits::get_next(this->get_root_node())); }
+ { return iterator(node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
//!
@@ -323,7 +414,7 @@
//!
//! <b>Complexity</b>: Constant.
const_iterator cbegin() const
- { return const_iterator(node_traits::get_next(this->get_root_node())); }
+ { return const_iterator(node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns an iterator to the end of the list.
//!
@@ -331,7 +422,7 @@
//!
//! <b>Complexity</b>: Constant.
iterator end()
- { return iterator(this->get_root_node()); }
+ { return iterator(this->get_root_node(), this); }
//! <b>Effects</b>: Returns a const_iterator to the end of the list.
//!
@@ -347,7 +438,7 @@
//!
//! <b>Complexity</b>: Constant.
const_iterator cend() const
- { return const_iterator(uncast(this->get_root_node())); }
+ { return const_iterator(uncast(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
//! of the reversed list.
@@ -411,11 +502,8 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static list &container_from_end_iterator(iterator end_iterator)
- {
- return *detail::parent_from_member<list, node>
- ( detail::get_pointer(end_iterator.pointed_node()), &list::root_);
- }
+ static list_impl &container_from_end_iterator(iterator end_iterator)
+ { return priv_container_from_end_iterator(end_iterator); }
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator
//! of list.
@@ -425,24 +513,21 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static const list &container_from_end_iterator(const_iterator end_iterator)
- {
- return *detail::parent_from_member<list, node>
- ( detail::get_pointer(end_iterator.pointed_node()), &list::root_);
- }
+ static const list_impl &container_from_end_iterator(const_iterator end_iterator)
+ { return priv_container_from_end_iterator(end_iterator); }
//! <b>Effects</b>: Returns the number of the elements contained in the list.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Linear to the number of elements contained in the list.
- //! if ConstantTimeSize is false. Constant time otherwise.
+ //! if constant-time size option is disabled. Constant time otherwise.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
size_type size() const
{
- if(ConstantTimeSize)
- return size_traits::get_size();
+ if(constant_time_size)
+ return this->priv_size_traits().get_size();
else
return node_algorithms::count(this->get_root_node()) - 1;
}
@@ -464,13 +549,13 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
- void swap(list& other)
+ void swap(list_impl& other)
{
node_algorithms::swap_nodes(this->get_root_node(), other.get_root_node());
- if(ConstantTimeSize){
- size_type backup = size_traits::get_size();
- size_traits::set_size(other.get_size());
- other.set_size(backup);
+ if(constant_time_size){
+ size_type backup = this->priv_size_traits().get_size();
+ this->priv_size_traits().set_size(other.priv_size_traits().get_size());
+ other.priv_size_traits().set_size(backup);
}
}
@@ -543,7 +628,7 @@
++i;
node_ptr to_erase = erase.pointed_node();
node_algorithms::unlink(to_erase);
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
return i;
@@ -566,7 +651,7 @@
//! erased elements.
iterator erase(iterator b, iterator e)
{
- if(safemode_or_autounlink || ConstantTimeSize){
+ if(safemode_or_autounlink || constant_time_size){
while(b != e){
b = this->erase(b);
}
@@ -599,10 +684,10 @@
++i;
node_ptr to_erase = erase.pointed_node();
node_algorithms::unlink(to_erase);
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
- disposer(ValueTraits::to_value_ptr(to_erase));
+ disposer(get_real_value_traits().to_value_ptr(to_erase));
return i;
}
@@ -645,7 +730,7 @@
}
else{
node_algorithms::init(this->get_root_node());
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
}
}
@@ -678,24 +763,20 @@
//!
//! <b>Throws</b>: If cloner throws. Basic guarantee.
template <class Cloner, class Disposer>
- void clone_from(const list &src, Cloner cloner, Disposer disposer)
+ void clone_from(const list_impl &src, Cloner cloner, Disposer disposer)
{
this->clear_and_dispose(disposer);
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
- BOOST_TRY{
- #endif
+ BOOST_INTRUSIVE_TRY{
const_iterator b(src.begin()), e(src.end());
for(; b != e; ++b){
this->push_back(*cloner(*b));
}
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
}
- BOOST_CATCH(...){
- clear_and_dispose(disposer);
- BOOST_RETHROW;
+ BOOST_INTRUSIVE_CATCH(...){
+ this->clear_and_dispose(disposer);
+ BOOST_INTRUSIVE_RETHROW;
}
- BOOST_CATCH_END
- #endif
+ BOOST_INTRUSIVE_CATCH_END
}
//! <b>Requires</b>: value must be an lvalue and p must be a valid iterator of *this.
@@ -711,12 +792,12 @@
//! <b>Note</b>: Does not affect the validity of iterators and references.
iterator insert(iterator p, reference value)
{
- node_ptr to_insert = ValueTraits::to_node_ptr(value);
+ node_ptr to_insert = get_real_value_traits().to_node_ptr(value);
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
node_algorithms::link_before(p.pointed_node(), to_insert);
- size_traits::increment();
- return iterator(to_insert);
+ this->priv_size_traits().increment();
+ return iterator(to_insert, this);
}
//! <b>Requires</b>: Dereferencing iterator must yield
@@ -793,13 +874,15 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of
//! this list. Iterators of this list and all the references are not invalidated.
- void splice(iterator p, list& x)
+ void splice(iterator p, list_impl& x)
{
if(!x.empty()){
+ size_traits &thist = this->priv_size_traits();
+ size_traits &xt = x.priv_size_traits();
node_algorithms::transfer
(p.pointed_node(), x.begin().pointed_node(), x.end().pointed_node());
- size_traits::set_size(size_traits::get_size() + x.get_size());
- x.set_size(size_type(0));
+ thist.set_size(thist.get_size() + xt.get_size());
+ xt.set_size(size_type(0));
}
}
@@ -816,11 +899,11 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice(iterator p, list&x, iterator new_ele)
+ void splice(iterator p, list_impl&x, iterator new_ele)
{
node_algorithms::transfer(p.pointed_node(), new_ele.pointed_node());
- x.decrement();
- size_traits::increment();
+ x.priv_size_traits().decrement();
+ this->priv_size_traits().increment();
}
//! <b>Requires</b>: p must be a valid iterator of *this.
@@ -832,18 +915,20 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Linear to the number of elements transferred
- //! if ConstantTimeSize is true. Constant-time otherwise.
+ //! if constant-time size option is enabled. Constant-time otherwise.
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice(iterator p, list&x, iterator start, iterator end)
+ void splice(iterator p, list_impl&x, iterator start, iterator end)
{
if(start != end){
- if(ConstantTimeSize){
+ if(constant_time_size){
+ size_traits &thist = this->priv_size_traits();
+ size_traits &xt = x.priv_size_traits();
size_type increment = std::distance(start, end);
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
- size_traits::set_size(size_traits::get_size() + increment);
- x.set_size(x.get_size() - increment);
+ thist.set_size(thist.get_size() + increment);
+ xt.set_size(xt.get_size() - increment);
}
else{
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
@@ -864,14 +949,16 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice(iterator p, list&x, iterator start, iterator end, difference_type n)
+ void splice(iterator p, list_impl&x, iterator start, iterator end, difference_type n)
{
if(n){
- if(ConstantTimeSize){
+ if(constant_time_size){
+ size_traits &thist = this->priv_size_traits();
+ size_traits &xt = x.priv_size_traits();
BOOST_INTRUSIVE_INVARIANT_ASSERT(n == std::distance(start, end));
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
- size_traits::set_size(size_traits::get_size() + n);
- x.set_size(x.get_size() - n);
+ thist.set_size(thist.get_size() + n);
+ xt.set_size(xt.get_size() - n);
}
else{
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
@@ -882,7 +969,7 @@
//! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
//! The sort is stable, that is, the relative order of equivalent elements is preserved.
//!
- //! <b>Throws</b>: If value_traits::node_traits::node
+ //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
//! or std::less<value_type> throws. Basic guarantee.
//!
@@ -898,12 +985,12 @@
//! <b>Effects</b>: This function sorts the list *this according to p. The sort is
//! stable, that is, the relative order of equivalent elements is preserved.
//!
- //! <b>Throws</b>: If value_traits::node_traits::node
+ //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
//! or the predicate throws. Basic guarantee.
//!
- //! <b>Notes</b>: This won't throw if list_base_hook<>::value_traits or
- //! list_member_hook::::value_traits are used as value traits.
+ //! <b>Notes</b>: This won't throw if list_base_hook<> or
+ //! list_member_hook are used.
//! Iterators and references are not invalidated.
//!
//! <b>Complexity</b>: The number of comparisons is approximately N log N, where N
@@ -913,8 +1000,8 @@
{
if(node_traits::get_next(this->get_root_node())
!= node_traits::get_previous(this->get_root_node())){
- list carry;
- list counter[64];
+ list_impl carry;
+ list_impl counter[64];
int fill = 0;
while(!this->empty()){
carry.splice(carry.begin(), *this, this->begin());
@@ -943,7 +1030,7 @@
//! size() + x.size() - 1 comparisons.
//!
//! <b>Note</b>: Iterators and references are not invalidated
- void merge(list& x)
+ void merge(list_impl& x)
{ merge(x, std::less<value_type>()); }
//! <b>Requires</b>: p must be a comparison function that induces a strict weak
@@ -961,7 +1048,7 @@
//!
//! <b>Note</b>: Iterators and references are not invalidated.
template<class Predicate>
- void merge(list& x, Predicate p)
+ void merge(list_impl& x, Predicate p)
{
iterator e = this->end();
iterator bx = x.begin();
@@ -1142,10 +1229,46 @@
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
- static iterator iterator_to(reference value)
+ //! This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static iterator s_iterator_to(reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(value)));
+ return iterator(real_value_traits::to_node_ptr(value), 0);
+ }
+
+ //! <b>Requires</b>: value must be a const reference to a value inserted in a list.
+ //!
+ //! <b>Effects</b>: This function returns an iterator pointing to the element.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant time.
+ //!
+ //! <b>Note</b>: Iterators and references are not invalidated.
+ //! This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_iterator s_iterator_to(const_reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(const_cast<reference> (value))));
+ return const_iterator(real_value_traits::to_node_ptr(const_cast<reference> (value)), 0);
+ }
+
+ //! <b>Requires</b>: value must be a reference to a value inserted in a list.
+ //!
+ //! <b>Effects</b>: This function returns a const_iterator pointing to the element
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant time.
+ //!
+ //! <b>Note</b>: Iterators and references are not invalidated.
+ iterator iterator_to(reference value)
{
- BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(value)));
- return iterator(ValueTraits::to_node_ptr(value));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(value)));
+ return iterator(real_value_traits::to_node_ptr(value), this);
}
//! <b>Requires</b>: value must be a const reference to a value inserted in a list.
@@ -1157,20 +1280,58 @@
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
- static const_iterator iterator_to(const_reference value)
+ const_iterator iterator_to(const_reference value) const
{
- BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast<reference> (value))));
- return const_iterator(ValueTraits::to_node_ptr(const_cast<reference> (value)));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(const_cast<reference> (value))));
+ return const_iterator(real_value_traits::to_node_ptr(const_cast<reference> (value)), this);
}
+
+ /// @cond
+
+ private:
+ static list_impl &priv_container_from_end_iterator(const const_iterator &end_iterator)
+ {
+ root_plus_size *r = detail::parent_from_member<root_plus_size, node>
+ ( detail::get_pointer(end_iterator.pointed_node()), &root_plus_size::root_);
+ data_t *d = detail::parent_from_member<data_t, root_plus_size>
+ ( r, &data_t::root_plus_size_);
+ list_impl *s = detail::parent_from_member<list_impl, data_t>(d, &list_impl::data_);
+ return *s;
+ }
+ /// @endcond
};
-template <class V, bool C, class S>
-inline bool operator==(const list<V, C, S>& x, const list<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
+#else
+(const list_impl<Config> &x, const list_impl<Config> &y)
+#endif
+{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+bool operator==
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
+#else
+(const list_impl<Config> &x, const list_impl<Config> &y)
+#endif
{
+ typedef list_impl<Config> list_type;
+ typedef typename list_type::const_iterator const_iterator;
+ const bool C = list_type::constant_time_size;
if(C && x.size() != y.size()){
return false;
}
- typedef typename list<V, C, S>::const_iterator const_iterator;
const_iterator end1 = x.end();
const_iterator i1 = x.begin();
@@ -1192,31 +1353,132 @@
}
}
-template <class V, bool C, class S>
-inline bool operator<(const list<V, C, S>& x,
- const list<V, C, S>& y)
-{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
-
-template <class V, bool C, class S>
-inline bool operator!=(const list<V, C, S>& x, const list<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator!=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
+#else
+(const list_impl<Config> &x, const list_impl<Config> &y)
+#endif
{ return !(x == y); }
-template <class V, bool C, class S>
-inline bool operator>(const list<V, C, S>& x, const list<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
+#else
+(const list_impl<Config> &x, const list_impl<Config> &y)
+#endif
{ return y < x; }
-template <class V, bool C, class S>
-inline bool operator<=(const list<V, C, S>& x, const list<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
+#else
+(const list_impl<Config> &x, const list_impl<Config> &y)
+#endif
{ return !(y < x); }
-template <class V, bool C, class S>
-inline bool operator>=(const list<V, C, S>& x, const list<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
+#else
+(const list_impl<Config> &x, const list_impl<Config> &y)
+#endif
{ return !(x < y); }
-template <class V, bool C, class S>
-inline void swap(list<V, C, S>& x, list<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline void swap
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(list_impl<T, Options...> &x, list_impl<T, Options...> &y)
+#else
+(list_impl<Config> &x, list_impl<Config> &y)
+#endif
{ x.swap(y); }
+//! Helper metafunction to define a \c list that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_list
+{
+ /// @cond
+ typedef typename pack_options
+ < list_defaults<T>, O1, O2, O3>::type packed_options;
+ typedef typename detail::get_value_traits
+ <T, typename packed_options::value_traits>::type value_traits;
+
+ typedef list_impl
+ <
+ listopt
+ < value_traits
+ , typename packed_options::size_type
+ , packed_options::constant_time_size
+ >
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
+
+#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class O1, class O2, class O3>
+class list
+ : public make_list<T, O1, O2, O3>::type
+{
+ typedef typename make_list
+ <T, O1, O2, O3>::type Base;
+ typedef typename Base::real_value_traits real_value_traits;
+ //Assert if passed value traits are compatible with the type
+ BOOST_STATIC_ASSERT((detail::is_same<typename real_value_traits::value_type, T>::value));
+ public:
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+
+ list(const value_traits &v_traits = value_traits())
+ : Base(v_traits)
+ {}
+
+ template<class Iterator>
+ list(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
+ : Base(b, e, v_traits)
+ {}
+
+ static list &container_from_end_iterator(iterator end_iterator)
+ { return static_cast<list &>(Base::container_from_end_iterator(end_iterator)); }
+
+ static const list &container_from_end_iterator(const_iterator end_iterator)
+ { return static_cast<const list &>(Base::container_from_end_iterator(end_iterator)); }
+};
+
+#endif
+
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/list_hook.hpp
==============================================================================
--- trunk/boost/intrusive/list_hook.hpp (original)
+++ trunk/boost/intrusive/list_hook.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -17,116 +17,104 @@
#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/detail/list_node.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp>
-#include <boost/intrusive/linking_policy.hpp>
-#include <boost/intrusive/tag.hpp>
-#include <boost/static_assert.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/detail/generic_hook.hpp>
namespace boost {
namespace intrusive {
-//! Derive a class from list_base_hook in order to store objects in
-//! in an list. list_base_hook holds the data necessary to maintain the
-//! list and provides an appropriate value_traits class for list.
+/// @cond
+template<class VoidPointer>
+struct get_list_node_algo
+{
+ typedef circular_list_algorithms<list_node_traits<VoidPointer> > type;
+};
+/// @endcond
+
+//! Helper metafunction to define a \c \c list_base_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_list_base_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
+
+ typedef detail::generic_hook
+ < get_list_node_algo<typename packed_options::void_pointer>
+ , typename packed_options::tag
+ , packed_options::link_mode
+ , detail::ListBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
+//! Derive a class from this hook in order to store objects of that class
+//! in an list.
//!
-//! The first integer template argument defines a tag to identify the node.
+//! The hook admits the following options: \c tag<>, \c void_pointer<> and
+//! \c link_mode<>.
+//!
+//! \c tag<> defines a tag to identify the node.
//! The same tag value can be used in different classes, but if a class is
-//! derived from more than one list_base_hook, then each list_base_hook needs its
+//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its
//! unique tag.
//!
-//! The second boolean template parameter will specify the linking mode of the hook.
+//! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
+//! \c auto_unlink or \c safe_link).
//!
-//! The third argument is the pointer type that will be used internally in the hook
-//! and the list configured from this hook.
-template< class Tag //= tag
- , linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
+//! \c void_pointer<> is the pointer type that will be used internally in the hook
+//! and the the container configured to use this hook.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
class list_base_hook
- : private detail::list_node_traits<VoidPointer>::node
+ : public make_list_base_hook<O1, O2, O3>::type
{
- public:
- typedef detail::list_node_traits<VoidPointer> node_traits;
- enum { linking_policy = Policy };
-
- /// @cond
- private:
- typedef circular_list_algorithms<node_traits> node_algorithms;
-
- public:
- typedef typename node_traits::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;
- typedef list_base_hook
- <Tag, Policy, VoidPointer> this_type;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type>::type this_type_ptr;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type>::type const_this_type_ptr;
-
- private:
- node_ptr this_as_node()
- { return node_ptr(static_cast<node *const>(this)); }
-
- const_node_ptr this_as_node() const
- { return const_node_ptr(static_cast<const node *const>(this)); }
- /// @endcond
-
- public:
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
- list_base_hook()
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ list_base_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using list_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- list_base_hook(const list_base_hook& )
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ list_base_hook(const list_base_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using list_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- list_base_hook& operator=(const list_base_hook& )
- { return *this; }
+ list_base_hook& operator=(const list_base_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an list an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
- ~list_base_hook()
- { detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
+ ~list_base_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
@@ -140,170 +128,102 @@
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
- void swap_nodes(list_base_hook &other)
- { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
+ void swap_nodes(list_base_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
- //! otherwise. This function can be used to test whether list::iterator_to
+ //! otherwise. This function can be used to test whether \c list::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
- bool is_linked() const
- {
- //is_linked() can be only used in safe-mode or auto-unlink
- BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
- return !node_algorithms::unique(this_as_node());
- }
+ bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
- //! This function is only allowed if Policy is auto_unlink.
- //!
- //! <b>Throws</b>: Nothing.
- void unlink()
- {
- BOOST_STATIC_ASSERT((Policy == auto_unlink));
- node_algorithms::unlink(this_as_node());
- node_algorithms::init(this_as_node());
- }
-
- //! The value_traits class is used as the first template argument for list.
- //! The template argument T defines the class type stored in list. Objects
- //! of type T and of types derived from T can be stored. T doesn't need to be
- //! copy-constructible or assignable.
- template<class T>
- struct value_traits
- : detail::derivation_hook_value_traits<T, this_type, Tag>
- {};
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr(static_cast<list_base_hook*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
+ //! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr(static_cast<const list_base_hook*> (detail::get_pointer(p)));
- }
+ void unlink();
+ #endif
+};
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return this_as_node(); }
+//! Helper metafunction to define a \c \c list_member_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_list_member_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return this_as_node(); }
+ typedef detail::generic_hook
+ < get_list_node_algo<typename packed_options::void_pointer>
+ , member_tag
+ , packed_options::link_mode
+ , detail::NoBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
};
-//! Put a public data member list_member_hook in order to store objects of this class in
-//! an list. list_member_hook holds the data necessary for maintaining the list and
-//! provides an appropriate value_traits class for list.
+//! Store this hook in a class to be inserted
+//! in an list.
//!
-//! The first boolean template parameter will specify the linking mode of the hook.
+//! The hook admits the following options: \c void_pointer<> and
+//! \c link_mode<>.
+//!
+//! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
+//! \c auto_unlink or \c safe_link).
//!
-//! The second argument is the pointer type that will be used internally in the hook
-//! and the list configured from this hook.
-template< linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
+//! \c void_pointer<> is the pointer type that will be used internally in the hook
+//! and the the container configured to use this hook.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
class list_member_hook
- : private detail::list_node_traits<VoidPointer>::node
+ : public make_list_member_hook<O1, O2, O3>::type
{
- public:
- typedef detail::list_node_traits<VoidPointer> node_traits;
- enum { linking_policy = Policy };
-
- /// @cond
- private:
- typedef circular_list_algorithms<node_traits> node_algorithms;
- /// @endcond
-
- public:
- typedef typename node_traits::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;
- typedef list_member_hook
- <Policy, VoidPointer> this_type;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type >::type this_type_ptr;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type >::type const_this_type_ptr;
-
- /// @cond
- private:
- node_ptr this_as_node()
- { return node_ptr(static_cast<node *const>(this)); }
-
- const_node_ptr this_as_node() const
- { return const_node_ptr(static_cast<const node *const>(this)); }
- /// @endcond
-
- public:
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
- list_member_hook()
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ list_member_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using list_member_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- list_member_hook(const list_member_hook& )
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ list_member_hook(const list_member_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using list_member_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- list_member_hook& operator=(const list_member_hook& )
- { return *this; }
+ list_member_hook& operator=(const list_member_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an list an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
- ~list_member_hook()
- { detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
+ ~list_member_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
@@ -316,73 +236,24 @@
//!
//! <b>Complexity</b>: Constant
//!
- //! <b>Throws</b>: Nothing.
- void swap_nodes(list_member_hook& other)
- { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
+ //! <b>Throws</b>: Nothing.
+ void swap_nodes(list_member_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
- //! otherwise. This function can be used to test whether list::iterator_to
+ //! otherwise. This function can be used to test whether \c list::iterator_to
//! will return a valid iterator.
//!
- //! <b>Complexity</b>: Constant
- bool is_linked() const
- {
- //is_linked() can be only used in safe-mode or auto-unlink
- BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
- return !node_algorithms::unique(this_as_node());
- }
+ //! <b>Complexity</b>: Constant
+ bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
- //! This function is only allowed if Policy is auto_unlink.
- //!
- //! <b>Throws</b>: Nothing.
- void unlink()
- {
- BOOST_STATIC_ASSERT((Policy == auto_unlink));
- node_algorithms::unlink(this_as_node());
- node_algorithms::init(this_as_node());
- }
-
- //! The value_traits class is used as the first template argument for list.
- //! The template argument is a pointer to member pointing to the node in
- //! the class. Objects of type T and of types derived from T can be stored.
- //! T doesn't need to be copy-constructible or assignable.
- template<class T, this_type T::* M>
- struct value_traits
- : detail::member_hook_value_traits<T, this_type, M>
- {};
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr(static_cast<this_type*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr(static_cast<const this_type*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return this_as_node(); }
-
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
+ //! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return this_as_node(); }
+ void unlink();
+ #endif
};
} //namespace intrusive
Modified: trunk/boost/intrusive/member_value_traits.hpp
==============================================================================
--- trunk/boost/intrusive/member_value_traits.hpp (original)
+++ trunk/boost/intrusive/member_value_traits.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -13,7 +13,7 @@
#ifndef BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/link_mode.hpp>
#include <iterator>
#include <boost/intrusive/detail/parent_from_member.hpp>
@@ -25,7 +25,7 @@
//!store a node_traits::node
template< class T, class NodeTraits
, typename NodeTraits::node T::* PtrToMember
- , linking_policy Policy>
+ , link_mode_type LinkMode = safe_link>
struct member_value_traits
{
public:
@@ -38,8 +38,7 @@
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference;
-
- enum { linking_policy = Policy };
+ static const link_mode_type link_mode = LinkMode;
static node_ptr to_node_ptr(reference value)
{ return node_ptr(&(value.*PtrToMember)); }
Added: trunk/boost/intrusive/options.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/intrusive/options.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -0,0 +1,429 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// (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_OPTIONS_HPP
+#define BOOST_INTRUSIVE_OPTIONS_HPP
+
+#include <boost/intrusive/detail/config_begin.hpp>
+#include <boost/intrusive/intrusive_fwd.hpp>
+#include <boost/intrusive/link_mode.hpp>
+#include <boost/intrusive/detail/mpl.hpp>
+#include <boost/intrusive/detail/utilities.hpp>
+#include <boost/static_assert.hpp>
+
+
+namespace boost {
+namespace intrusive {
+
+/// @cond
+
+struct default_tag;
+struct member_tag;
+
+namespace detail{
+
+template <class ValueTraits>
+struct eval_value_traits
+{
+ typedef typename ValueTraits::value_traits type;
+};
+
+template <class T>
+struct external_bucket_traits_is_true
+{
+ static const bool value = external_bucket_traits_bool<T>::value == 3;
+};
+
+template <class BucketTraits>
+struct eval_bucket_traits
+{
+ typedef typename BucketTraits::bucket_traits type;
+};
+
+template<class T, class BaseHook>
+struct get_base_value_traits
+{
+ typedef detail::base_hook_traits
+ < T
+ , typename BaseHook::boost_intrusive_tags::node_traits
+ , BaseHook::boost_intrusive_tags::link_mode
+ , typename BaseHook::boost_intrusive_tags::tag
+ , BaseHook::boost_intrusive_tags::hook_type> type;
+};
+
+template<class T, class MemberHook>
+struct get_member_value_traits
+{
+ typedef typename MemberHook::member_value_traits type;
+};
+
+template<class T, class SupposedValueTraits>
+struct get_value_traits
+{
+ typedef SupposedValueTraits supposed_value_traits;
+ //...if it's a base hook
+ typedef typename detail::eval_if_c
+ < internal_base_hook_bool_is_true<supposed_value_traits>::value
+ //...get it's internal value traits using
+ //the provided T value type.
+ , get_base_value_traits<T, supposed_value_traits>
+ //...else use it's internal value traits tag
+ //(member hooks and custom value traits are in this group)
+ , detail::eval_if_c
+ < internal_member_value_traits<supposed_value_traits>::value
+ , get_member_value_traits<T, supposed_value_traits>
+ , detail::identity<supposed_value_traits>
+ >
+ >::type type;
+};
+
+template<class BaseHook>
+struct get_base_node_traits
+{
+ typedef typename BaseHook::boost_intrusive_tags::node_traits type;
+};
+
+template<class MemberHook>
+struct get_member_node_traits
+{
+ typedef typename MemberHook::member_value_traits::node_traits type;
+};
+
+template<class ValueTraits>
+struct get_explicit_node_traits
+{
+ typedef typename ValueTraits::node_traits type;
+};
+
+
+template<class SupposedValueTraits>
+struct get_node_traits
+{
+ typedef SupposedValueTraits supposed_value_traits;
+ //...if it's a base hook
+ typedef typename detail::eval_if_c
+ < internal_base_hook_bool_is_true<supposed_value_traits>::value
+ //...get it's internal value traits using
+ //the provided T value type.
+ , get_base_node_traits<supposed_value_traits>
+ //...else use it's internal value traits tag
+ //(member hooks and custom value traits are in this group)
+ , detail::eval_if_c
+ < internal_member_value_traits<supposed_value_traits>::value
+ , get_member_node_traits<supposed_value_traits>
+ , get_explicit_node_traits<supposed_value_traits>
+ >
+ >::type type;
+};
+
+
+} //namespace detail{
+
+
+//!This type indicates that no option is being used
+//!and that the default options should be used
+struct none
+{
+ template<class Base>
+ struct pack : Base
+ { };
+};
+
+/// @endcond
+
+//!This option setter specifies if the intrusive
+//!container stores its size as a member to
+//!obtain constant-time size() member.
+template<bool Enabled>
+struct constant_time_size
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ static const bool constant_time_size = Enabled;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the type that
+//!the container will use to store its size.
+template<class SizeType>
+struct size_type
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef SizeType size_type;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the strict weak ordering
+//!comparison functor for the value type
+template<class Compare>
+struct compare
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef Compare compare;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the equality
+//!functor for the value type
+template<class Equal>
+struct equal
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef Equal equal;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the hash
+//!functor for the value type
+template<class Hash>
+struct hash
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef Hash hash;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the relationship between the type
+//!to be managed by the container (the value type) and the node to be
+//!used in the node algorithms. It also specifies the linking policy.
+template<typename ValueTraits>
+struct value_traits
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef ValueTraits value_traits;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the member hook the
+//!container must use.
+template< typename Parent
+ , typename MemberHook
+ , MemberHook Parent::* PtrToMember>
+struct member_hook
+{
+/// @cond
+ typedef char Parent::* GenericPtrToMember;
+ typedef detail::member_hook_traits
+ < Parent
+ , MemberHook
+ , PtrToMember
+ > member_value_traits;
+ template<class Base>
+ struct pack : Base
+ {
+ typedef member_value_traits value_traits;
+ };
+/// @endcond
+};
+
+//!This option setter specifies that the container
+//!must use the specified base hook
+template<typename BaseHook>
+struct base_hook
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef BaseHook value_traits;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the type of
+//!a void pointer. This will instruct the hook
+//!to use this type of pointer instead of the
+//!default one
+template<class VoidPointer>
+struct void_pointer
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef VoidPointer void_pointer;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the type of
+//!the tag of a base hook. A type can not have two
+//!base hooks of the same type, so a tag can be used
+//!to differentiate two base hooks with otherwise same type
+template<class BaseTag>
+struct tag
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef BaseTag tag;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the type of
+//!a void pointer. This will instruct the hook
+//!to use this type of pointer instead of the
+//!default one
+template<link_mode_type LinkType>
+struct link_mode
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ static const link_mode_type link_mode = LinkType;
+ };
+/// @endcond
+};
+
+//!This option setter specifies the bucket traits
+//!class for unordered associative containers. When this option is specified,
+//!instead of using the default bucket traits, a user defined holder will be defined
+template<class BucketTraits>
+struct bucket_traits
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ typedef BucketTraits bucket_traits;
+ };
+/// @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.
+//!In debug mode, if power of two buckets mode is activated, the bucket length
+//!will be checked to through assertions to assure the bucket length is power of two.
+template<bool Enabled>
+struct power_2_buckets
+{
+/// @cond
+ template<class Base>
+ struct pack : Base
+ {
+ static const bool power_2_buckets = Enabled;
+ };
+/// @endcond
+};
+
+/// @cond
+
+template<class Prev, class Next>
+struct do_pack
+{
+ //Use "pack" member template to pack options
+ typedef typename Next::template pack<Prev> type;
+};
+
+template<class Prev>
+struct do_pack<Prev, none>
+{
+ //Avoid packing "none" to shorten template names
+ typedef Prev type;
+};
+
+
+template
+ < class DefaultOptions
+ , class O1 = none
+ , class O2 = none
+ , class O3 = none
+ , class O4 = none
+ , class O5 = none
+ , class O6 = none
+ , class O7 = none
+ , class O8 = none
+ , class O9 = none
+ , class Option10 = none
+ >
+struct pack_options
+{
+ // join options
+ typedef
+ typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < typename do_pack
+ < DefaultOptions
+ , O1
+ >::type
+ , O2
+ >::type
+ , O3
+ >::type
+ , O4
+ >::type
+ , O5
+ >::type
+ , O6
+ >::type
+ , O7
+ >::type
+ , O8
+ >::type
+ , O9
+ >::type
+ , Option10
+ >::type
+ type;
+};
+
+struct hook_defaults
+ : public pack_options
+ < none
+ , void_pointer<void*>
+ , link_mode<safe_link>
+ , tag<default_tag>
+ >::type
+{};
+
+/// @endcond
+
+} //namespace intrusive {
+} //namespace boost {
+
+#include <boost/intrusive/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTRUSIVE_OPTIONS_HPP
Modified: trunk/boost/intrusive/pointer_plus_bit.hpp
==============================================================================
--- trunk/boost/intrusive/pointer_plus_bit.hpp (original)
+++ trunk/boost/intrusive/pointer_plus_bit.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -23,7 +23,7 @@
template<class VoidPointer, std::size_t Alignment>
struct has_pointer_plus_bit
{
- enum { value = false };
+ static const bool value = false;
};
//!This is an specialization for raw pointers.
@@ -32,7 +32,7 @@
template<std::size_t N>
struct has_pointer_plus_bit<void*, N>
{
- enum { value = N % 2u == 0 };
+ static const bool value = (N % 2u == 0);
};
//!This is class that is supposed to have static methods
Modified: trunk/boost/intrusive/rbtree.hpp
==============================================================================
--- trunk/boost/intrusive/rbtree.hpp (original)
+++ trunk/boost/intrusive/rbtree.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -23,123 +23,228 @@
#include <boost/intrusive/set_hook.hpp>
#include <boost/intrusive/detail/rbtree_node.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp>
+#include <boost/intrusive/options.hpp>
#include <boost/intrusive/rbtree_algorithms.hpp>
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/link_mode.hpp>
#include <cstddef>
#include <iterator>
namespace boost {
namespace intrusive {
+/// @cond
+
+template <class T>
+struct internal_default_set_hook
+{
+ template <class U> static detail::one test(...);
+ template <class U> static detail::two test(typename U::default_set_hook* = 0);
+ static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
+};
+
+template <class T>
+struct get_default_set_hook
+{
+ typedef typename T::default_set_hook type;
+};
+
+template <class ValueTraits, class Compare, class SizeType, bool ConstantTimeSize>
+struct setopt
+{
+ typedef ValueTraits value_traits;
+ typedef Compare compare;
+ typedef SizeType size_type;
+ static const bool constant_time_size = ConstantTimeSize;
+};
+
+template <class T>
+struct set_defaults
+ : pack_options
+ < none
+ , base_hook
+ < typename detail::eval_if_c
+ < internal_default_set_hook<T>::value
+ , get_default_set_hook<T>
+ , detail::identity<none>
+ >::type
+ >
+ , constant_time_size<true>
+ , size_type<std::size_t>
+ , compare<std::less<T> >
+ >::type
+{};
+
+/// @endcond
+
//! The class template rbtree is an intrusive red-black tree container, that
//! is used to construct intrusive set and tree containers. The no-throw
-//! guarantee holds only, if the Compare object
+//! guarantee holds only, if the value_compare object
//! doesn't throw.
-template < class ValueTraits
- , class Compare //= std::less<typename ValueTraits::value_type>
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class rbtree
- : private detail::size_holder<ConstantTimeSize, SizeType>
+//!
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
+//!
+//! The container supports the following options:
+//! \c base_hook<>/member_hook<>/value_traits<>,
+//! \c constant_time_size<>, \c size_type<> and
+//! \c compare<>.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class rbtree_impl
{
+ public:
+ typedef typename Config::value_traits value_traits;
/// @cond
- private:
- typename ValueTraits::node_traits::node root_;
- typedef rbtree<ValueTraits, Compare
- ,ConstantTimeSize, SizeType> this_type;
- typedef typename ValueTraits::node_traits node_traits;
- typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;
-
- //noncopyable
- rbtree (const rbtree&);
- rbtree operator =(const rbtree&);
+ static const bool external_value_traits =
+ detail::external_value_traits_is_true<value_traits>::value;
+ typedef typename detail::eval_if_c
+ < external_value_traits
+ , detail::eval_value_traits<value_traits>
+ , detail::identity<value_traits>
+ >::type real_value_traits;
/// @endcond
+ typedef typename real_value_traits::pointer pointer;
+ typedef typename real_value_traits::const_pointer const_pointer;
+ typedef typename std::iterator_traits<pointer>::value_type value_type;
+ typedef value_type key_type;
+ typedef typename std::iterator_traits<pointer>::reference reference;
+ typedef typename std::iterator_traits<const_pointer>::reference const_reference;
+ typedef typename std::iterator_traits<pointer>::difference_type difference_type;
+ typedef typename Config::size_type size_type;
+ typedef typename Config::compare value_compare;
+ typedef value_compare key_compare;
+ typedef rbtree_iterator<rbtree_impl, false> iterator;
+ typedef rbtree_iterator<rbtree_impl, true> const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef typename real_value_traits::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename boost::pointer_to_other
+ <pointer, node>::type node_ptr;
+ typedef typename boost::pointer_to_other
+ <node_ptr, const node>::type const_node_ptr;
+ typedef rbtree_algorithms<node_traits> node_algorithms;
- public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef value_type key_type;
- typedef Compare value_compare;
- typedef detail::rbtree_iterator<value_type, ValueTraits> iterator;
- typedef detail::rbtree_iterator<const value_type, ValueTraits> const_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ static const bool constant_time_size = Config::constant_time_size;
+ static const bool stateful_value_traits = detail::store_cont_ptr_on_it<rbtree_impl>::value;
/// @cond
private:
- typedef typename node_traits::node node;
- typedef typename boost::pointer_to_other
- <pointer, node>::type node_ptr;
- typedef typename boost::pointer_to_other
- <node_ptr, const node>::type const_node_ptr;
- typedef rbtree_algorithms<node_traits> node_algorithms;
+ typedef detail::size_holder<constant_time_size, size_type> size_traits;
+
+ //noncopyable
+ rbtree_impl (const rbtree_impl&);
+ rbtree_impl operator =(const rbtree_impl&);
+
enum { safemode_or_autounlink =
- (int)ValueTraits::linking_policy == (int)auto_unlink ||
- (int)ValueTraits::linking_policy == (int)safe_link };
+ (int)real_value_traits::link_mode == (int)auto_unlink ||
+ (int)real_value_traits::link_mode == (int)safe_link };
//Constant-time size is incompatible with auto-unlink hooks!
- BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));
+ BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink)));
- //Use EBO if possible
- typedef detail::node_plus_pred<node, Compare> members_t;
- members_t members_;
-
- const Compare &priv_comp() const
- { return members_.second(); }
+ struct header_plus_size : public size_traits
+ { node header_; };
- Compare &priv_comp()
- { return members_.second(); }
+ struct node_plus_pred_t : public detail::ebo_functor_holder<value_compare>
+ {
+ node_plus_pred_t(const value_compare &comp)
+ : detail::ebo_functor_holder<value_compare>(comp)
+ {}
+ header_plus_size header_plus_size_;
+ };
+
+ struct data_t : public rbtree_impl::value_traits
+ {
+ typedef typename rbtree_impl::value_traits value_traits;
+ data_t(const value_compare & comp, const value_traits &val_traits)
+ : value_traits(val_traits), node_plus_pred_(comp)
+ {}
+ node_plus_pred_t node_plus_pred_;
+ } data_;
+
+ const value_compare &priv_comp() const
+ { return data_.node_plus_pred_.get(); }
+
+ value_compare &priv_comp()
+ { return data_.node_plus_pred_.get(); }
const node &priv_header() const
- { return members_.first(); }
+ { return data_.node_plus_pred_.header_plus_size_.header_; }
node &priv_header()
- { return members_.first(); }
+ { return data_.node_plus_pred_.header_plus_size_.header_; }
static node_ptr uncast(const_node_ptr ptr)
{
return node_ptr(const_cast<node*>(detail::get_pointer(ptr)));
}
+
+ size_traits &priv_size_traits()
+ { return data_.node_plus_pred_.header_plus_size_; }
+
+ const size_traits &priv_size_traits() const
+ { return data_.node_plus_pred_.header_plus_size_; }
+
+ const real_value_traits &get_real_value_traits(detail::bool_<false>) const
+ { return data_; }
+
+ const real_value_traits &get_real_value_traits(detail::bool_<true>) const
+ { return data_.get_value_traits(*this); }
+
+ real_value_traits &get_real_value_traits(detail::bool_<false>)
+ { return data_; }
+
+ real_value_traits &get_real_value_traits(detail::bool_<true>)
+ { return data_.get_value_traits(*this); }
+
/// @endcond
public:
+
+ const real_value_traits &get_real_value_traits() const
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
+ real_value_traits &get_real_value_traits()
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
typedef typename node_algorithms::insert_commit_data insert_commit_data;
//! <b>Effects</b>: Constructs an empty tree.
//!
//! <b>Complexity</b>: Constant.
//!
- //! <b>Throws</b>: Nothing unless the copy constructor of the Compare object throws.
- rbtree(Compare cmp = Compare())
- : members_(cmp)
+ //! <b>Throws</b>: Nothing unless the copy constructor of the value_compare object throws.
+ rbtree_impl( value_compare cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : data_(cmp, v_traits)
{
node_algorithms::init_header(&priv_header());
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
}
- //! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type.
+ //! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type.
//! cmp must be a comparison function that induces a strict weak ordering.
- //!
- //! <b>Effects</b>: Constructs an empty tree and inserts elements from
+ //!
+ //! <b>Effects</b>: Constructs an empty tree and inserts elements from
//! [b, e).
- //!
- //! <b>Complexity</b>: Linear in N if [b, e) is already sorted using
+ //!
+ //! <b>Complexity</b>: Linear in N if [b, e) is already sorted using
//! comp and otherwise N * log N, where N is last first.
//!
- //! <b>Throws</b>: Nothing unless the copy constructor of the Compare object throws.
+ //! <b>Throws</b>: Nothing unless the copy constructor of the value_compare object throws.
template<class Iterator>
- rbtree(bool unique, Iterator b, Iterator e, Compare cmp = Compare())
- : members_(cmp)
+ rbtree_impl( bool unique, Iterator b, Iterator e
+ , value_compare cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : data_(cmp, v_traits)
{
node_algorithms::init_header(&priv_header());
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
if(unique)
this->insert_unique(b, e);
else
@@ -148,12 +253,12 @@
//! <b>Effects</b>: Detaches all elements from this. The objects in the set
//! are not deleted (i.e. no destructors are called), but the nodes according to
- //! the ValueTraits template parameter are reinitialized and thus can be reused.
+ //! the value_traits template parameter are reinitialized and thus can be reused.
//!
//! <b>Complexity</b>: Linear to elements contained in *this.
//!
//! <b>Throws</b>: Nothing.
- ~rbtree()
+ ~rbtree_impl()
{ this->clear(); }
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the tree.
@@ -162,7 +267,7 @@
//!
//! <b>Throws</b>: Nothing.
iterator begin()
- { return iterator (node_traits::get_left(node_ptr(&priv_header()))); }
+ { return iterator (node_traits::get_left(node_ptr(&priv_header())), this); }
//! <b>Effects</b>: Returns a const_iterator pointing to the beginning of the tree.
//!
@@ -178,7 +283,7 @@
//!
//! <b>Throws</b>: Nothing.
const_iterator cbegin() const
- { return const_iterator (node_traits::get_left(const_node_ptr(&priv_header()))); }
+ { return const_iterator (node_traits::get_left(const_node_ptr(&priv_header())), this); }
//! <b>Effects</b>: Returns an iterator pointing to the end of the tree.
//!
@@ -186,10 +291,10 @@
//!
//! <b>Throws</b>: Nothing.
iterator end()
- { return iterator (node_ptr(&priv_header())); }
+ { return iterator (node_ptr(&priv_header()), this); }
//! <b>Effects</b>: Returns a const_iterator pointing to the end of the tree.
- //!
+ //!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
@@ -202,7 +307,7 @@
//!
//! <b>Throws</b>: Nothing.
const_iterator cend() const
- { return const_iterator (uncast(const_node_ptr(&priv_header()))); }
+ { return const_iterator (uncast(const_node_ptr(&priv_header())), this); }
//! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning of the
//! reversed tree.
@@ -266,12 +371,8 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static rbtree &container_from_end_iterator(iterator end_iterator)
- {
- return *detail::parent_from_member<rbtree, members_t>
- ( members_t::this_from_node(detail::get_pointer(end_iterator.pointed_node()))
- , &rbtree::members_);
- }
+ static rbtree_impl &container_from_end_iterator(iterator end_iterator)
+ { return priv_container_from_end_iterator(end_iterator); }
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator
//! of rbtree.
@@ -281,12 +382,8 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static const rbtree &container_from_end_iterator(const_iterator end_iterator)
- {
- return *detail::parent_from_member<rbtree, members_t>
- ( members_t::this_from_node(detail::get_pointer(end_iterator.pointed_node()))
- , &rbtree::members_);
- }
+ static const rbtree_impl &container_from_end_iterator(const_iterator end_iterator)
+ { return priv_container_from_end_iterator(end_iterator); }
//! <b>Effects</b>: Returns the value_compare object used by the tree.
//!
@@ -311,8 +408,8 @@
//! <b>Throws</b>: Nothing.
size_type size() const
{
- if(ConstantTimeSize)
- return size_traits::get_size();
+ if(constant_time_size)
+ return this->priv_size_traits().get_size();
else
return empty() ? 0 : node_algorithms::count(node_traits::get_parent(const_node_ptr(&priv_header())));
}
@@ -321,18 +418,18 @@
//!
//! <b>Complexity</b>: Constant.
//!
- //! <b>Throws</b>: If the comparison functor's unspecified swap call throws.
- void swap(rbtree& other)
+ //! <b>Throws</b>: If the comparison functor's none swap call throws.
+ void swap(rbtree_impl& other)
{
//This can throw
using std::swap;
swap(priv_comp(), priv_comp());
//These can't throw
node_algorithms::swap_tree(node_ptr(&priv_header()), node_ptr(&other.priv_header()));
- if(ConstantTimeSize){
- size_type backup = size_traits::get_size();
- size_traits::set_size(other.get_size());
- other.set_size(backup);
+ if(constant_time_size){
+ size_type backup = this->priv_size_traits().get_size();
+ this->priv_size_traits().set_size(other.priv_size_traits().get_size());
+ other.priv_size_traits().set_size(backup);
}
}
@@ -349,13 +446,14 @@
//! No copy-constructors are called.
iterator insert_equal_upper_bound(reference value)
{
- detail::key_node_ptr_compare<value_compare, ValueTraits> key_node_comp(priv_comp());
- node_ptr to_insert(ValueTraits::to_node_ptr(value));
+ detail::key_nodeptr_comp<value_compare, rbtree_impl>
+ key_node_comp(priv_comp(), this);
+ node_ptr to_insert(get_real_value_traits().to_node_ptr(value));
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
- size_traits::increment();
+ this->priv_size_traits().increment();
return iterator(node_algorithms::insert_equal_upper_bound
- (node_ptr(&priv_header()), to_insert, key_node_comp));
+ (node_ptr(&priv_header()), to_insert, key_node_comp), this);
}
//! <b>Requires</b>: value must be an lvalue
@@ -371,13 +469,14 @@
//! No copy-constructors are called.
iterator insert_equal_lower_bound(reference value)
{
- detail::key_node_ptr_compare<value_compare, ValueTraits> key_node_comp(priv_comp());
- node_ptr to_insert(ValueTraits::to_node_ptr(value));
+ detail::key_nodeptr_comp<value_compare, rbtree_impl>
+ key_node_comp(priv_comp(), this);
+ node_ptr to_insert(get_real_value_traits().to_node_ptr(value));
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
- size_traits::increment();
+ this->priv_size_traits().increment();
return iterator(node_algorithms::insert_equal_lower_bound
- (node_ptr(&priv_header()), to_insert, key_node_comp));
+ (node_ptr(&priv_header()), to_insert, key_node_comp), this);
}
//! <b>Requires</b>: value must be an lvalue, and "hint" must be
@@ -396,13 +495,14 @@
//! No copy-constructors are called.
iterator insert_equal(const_iterator hint, reference value)
{
- detail::key_node_ptr_compare<value_compare, ValueTraits> key_node_comp(priv_comp());
- node_ptr to_insert(ValueTraits::to_node_ptr(value));
+ detail::key_nodeptr_comp<value_compare, rbtree_impl>
+ key_node_comp(priv_comp(), this);
+ node_ptr to_insert(get_real_value_traits().to_node_ptr(value));
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
- size_traits::increment();
+ this->priv_size_traits().increment();
return iterator(node_algorithms::insert_equal
- (node_ptr(&priv_header()), hint.pointed_node(), to_insert, key_node_comp));
+ (node_ptr(&priv_header()), hint.pointed_node(), to_insert, key_node_comp), this);
}
//! <b>Requires</b>: Dereferencing iterator must yield an lvalue
@@ -411,8 +511,8 @@
//! <b>Effects</b>: Inserts a each element of a range into the tree
//! before the upper bound of the key of each element.
//!
- //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
- //! size of the range. However, it is linear in N if the range is already sorted
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
+ //! size of the range. However, it is linear in N if the range is already sorted
//! by value_comp().
//!
//! <b>Throws</b>: Nothing.
@@ -512,11 +612,12 @@
std::pair<iterator, bool> insert_unique_check
(const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data)
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> comp(key_value_comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ comp(key_value_comp, this);
std::pair<node_ptr, bool> ret =
(node_algorithms::insert_unique_check
(node_ptr(&priv_header()), key, comp, commit_data));
- return std::pair<iterator, bool>(iterator(ret.first), ret.second);
+ return std::pair<iterator, bool>(iterator(ret.first, this), ret.second);
}
std::pair<iterator, bool> insert_unique_check
@@ -528,22 +629,23 @@
(const_iterator hint, const KeyType &key
,KeyValueCompare key_value_comp, insert_commit_data &commit_data)
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> comp(key_value_comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ comp(key_value_comp, this);
std::pair<node_ptr, bool> ret =
(node_algorithms::insert_unique_check
(node_ptr(&priv_header()), hint.pointed_node(), key, comp, commit_data));
- return std::pair<iterator, bool>(iterator(ret.first), ret.second);
+ return std::pair<iterator, bool>(iterator(ret.first, this), ret.second);
}
iterator insert_unique_commit(reference value, const insert_commit_data &commit_data)
{
- node_ptr to_insert(ValueTraits::to_node_ptr(value));
+ node_ptr to_insert(get_real_value_traits().to_node_ptr(value));
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
- size_traits::increment();
+ this->priv_size_traits().increment();
node_algorithms::insert_unique_commit
(node_ptr(&priv_header()), to_insert, commit_data);
- return iterator(to_insert);
+ return iterator(to_insert, this);
}
//! <b>Effects</b>: Erases the element pointed to by pos.
@@ -562,7 +664,7 @@
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!node_algorithms::unique(to_erase));
node_algorithms::erase(&priv_header(), to_erase);
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
return ret;
@@ -629,7 +731,7 @@
{
node_ptr to_erase(i.pointed_node());
iterator ret(this->erase(i));
- disposer(ValueTraits::to_value_ptr(to_erase));
+ disposer(get_real_value_traits().to_value_ptr(to_erase));
return ret;
}
@@ -706,20 +808,11 @@
void clear()
{
if(safemode_or_autounlink){
- while(1){
- node_ptr leftmost
- (node_algorithms::unlink_leftmost_without_rebalance
- (node_ptr(&priv_header())));
- if(!leftmost)
- break;
- size_traits::decrement();
- if(safemode_or_autounlink)
- node_algorithms::init(leftmost);
- }
+ this->clear_and_dispose(detail::null_disposer());
}
else{
node_algorithms::init_header(&priv_header());
- size_traits::set_size(0);
+ this->priv_size_traits().set_size(0);
}
}
@@ -735,17 +828,10 @@
template<class Disposer>
void clear_and_dispose(Disposer disposer)
{
- while(1){
- node_ptr leftmost
- (node_algorithms::unlink_leftmost_without_rebalance
- (node_ptr(&priv_header())));
- if(!leftmost)
- break;
- size_traits::decrement();
- if(safemode_or_autounlink)
- node_algorithms::init(leftmost);
- disposer(ValueTraits::to_value_ptr(leftmost));
- }
+ node_algorithms::clear_and_dispose(node_ptr(&priv_header())
+ , detail::node_disposer<Disposer, rbtree_impl>(disposer, this));
+ node_algorithms::init_header(&priv_header());
+ this->priv_size_traits().set_size(0);
}
//! <b>Effects</b>: Returns the number of contained elements with the given value
@@ -797,9 +883,10 @@
template<class KeyType, class KeyValueCompare>
iterator lower_bound(const KeyType &key, KeyValueCompare comp)
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
return iterator(node_algorithms::lower_bound
- (const_node_ptr(&priv_header()), key, key_node_comp));
+ (const_node_ptr(&priv_header()), key, key_node_comp), this);
}
//! <b>Effects</b>: Returns a const iterator to the first element whose
@@ -811,9 +898,10 @@
template<class KeyType, class KeyValueCompare>
const_iterator lower_bound(const KeyType &key, KeyValueCompare comp) const
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
return const_iterator(node_algorithms::lower_bound
- (const_node_ptr(&priv_header()), key, key_node_comp));
+ (const_node_ptr(&priv_header()), key, key_node_comp), this);
}
//! <b>Effects</b>: Returns an iterator to the first element whose
@@ -835,9 +923,10 @@
template<class KeyType, class KeyValueCompare>
iterator upper_bound(const KeyType &key, KeyValueCompare comp)
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
return iterator(node_algorithms::upper_bound
- (const_node_ptr(&priv_header()), key, key_node_comp));
+ (const_node_ptr(&priv_header()), key, key_node_comp), this);
}
//! <b>Effects</b>: Returns an iterator to the first element whose
@@ -859,9 +948,10 @@
template<class KeyType, class KeyValueCompare>
const_iterator upper_bound(const KeyType &key, KeyValueCompare comp) const
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
return const_iterator(node_algorithms::upper_bound
- (const_node_ptr(&priv_header()), key, key_node_comp));
+ (const_node_ptr(&priv_header()), key, key_node_comp), this);
}
//! <b>Effects</b>: Finds an iterator to the first element whose key is
@@ -882,9 +972,10 @@
template<class KeyType, class KeyValueCompare>
iterator find(const KeyType &key, KeyValueCompare comp)
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
return iterator
- (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp));
+ (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp), this);
}
//! <b>Effects</b>: Finds a const_iterator to the first element whose key is
@@ -905,9 +996,10 @@
template<class KeyType, class KeyValueCompare>
const_iterator find(const KeyType &key, KeyValueCompare comp) const
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
return const_iterator
- (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp));
+ (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp), this);
}
//! <b>Effects</b>: Finds a range containing all elements whose key is k or
@@ -930,10 +1022,11 @@
template<class KeyType, class KeyValueCompare>
std::pair<iterator,iterator> equal_range(const KeyType &key, KeyValueCompare comp)
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
std::pair<node_ptr, node_ptr> ret
(node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp));
- return std::pair<iterator, iterator>(iterator(ret.first), iterator(ret.second));
+ return std::pair<iterator, iterator>(iterator(ret.first, this), iterator(ret.second, this));
}
//! <b>Effects</b>: Finds a range containing all elements whose key is k or
@@ -958,23 +1051,24 @@
std::pair<const_iterator, const_iterator>
equal_range(const KeyType &key, KeyValueCompare comp) const
{
- detail::key_node_ptr_compare<KeyValueCompare, ValueTraits> key_node_comp(comp);
+ detail::key_nodeptr_comp<KeyValueCompare, rbtree_impl>
+ key_node_comp(comp, this);
std::pair<node_ptr, node_ptr> ret
(node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp));
- return std::pair<const_iterator, const_iterator>(const_iterator(ret.first), const_iterator(ret.second));
+ return std::pair<const_iterator, const_iterator>(const_iterator(ret.first, this), const_iterator(ret.second, this));
}
template <class Cloner, class Disposer>
- void clone_from(const rbtree &src, Cloner cloner, Disposer disposer)
+ void clone_from(const rbtree_impl &src, Cloner cloner, Disposer disposer)
{
this->clear_and_dispose(disposer);
if(!src.empty()){
- node_algorithms::clone_tree
+ node_algorithms::clone
(const_node_ptr(&src.priv_header())
,node_ptr(&this->priv_header())
- ,detail::value_to_node_cloner<Cloner, ValueTraits>(cloner)
- ,detail::value_to_node_disposer<Disposer, ValueTraits>(disposer));
- size_traits::set_size(src.get_size());
+ ,detail::node_cloner<Cloner, rbtree_impl>(cloner, this)
+ ,detail::node_disposer<Disposer, rbtree_impl>(disposer, this));
+ this->priv_size_traits().set_size(src.priv_size_traits().get_size());
}
}
@@ -984,10 +1078,31 @@
(node_ptr(&priv_header())));
if(!to_be_disposed)
return 0;
- size_traits::decrement();
- if(safemode_or_autounlink)
+ this->priv_size_traits().decrement();
+ if(safemode_or_autounlink)//If this is commented does not work with normal_link
node_algorithms::init(to_be_disposed);
- return ValueTraits::to_value_ptr(to_be_disposed);
+ return get_real_value_traits().to_value_ptr(to_be_disposed);
+ }
+
+ //! <b>Requires</b>: replace_this must be a valid iterator of *this
+ //! and with_this must not be inserted in any tree.
+ //!
+ //! <b>Effects</b>: Replaces replace_this in its position in the
+ //! tree with with_this. The tree does not need to be rebalanced.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Note</b>: This function will break container ordering invariants if
+ //! with_this is not equivalent to *replace_this according to the
+ //! ordering rules. This function is faster than erasing and inserting
+ //! the node, since no rebalancing or comparison is needed.
+ void replace_node(iterator replace_this, reference with_this)
+ {
+ node_algorithms::replace_node( get_real_value_traits().to_node_ptr(*replace_this)
+ , node_ptr(&priv_header())
+ , get_real_value_traits().to_node_ptr(with_this));
}
//! <b>Requires</b>: value must be an lvalue and shall be in a set of
@@ -999,8 +1114,14 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static iterator iterator_to(reference value)
- { return iterator (ValueTraits::to_node_ptr(value)); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static iterator s_iterator_to(reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ return iterator (value_traits::to_node_ptr(value), 0);
+ }
//! <b>Requires</b>: value must be an lvalue and shall be in a set of
//! appropriate type. Otherwise the behavior is undefined.
@@ -1010,26 +1131,55 @@
//!
//! <b>Complexity</b>: Constant.
//!
+ //! <b>Throws</b>: Nothing.ç
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_iterator s_iterator_to(const_reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ return const_iterator (value_traits::to_node_ptr(const_cast<reference> (value)), 0);
+ }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the set
+ //! that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
//! <b>Throws</b>: Nothing.
- static const_iterator iterator_to(const_reference value)
- { return const_iterator (ValueTraits::to_node_ptr(const_cast<reference> (value))); }
-/*
- //! <b>Requires</b>: value shall not be in a tree of the appropriate type.
+ iterator iterator_to(reference value)
+ { return iterator (value_traits::to_node_ptr(value), this); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of
+ //! appropriate type. Otherwise the behavior is undefined.
//!
- //! <b>Effects</b>: init_node post-constructs the node data in x used by multisets of
- //! the appropriate type. For the accessors multiset_derived_node and multiset_member_node
- //! init_node has no effect, since the constructors of multiset_node_d and multiset_node_m
- //! have already initialized the node data.
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the
+ //! set that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ const_iterator iterator_to(const_reference value) const
+ { return const_iterator (value_traits::to_node_ptr(const_cast<reference> (value)), this); }
+
+ //! <b>Requires</b>: value shall not be in a tree.
+ //!
+ //! <b>Effects</b>: init_node puts the hook of a value in a well-known default
+ //! state.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant time.
//!
- //! <b>Note</b>: This function is meant to be used mainly with the member value_traits,
- //! where no implicit node initialization during construction occurs.
+ //! <b>Note</b>: This function puts the hook in the well-known default state
+ //! used by auto_unlink and safe hooks.
static void init_node(reference value)
- { node_algorithms::init(node_ptr(&*ValueTraits::to_node_ptr(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.
//!
@@ -1047,15 +1197,16 @@
{
//This function is only usable for safe mode hooks and non-constant
//time lists.
- //BOOST_STATIC_ASSERT((!(safemode_or_autounlink && ConstantTimeSize)));
- BOOST_STATIC_ASSERT((!ConstantTimeSize));
+ //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(ValueTraits::to_node_ptr(value));
+ node_ptr to_remove(value_traits::to_node_ptr(value));
node_algorithms::unlink_and_rebalance(to_remove);
if(safemode_or_autounlink)
node_algorithms::init(to_remove);
}
*/
+
/// @cond
private:
template<class Disposer>
@@ -1073,20 +1224,55 @@
return b;
}
/// @endcond
+
+ private:
+ static rbtree_impl &priv_container_from_end_iterator(const const_iterator &end_iterator)
+ {
+ header_plus_size *r = detail::parent_from_member<header_plus_size, node>
+ ( detail::get_pointer(end_iterator.pointed_node()), &header_plus_size::header_);
+ node_plus_pred_t *n = detail::parent_from_member
+ <node_plus_pred_t, header_plus_size>(r, &node_plus_pred_t::header_plus_size_);
+ data_t *d = detail::parent_from_member<data_t, node_plus_pred_t>(n, &data_t::node_plus_pred_);
+ rbtree_impl *rb = detail::parent_from_member<rbtree_impl, data_t>(d, &rbtree_impl::data_);
+ return *rb;
+ }
};
-template <class V, class P, bool C, class S>
-inline bool operator==(const rbtree<V, P, C, S>& x, const rbtree<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const rbtree_impl<T, Options...> &x, const rbtree_impl<T, Options...> &y)
+#else
+(const rbtree_impl<Config> &x, const rbtree_impl<Config> &y)
+#endif
+{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+bool operator==
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const rbtree_impl<T, Options...> &x, const rbtree_impl<T, Options...> &y)
+#else
+(const rbtree_impl<Config> &x, const rbtree_impl<Config> &y)
+#endif
{
- if(C && x.size() != y.size()){
+ typedef rbtree_impl<Config> tree_type;
+ typedef typename tree_type::const_iterator const_iterator;
+ const bool CS = tree_type::constant_time_size;
+ if(CS && x.size() != y.size()){
return false;
}
- typedef typename rbtree<V, P, C, S>::const_iterator const_iterator;
const_iterator end1 = x.end();
-
const_iterator i1 = x.begin();
const_iterator i2 = y.begin();
- if(C){
+ if(CS){
while (i1 != end1 && *i1 == *i2) {
++i1;
++i2;
@@ -1103,31 +1289,151 @@
}
}
-template <class V, class P, bool C, class S>
-inline bool operator<(const rbtree<V, P, C, S>& x,
- const rbtree<V, P, C, S>& y)
-{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
-
-template <class V, class P, bool C, class S>
-inline bool operator!=(const rbtree<V, P, C, S>& x, const rbtree<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator!=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const rbtree_impl<T, Options...> &x, const rbtree_impl<T, Options...> &y)
+#else
+(const rbtree_impl<Config> &x, const rbtree_impl<Config> &y)
+#endif
{ return !(x == y); }
-template <class V, class P, bool C, class S>
-inline bool operator>(const rbtree<V, P, C, S>& x, const rbtree<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const rbtree_impl<T, Options...> &x, const rbtree_impl<T, Options...> &y)
+#else
+(const rbtree_impl<Config> &x, const rbtree_impl<Config> &y)
+#endif
{ return y < x; }
-template <class V, class P, bool C, class S>
-inline bool operator<=(const rbtree<V, P, C, S>& x, const rbtree<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const rbtree_impl<T, Options...> &x, const rbtree_impl<T, Options...> &y)
+#else
+(const rbtree_impl<Config> &x, const rbtree_impl<Config> &y)
+#endif
{ return !(y < x); }
-template <class V, class P, bool C, class S>
-inline bool operator>=(const rbtree<V, P, C, S>& x, const rbtree<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const rbtree_impl<T, Options...> &x, const rbtree_impl<T, Options...> &y)
+#else
+(const rbtree_impl<Config> &x, const rbtree_impl<Config> &y)
+#endif
{ return !(x < y); }
-template <class V, class P, bool C, class S>
-inline void swap(rbtree<V, P, C, S>& x, rbtree<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline void swap
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(rbtree_impl<T, Options...> &x, rbtree_impl<T, Options...> &y)
+#else
+(rbtree_impl<Config> &x, rbtree_impl<Config> &y)
+#endif
{ x.swap(y); }
+/// @cond
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none
+ , class O5 = none, class O6 = none
+ , class O7 = none
+ >
+struct make_rbtree_opt
+{
+ typedef typename pack_options
+ < set_defaults<T>, O1, O2, O3, O4>::type packed_options;
+ typedef typename detail::get_value_traits
+ <T, typename packed_options::value_traits>::type value_traits;
+
+ typedef setopt
+ < value_traits
+ , typename packed_options::compare
+ , typename packed_options::size_type
+ , packed_options::constant_time_size
+ > type;
+};
+/// @endcond
+
+//! Helper metafunction to define a \c rbtree that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none>
+#endif
+struct make_rbtree
+{
+ /// @cond
+ typedef rbtree_impl
+ < typename make_rbtree_opt<T, O1, O2, O3, O4>::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 rbtree
+ : public make_rbtree<T, O1, O2, O3, O4>::type
+{
+ typedef typename make_rbtree
+ <T, O1, O2, O3, O4>::type Base;
+
+ public:
+ typedef typename Base::value_compare value_compare;
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::real_value_traits real_value_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+
+ //Assert if passed value traits are compatible with the type
+ BOOST_STATIC_ASSERT((detail::is_same<typename real_value_traits::value_type, T>::value));
+
+ rbtree( const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : Base(cmp, v_traits)
+ {}
+
+ template<class Iterator>
+ rbtree( bool unique, Iterator b, Iterator e
+ , const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : Base(unique, b, e, cmp, v_traits)
+ {}
+
+ static rbtree &container_from_end_iterator(iterator end_iterator)
+ { return static_cast<rbtree &>(Base::container_from_end_iterator(end_iterator)); }
+
+ static const rbtree &container_from_end_iterator(const_iterator end_iterator)
+ { return static_cast<const rbtree &>(Base::container_from_end_iterator(end_iterator)); }
+};
+
+#endif
+
+
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/rbtree_algorithms.hpp
==============================================================================
--- trunk/boost/intrusive/rbtree_algorithms.hpp (original)
+++ trunk/boost/intrusive/rbtree_algorithms.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -35,6 +35,15 @@
// in supporting documentation. Hewlett-Packard Company makes no
// representations about the suitability of this software for any
// purpose. It is provided "as is" without express or implied warranty.
+//
+// The tree destruction algorithm is based on Julienne Walker and The EC Team code:
+//
+// This code is in the public domain. Anyone may use it or change it in any way that
+// they see fit. The author assumes no responsibility for damages incurred through
+// use of the original code or any variations thereof.
+//
+// It is requested, but not required, that due credit is given to the original author
+// and anyone who has modified the code through a header comment, such as this one.
#ifndef BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
#define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
@@ -43,9 +52,7 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <cstddef>
-#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
-#include <boost/detail/no_exceptions_support.hpp>
-#endif
+#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
@@ -67,7 +74,7 @@
//! relinked into its place, rather than copied, so that the only
//! pointers invalidated are those referring to the deleted node.
//!
-//! rbtree_algorithms is configured with a NodeTraits class, which capsulates the
+//! rbtree_algorithms is configured with a NodeTraits class, which encapsulates the
//! information about the node to be manipulated. NodeTraits must support the
//! following interface:
//!
@@ -111,6 +118,7 @@
/// @endcond
public:
+ typedef NodeTraits node_traits;
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
typedef typename NodeTraits::color color;
@@ -121,6 +129,27 @@
{
return node_ptr(const_cast<node*>(::boost::intrusive::detail::get_pointer(ptr)));
}
+
+ static void swap_left(node_ptr this_node, node_ptr other_node)
+ {
+ node_ptr temp(NodeTraits::get_left(this_node));
+ NodeTraits::set_left(this_node, NodeTraits::get_left(other_node));
+ NodeTraits::set_left(other_node, temp);
+ }
+
+ static void swap_right(node_ptr this_node, node_ptr other_node)
+ {
+ node_ptr temp(NodeTraits::get_right(this_node));
+ NodeTraits::set_right(this_node, NodeTraits::get_right(other_node));
+ NodeTraits::set_right(other_node, temp);
+ }
+
+ static void swap_parent(node_ptr this_node, node_ptr other_node)
+ {
+ node_ptr temp(NodeTraits::get_parent(this_node));
+ NodeTraits::set_parent(this_node, NodeTraits::get_parent(other_node));
+ NodeTraits::set_parent(other_node, temp);
+ }
/// @endcond
public:
@@ -146,7 +175,14 @@
//!
//! <b>Throws</b>: Nothing.
static void swap_tree(node_ptr header1, node_ptr header2)
- {
+ {/*
+ if(NodeTraits::get_parent(header1)){
+ NodeTraits::node n1;
+ node_ptr n2(NodeTraits::get_parent(header1));
+ init(&n1);
+ swap_nodes(&n1, n2);
+ swap_nodes(&n1, n2);
+ }*/
if(header1 == header2)
return;
@@ -185,6 +221,276 @@
}
}
+ static node_ptr get_header(const_node_ptr node)
+ {
+ node_ptr h = uncast(node);
+ if(NodeTraits::get_parent(node)){
+ h = NodeTraits::get_parent(node);
+ while(!is_header(h))
+ h = NodeTraits::get_parent(h);
+ }
+ return h;
+ }
+
+ //! <b>Requires</b>: node1 and node2 can't be header nodes
+ //! of two trees.
+ //!
+ //! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted
+ //! in the position node2 before the function. node2 will be inserted in the
+ //! position node1 had before the function.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Note</b>: This function will break container ordering invariants if
+ //! node1 and node2 are not equivalent according to the ordering rules.
+ //!
+ //!Experimental function
+ static void swap_nodes(node_ptr node1, node_ptr node2)
+ {
+ if(node1 == node2)
+ return;
+
+ node_ptr header1(get_header(node1)), header2(get_header(node2));
+ swap_nodes(node1, header1, node2, header2);
+ }
+
+ //! <b>Requires</b>: node1 and node2 can't be header nodes
+ //! of two trees with header header1 and header2.
+ //!
+ //! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted
+ //! in the position node2 before the function. node2 will be inserted in the
+ //! position node1 had before the function.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Note</b>: This function will break container ordering invariants if
+ //! node1 and node2 are not equivalent according to the ordering rules.
+ //!
+ //!Experimental function
+ static void swap_nodes(node_ptr node1, node_ptr header1, node_ptr node2, node_ptr header2)
+ {
+ if(node1 == node2)
+ return;
+
+ //node1 and node2 must not be header nodes
+ //BOOST_INTRUSIVE_INVARIANT_ASSERT((header1 != node1 && header2 != node2));
+ if(header1 != header2){
+ //Update header1 if necessary
+ if(node1 == NodeTraits::get_left(header1)){
+ NodeTraits::set_left(header1, node2);
+ }
+
+ if(node1 == NodeTraits::get_right(header1)){
+ NodeTraits::set_right(header1, node2);
+ }
+
+ if(node1 == NodeTraits::get_parent(header1)){
+ NodeTraits::set_parent(header1, node2);
+ }
+
+ //Update header2 if necessary
+ if(node2 == NodeTraits::get_left(header2)){
+ NodeTraits::set_left(header2, node1);
+ }
+
+ if(node2 == NodeTraits::get_right(header2)){
+ NodeTraits::set_right(header2, node1);
+ }
+
+ if(node2 == NodeTraits::get_parent(header2)){
+ NodeTraits::set_parent(header2, node1);
+ }
+ }
+ else{
+ //If both nodes are from the same tree
+ //Update header if necessary
+ if(node1 == NodeTraits::get_left(header1)){
+ NodeTraits::set_left(header1, node2);
+ }
+ else if(node2 == NodeTraits::get_left(header2)){
+ NodeTraits::set_left(header2, node1);
+ }
+
+ if(node1 == NodeTraits::get_right(header1)){
+ NodeTraits::set_right(header1, node2);
+ }
+ else if(node2 == NodeTraits::get_right(header2)){
+ NodeTraits::set_right(header2, node1);
+ }
+
+ if(node1 == NodeTraits::get_parent(header1)){
+ NodeTraits::set_parent(header1, node2);
+ }
+ else if(node2 == NodeTraits::get_parent(header2)){
+ NodeTraits::set_parent(header2, node1);
+ }
+
+ //Adjust data in nodes to be swapped
+ //so that final link swap works as expected
+ if(node1 == NodeTraits::get_parent(node2)){
+ NodeTraits::set_parent(node2, node2);
+
+ if(node2 == NodeTraits::get_right(node1)){
+ NodeTraits::set_right(node1, node1);
+ }
+ else{
+ NodeTraits::set_left(node1, node1);
+ }
+ }
+ else if(node2 == NodeTraits::get_parent(node1)){
+ NodeTraits::set_parent(node1, node1);
+
+ if(node1 == NodeTraits::get_right(node2)){
+ NodeTraits::set_right(node2, node2);
+ }
+ else{
+ NodeTraits::set_left(node2, node2);
+ }
+ }
+ }
+
+ //Now swap all the links
+ node_ptr temp;
+ //swap left link
+ temp = NodeTraits::get_left(node1);
+ NodeTraits::set_left(node1, NodeTraits::get_left(node2));
+ NodeTraits::set_left(node2, temp);
+ //swap right link
+ temp = NodeTraits::get_right(node1);
+ NodeTraits::set_right(node1, NodeTraits::get_right(node2));
+ NodeTraits::set_right(node2, temp);
+ //swap parent link
+ temp = NodeTraits::get_parent(node1);
+ NodeTraits::set_parent(node1, NodeTraits::get_parent(node2));
+ NodeTraits::set_parent(node2, temp);
+ //Swap color
+ color c = NodeTraits::get_color(node1);
+ NodeTraits::set_color(node1, NodeTraits::get_color(node2));
+ NodeTraits::set_color(node2, c);
+
+ //Now adjust adjacent nodes for newly inserted node 1
+ if((temp = NodeTraits::get_left(node1))){
+ NodeTraits::set_parent(temp, node1);
+ }
+ if((temp = NodeTraits::get_right(node1))){
+ NodeTraits::set_parent(temp, node1);
+ }
+ if((temp = NodeTraits::get_parent(node1)) &&
+ //The header has been already updated so avoid it
+ temp != header2){
+ if(NodeTraits::get_left(temp) == node2){
+ NodeTraits::set_left(temp, node1);
+ }
+ if(NodeTraits::get_right(temp) == node2){
+ NodeTraits::set_right(temp, node1);
+ }
+ }
+ //Now adjust adjacent nodes for newly inserted node 2
+ if((temp = NodeTraits::get_left(node2))){
+ NodeTraits::set_parent(temp, node2);
+ }
+ if((temp = NodeTraits::get_right(node2))){
+ NodeTraits::set_parent(temp, node2);
+ }
+ if((temp = NodeTraits::get_parent(node2)) &&
+ //The header has been already updated so avoid it
+ temp != header1){
+ if(NodeTraits::get_left(temp) == node1){
+ NodeTraits::set_left(temp, node2);
+ }
+ if(NodeTraits::get_right(temp) == node1){
+ NodeTraits::set_right(temp, node2);
+ }
+ }
+ }
+
+ //! <b>Requires</b>: node_to_be_replaced must be inserted in a tree
+ //! and new_node must not be inserted in a tree.
+ //!
+ //! <b>Effects</b>: Replaces node_to_be_replaced in its position in the
+ //! tree with new_node. The tree does not need to be rebalanced
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Note</b>: This function will break container ordering invariants if
+ //! new_node is not equivalent to node_to_be_replaced according to the
+ //! ordering rules. This function is faster than erasing and inserting
+ //! the node, since no rebalancing and comparison is needed.
+ //!
+ //!Experimental function
+ static void replace_node(node_ptr node_to_be_replaced, node_ptr new_node)
+ {
+ if(node_to_be_replaced == new_node)
+ return;
+ replace_node(node_to_be_replaced, get_header(node_to_be_replaced), new_node);
+ }
+
+ //! <b>Requires</b>: node_to_be_replaced must be inserted in a tree
+ //! with header "header" and new_node must not be inserted in a tree.
+ //!
+ //! <b>Effects</b>: Replaces node_to_be_replaced in its position in the
+ //! tree with new_node. The tree does not need to be rebalanced
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Note</b>: This function will break container ordering invariants if
+ //! new_node is not equivalent to node_to_be_replaced according to the
+ //! ordering rules. This function is faster than erasing and inserting
+ //! the node, since no rebalancing or comparison is needed.
+ //!
+ //!Experimental function
+ static void replace_node(node_ptr node_to_be_replaced, node_ptr header, node_ptr new_node)
+ {
+ if(node_to_be_replaced == new_node)
+ return;
+
+ //Update header if necessary
+ if(node_to_be_replaced == NodeTraits::get_left(header)){
+ NodeTraits::set_left(header, new_node);
+ }
+
+ if(node_to_be_replaced == NodeTraits::get_right(header)){
+ NodeTraits::set_right(header, new_node);
+ }
+
+ if(node_to_be_replaced == NodeTraits::get_parent(header)){
+ NodeTraits::set_parent(header, new_node);
+ }
+
+ //Now set data from the original node
+ node_ptr temp;
+ NodeTraits::set_left(new_node, NodeTraits::get_left(node_to_be_replaced));
+ NodeTraits::set_right(new_node, NodeTraits::get_right(node_to_be_replaced));
+ NodeTraits::set_parent(new_node, NodeTraits::get_parent(node_to_be_replaced));
+ NodeTraits::set_color(new_node, NodeTraits::get_color(node_to_be_replaced));
+
+ //Now adjust adjacent nodes for newly inserted node
+ if((temp = NodeTraits::get_left(new_node))){
+ NodeTraits::set_parent(temp, new_node);
+ }
+ if((temp = NodeTraits::get_right(new_node))){
+ NodeTraits::set_parent(temp, new_node);
+ }
+ if((temp = NodeTraits::get_parent(new_node)) &&
+ //The header has been already updated so avoid it
+ temp != header){
+ if(NodeTraits::get_left(temp) == node_to_be_replaced){
+ NodeTraits::set_left(temp, new_node);
+ }
+ if(NodeTraits::get_right(temp) == node_to_be_replaced){
+ NodeTraits::set_right(temp, new_node);
+ }
+ }
+ }
+
//! <b>Requires</b>: node is a tree node but not the header.
//!
//! <b>Effects</b>: Unlinks the node and rebalances the tree.
@@ -202,6 +508,10 @@
}
}
+ static void unlink(node_ptr node)
+ { unlink_and_rebalance(node); }
+
+
//! <b>Requires</b>: header is the header of a tree.
//!
//! <b>Effects</b>: Unlinks the leftmost node from the tree, and
@@ -508,25 +818,42 @@
//!
//! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.
template <class Cloner, class Disposer>
- static void clone_tree
+ static void clone
(const_node_ptr source_header, node_ptr target_header, Cloner cloner, Disposer disposer)
{
if(!unique(target_header)){
- node_ptr p;
- while((p = unlink_leftmost_without_rebalance(target_header))){
- disposer(p);
- }
+ clear_and_dispose(target_header, disposer);
}
- node_ptr source_root = NodeTraits::get_parent(source_header);
+ node_ptr leftmost, rightmost;
+ node_ptr new_root = clone_subtree
+ (source_header, target_header, cloner, disposer, leftmost, rightmost);
+
+ //Now update header node
+ NodeTraits::set_parent(target_header, new_root);
+ NodeTraits::set_left (target_header, leftmost);
+ NodeTraits::set_right (target_header, rightmost);
+ }
+
+ //! <b>Requires</b>: "disposer" must be an object function
+ //! taking a node_ptr parameter and shouldn't throw.
+ //!
+ //! <b>Effects</b>: Empties the target tree calling
+ //! <tt>void disposer::operator()(node_ptr)</tt> for every node of the tree
+ //! except the header.
+ //!
+ //! <b>Complexity</b>: Linear to the number of element of the source tree plus the.
+ //! number of elements of tree target tree when calling this function.
+ //!
+ //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.
+ template<class Disposer>
+ static void clear_and_dispose(node_ptr header, Disposer disposer)
+ {
+ node_ptr source_root = NodeTraits::get_parent(header);
if(!source_root)
return;
-
- NodeTraits::set_parent
- ( target_header
- , deep_clone_node(source_root, target_header, cloner, disposer));
- NodeTraits::set_left(target_header, minimum(NodeTraits::get_parent(target_header)));
- NodeTraits::set_right(target_header, maximum(NodeTraits::get_parent(target_header)));
+ dispose_subtree(source_root, disposer);
+ init_header(header);
}
//! <b>Requires</b>: "header" must be the header node of a tree.
@@ -694,6 +1021,17 @@
bool link_left = (y == h) ||
comp(new_node, y);
link_and_balance(new_node, y, link_left, h);
+/*
+ //erase me
+ NodeTraits::node n;
+ init(&n);
+ if(y!=h)
+ x = x;
+ node_ptr n1(y!=h ? y : &n);
+ node_ptr n2(new_node);
+ swap_nodes(n2, n1);
+ swap_nodes(n2, n1);
+*/
return new_node;
}
@@ -725,6 +1063,17 @@
bool link_left = (y == h) ||
!comp(y, new_node);
link_and_balance(new_node, y, link_left, h);
+/*
+ //erase me
+ NodeTraits::node n;
+ init(&n);
+ if(y!=h)
+ x = x;
+ node_ptr n1(y!=h ? y : &n);
+ node_ptr n2(new_node);
+ swap_nodes(n2, n1);
+ swap_nodes(n2, n1);
+*/
return new_node;
}
@@ -752,6 +1101,14 @@
!comp(new_node, (prev = prev_node(hint)))){
bool link_left = unique(header) || !NodeTraits::get_left(hint);
link_and_balance(new_node, link_left ? hint : prev, link_left, header);
+/*
+ //erase me
+ NodeTraits::node n1;
+ node_ptr n2(new_node);
+ init(&n1);
+ swap_nodes(n2, &n1);
+ swap_nodes(&n1, n2);
+*/
return new_node;
}
else{
@@ -922,6 +1279,109 @@
/// @cond
+ template <class Cloner, class Disposer>
+ static node_ptr clone_subtree
+ ( const_node_ptr source_parent, node_ptr target_parent
+ , Cloner cloner, Disposer disposer
+ , node_ptr &leftmost_out, node_ptr &rightmost_out
+ )
+ {
+ node_ptr target_sub_root = target_parent;
+ node_ptr source_root = NodeTraits::get_parent(source_parent);
+ if(!source_root){
+ leftmost_out = rightmost_out = source_root;
+ }
+ else{
+ //We'll calculate leftmost and rightmost nodes while iterating
+ node_ptr current = source_root;
+ node_ptr insertion_point = target_sub_root = cloner(current);
+
+ //We'll calculate leftmost and rightmost nodes while iterating
+ node_ptr leftmost = target_sub_root;
+ 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_parent(target_sub_root, target_parent);
+ NodeTraits::set_color(target_sub_root, NodeTraits::get_color(current));
+
+ 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);
+ NodeTraits::set_color (insertion_point, NodeTraits::get_color(current));
+ //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);
+ NodeTraits::set_color (insertion_point, NodeTraits::get_color(current));
+ //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;
+ }
+ leftmost_out = leftmost;
+ rightmost_out = rightmost;
+ }
+ return target_sub_root;
+ }
+
+ template<class Disposer>
+ static void dispose_subtree(node_ptr x, Disposer disposer)
+ {
+ node_ptr save;
+ while (x){
+ save = NodeTraits::get_left(x);
+ if (save) {
+ // Right rotation
+ NodeTraits::set_left(x, NodeTraits::get_right(save));
+ NodeTraits::set_right(save, x);
+ }
+ else {
+ save = NodeTraits::get_right(x);
+ init(x);
+ disposer(x);
+ }
+ x = save;
+ }
+ }
+
//! <b>Requires</b>: z is the node to be inserted, par is its parent,
//! left, indicates if z should be a left node of par and header is the header
//! of the tree.
@@ -1106,59 +1566,6 @@
}
NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black());
}
-
- template <class Cloner, class Disposer>
- static node_ptr deep_clone_node
- (node_ptr source_root, node_ptr new_parent, Cloner cloner, Disposer disposer)
- {
- // structural copy. source_root and new_parent must be non-null.
- node_ptr top = cloner(source_root);
- NodeTraits::set_parent(top, new_parent);
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
- BOOST_TRY {
- #endif
- if(NodeTraits::get_right(source_root)){
- NodeTraits::set_right
- (top, deep_clone_node(NodeTraits::get_right(source_root), top
- ,cloner, disposer));
- }
- new_parent = top;
- source_root = NodeTraits::get_left(source_root);
-
- while(source_root){
- node_ptr y = cloner(source_root);
- NodeTraits::set_left(new_parent, y);
- NodeTraits::set_parent(y, new_parent);
-
- if(NodeTraits::get_right(source_root)){
- NodeTraits::set_right(y, deep_clone_node(NodeTraits::get_right(source_root), y
- ,cloner, disposer));
- }
- new_parent = y;
- source_root = NodeTraits::get_left(source_root);
- }
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
- }
- BOOST_CATCH(...){
- deep_dispose_node(top, disposer);
- BOOST_RETHROW;
- }
- BOOST_CATCH_END
- #endif
- return top;
- }
-
- template<class Disposer>
- static void deep_dispose_node(node_ptr x, Disposer disposer)
- {
- // erase without rebalancing
- while(x){
- deep_dispose_node(NodeTraits::get_right(x), disposer);
- node_ptr y = NodeTraits::get_left(x);
- disposer(x);
- x = y;
- }
- }
/// @endcond
};
Modified: trunk/boost/intrusive/set.hpp
==============================================================================
--- trunk/boost/intrusive/set.hpp (original)
+++ trunk/boost/intrusive/set.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -24,63 +24,59 @@
//! The class template set is an intrusive container, that mimics most of
//! the interface of std::set as described in the C++ standard.
//!
-//! The template parameter ValueTraits is called "value traits". It stores
-//! information and operations about the type to be stored in the container.
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
//!
-//! The template parameter Compare, provides a function object that can compare two
-//! element values as sort keys to determine their relative order in the set.
-//!
-//! If the user specifies ConstantTimeSize as "true", a member of type SizeType
-//! will be embedded in the class, that will keep track of the number of stored objects.
-//! This will allow constant-time O(1) size() member, instead of default O(N) size.
-template < class ValueTraits
- , class Compare //= std::less<typename ValueTraits::value_type>
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class set
+//! The container supports the following options:
+//! \c base_hook<>/member_hook<>/value_traits<>,
+//! \c constant_time_size<>, \c size_type<> and
+//! \c compare<>.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class set_impl
{
/// @cond
- typedef rbtree<ValueTraits, Compare, ConstantTimeSize, SizeType> tree_type;
-
+ typedef rbtree_impl<Config> tree_type;
//! This class is
//! non-copyable
- set (const set&);
+ set_impl (const set_impl&);
//! This class is
//! non-assignable
- set &operator =(const set&);
+ set_impl &operator =(const set_impl&);
typedef tree_type implementation_defined;
/// @endcond
public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef value_type key_type;
- typedef Compare value_compare;
- typedef value_compare key_compare;
+ typedef typename implementation_defined::value_type value_type;
+ typedef typename implementation_defined::value_traits value_traits;
+ typedef typename implementation_defined::pointer pointer;
+ typedef typename implementation_defined::const_pointer const_pointer;
+ typedef typename implementation_defined::reference reference;
+ typedef typename implementation_defined::const_reference const_reference;
+ typedef typename implementation_defined::difference_type difference_type;
+ typedef typename implementation_defined::size_type size_type;
+ typedef typename implementation_defined::value_compare value_compare;
+ typedef typename implementation_defined::key_compare key_compare;
typedef typename implementation_defined::iterator iterator;
typedef typename implementation_defined::const_iterator const_iterator;
typedef typename implementation_defined::reverse_iterator reverse_iterator;
typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator;
typedef typename implementation_defined::insert_commit_data insert_commit_data;
+ typedef typename implementation_defined::node_traits node_traits;
+ typedef typename implementation_defined::node node;
+ typedef typename implementation_defined::node_ptr node_ptr;
+ typedef typename implementation_defined::const_node_ptr const_node_ptr;
+ typedef typename implementation_defined::node_algorithms node_algorithms;
/// @cond
private:
tree_type tree_;
-
- template <class V1, class P1, bool C1, class S1>
- friend bool operator==(const set<V1, P1, C1, S1>& x, const set<V1, P1, C1, S1>& y);
-
- template <class V1, class P1, bool C1, class S1>
- friend bool operator<(const set<V1, P1, C1, S1>& x, const set<V1, P1, C1, S1>& y);
/// @endcond
public:
@@ -90,9 +86,10 @@
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
- //! or the copy constructor of the Compare object throws.
- set(const Compare &cmp = Compare())
- : tree_(cmp)
+ //! or the copy constructor of the value_compare object throws.
+ set_impl( const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : tree_(cmp, v_traits)
{}
//! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type.
@@ -106,10 +103,12 @@
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
- //! or the copy constructor/operator() of the Compare object throws.
+ //! or the copy constructor/operator() of the value_compare object throws.
template<class Iterator>
- set(Iterator b, Iterator e, const Compare &cmp = Compare())
- : tree_(true, b, e, cmp)
+ set_impl( Iterator b, Iterator e
+ , const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : tree_(true, b, e, cmp, v_traits)
{ insert(b, e); }
//! <b>Effects</b>: Detaches all elements from this. The objects in the set
@@ -119,7 +118,7 @@
//! value. Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
- ~set()
+ ~set_impl()
{}
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the set.
@@ -232,11 +231,11 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static set &container_from_end_iterator(iterator end_iterator)
+ static set_impl &container_from_end_iterator(iterator end_iterator)
{
- return *detail::parent_from_member<set, tree_type>
+ return *detail::parent_from_member<set_impl, tree_type>
( &tree_type::container_from_end_iterator(end_iterator)
- , &set::tree_);
+ , &set_impl::tree_);
}
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator
@@ -247,11 +246,11 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static const set &container_from_end_iterator(const_iterator end_iterator)
+ static const set_impl &container_from_end_iterator(const_iterator end_iterator)
{
- return *detail::parent_from_member<set, tree_type>
+ return *detail::parent_from_member<set_impl, tree_type>
( &tree_type::container_from_end_iterator(end_iterator)
- , &set::tree_);
+ , &set_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the set.
@@ -281,7 +280,7 @@
//! <b>Effects</b>: Returns the number of elements stored in the set.
//!
//! <b>Complexity</b>: Linear to elements contained in *this if,
- //! ConstantTimeSize is false. Constant-time otherwise.
+ //! constant-time size option is enabled. Constant-time otherwise.
//!
//! <b>Throws</b>: Nothing.
size_type size() const
@@ -293,7 +292,7 @@
//!
//! <b>Throws</b>: If the swap() call for the comparison functor
//! found using ADL throws. Strong guarantee.
- void swap(set& other)
+ void swap(set_impl& other)
{ tree_.swap(other.tree_); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
@@ -310,7 +309,7 @@
//!
//! <b>Throws</b>: If cloner throws.
template <class Cloner, class Disposer>
- void clone_from(const set &src, Cloner cloner, Disposer disposer)
+ void clone_from(const set_impl &src, Cloner cloner, Disposer disposer)
{ tree_.clone_from(src.tree_, cloner, disposer); }
//! <b>Requires</b>: value must be an lvalue
@@ -326,7 +325,7 @@
//! <b>Complexity</b>: Average complexity for insert element is at
//! most logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Strong guarantee.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
//! No copy-constructors are called.
@@ -344,7 +343,7 @@
//! <b>Complexity</b>: Logarithmic in general, but it's amortized
//! constant time if t is inserted immediately before hint.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Strong guarantee.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
//! No copy-constructors are called.
@@ -449,11 +448,11 @@
//!
//! <b>Effects</b>: Inserts a range into the set.
//!
- //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
- //! size of the range. However, it is linear in N if the range is already sorted
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
+ //! size of the range. However, it is linear in N if the range is already sorted
//! by value_comp().
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Basic guarantee.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
//! No copy-constructors are called.
@@ -494,7 +493,7 @@
//!
//! <b>Complexity</b>: O(log(size()) + this->count(value)).
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
@@ -556,7 +555,7 @@
//! <b>Effects</b>: Erases all the elements with the given value.
//! Disposer::operator()(pointer) is called for the removed elements.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
//!
//! <b>Complexity</b>: O(log(size() + this->count(value)). Basic guarantee.
//!
@@ -618,7 +617,7 @@
//! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal
//! to number of objects with the given key.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
size_type count(const_reference value) const
{ return tree_.find(value) != end(); }
@@ -638,7 +637,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
iterator lower_bound(const_reference value)
{ return tree_.lower_bound(value); }
@@ -666,7 +665,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
const_iterator lower_bound(const_reference value) const
{ return tree_.lower_bound(value); }
@@ -694,7 +693,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
iterator upper_bound(const_reference value)
{ return tree_.upper_bound(value); }
@@ -722,7 +721,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
const_iterator upper_bound(const_reference value) const
{ return tree_.upper_bound(value); }
@@ -750,7 +749,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
iterator find(const_reference value)
{ return tree_.find(value); }
@@ -778,7 +777,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
const_iterator find(const_reference value) const
{ return tree_.find(value); }
@@ -807,7 +806,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
std::pair<iterator,iterator> equal_range(const_reference value)
{ return tree_.equal_range(value); }
@@ -837,7 +836,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
std::pair<const_iterator, const_iterator>
equal_range(const_reference value) const
{ return tree_.equal_range(value); }
@@ -872,8 +871,11 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static iterator iterator_to(reference value)
- { return tree_type::iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static iterator s_iterator_to(reference value)
+ { return tree_type::s_iterator_to(value); }
//! <b>Requires</b>: value must be an lvalue and shall be in a set of
//! appropriate type. Otherwise the behavior is undefined.
@@ -884,91 +886,245 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static const_iterator iterator_to(const_reference value)
- { return tree_type::iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_iterator s_iterator_to(const_reference value)
+ { return tree_type::s_iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the set
+ //! that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ iterator iterator_to(reference value)
+ { return tree_.iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the
+ //! set that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ const_iterator iterator_to(const_reference value) const
+ { return tree_.iterator_to(value); }
+
+ //! <b>Requires</b>: value shall not be in a set/multiset.
+ //!
+ //! <b>Effects</b>: init_node puts the hook of a value in a well-known default
+ //! state.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant time.
+ //!
+ //! <b>Note</b>: This function puts the hook in the well-known default state
+ //! used by auto_unlink and safe hooks.
+ static void init_node(reference value)
+ { tree_type::init_node(value); }
+
+ //! <b>Requires</b>: replace_this must be a valid iterator of *this
+ //! and with_this must not be inserted in any tree.
+ //!
+ //! <b>Effects</b>: Replaces replace_this in its position in the
+ //! tree with with_this. The tree does not need to be rebalanced.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Note</b>: This function will break container ordering invariants if
+ //! with_this is not equivalent to *replace_this according to the
+ //! ordering rules. This function is faster than erasing and inserting
+ //! the node, since no rebalancing or comparison is needed.
+ void replace_node(iterator replace_this, reference with_this)
+ { tree_.replace_node(replace_this, with_this); }
/// @cond
- friend bool operator==(const set &x, const set &y)
+ friend bool operator==(const set_impl &x, const set_impl &y)
{ return x.tree_ == y.tree_; }
- friend bool operator<(const set &x, const set &y)
+ friend bool operator<(const set_impl &x, const set_impl &y)
{ return x.tree_ < y.tree_; }
/// @endcond
};
-template <class V, class P, bool C, class S>
-inline bool operator!=(const set<V, P, C, S>& x, const set<V, P, C, S>& y)
-{ return !(x==y); }
-
-template <class V, class P, bool C, class S>
-inline bool operator>(const set<V, P, C, S>& x, const set<V, P, C, S>& y)
-{ return y < x; }
-
-template <class V, class P, bool C, class S>
-inline bool operator<=(const set<V, P, C, S>& x, const set<V, P, C, S>& y)
-{ return !(y > x); }
-
-template <class V, class P, bool C, class S>
-inline bool operator>=(const set<V, P, C, S>& x, const set<V, P, C, S>& y)
-{ return !(x < y); }
-
-template <class V, class P, bool C, class S>
-inline void swap(set<V, P, C, S>& x, set<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator!=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const set_impl<T, Options...> &x, const set_impl<T, Options...> &y)
+#else
+(const set_impl<Config> &x, const set_impl<Config> &y)
+#endif
+{ return !(x == y); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const set_impl<T, Options...> &x, const set_impl<T, Options...> &y)
+#else
+(const set_impl<Config> &x, const set_impl<Config> &y)
+#endif
+{ return y < x; }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const set_impl<T, Options...> &x, const set_impl<T, Options...> &y)
+#else
+(const set_impl<Config> &x, const set_impl<Config> &y)
+#endif
+{ return !(y < x); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const set_impl<T, Options...> &x, const set_impl<T, Options...> &y)
+#else
+(const set_impl<Config> &x, const set_impl<Config> &y)
+#endif
+{ return !(x < y); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline void swap
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(set_impl<T, Options...> &x, set_impl<T, Options...> &y)
+#else
+(set_impl<Config> &x, set_impl<Config> &y)
+#endif
{ x.swap(y); }
+//! Helper metafunction to define a \c set that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none>
+#endif
+struct make_set
+{
+ /// @cond
+ typedef set_impl
+ < typename make_rbtree_opt<T, O1, O2, O3, O4>::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 set
+ : public make_set<T, O1, O2, O3, O4>::type
+{
+ typedef typename make_set
+ <T, O1, O2, O3, O4>::type Base;
+
+ public:
+ typedef typename Base::value_compare value_compare;
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+
+ //Assert if passed value traits are compatible with the type
+ BOOST_STATIC_ASSERT((detail::is_same<typename value_traits::value_type, T>::value));
+
+ set( const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : Base(cmp, v_traits)
+ {}
+
+ template<class Iterator>
+ set( Iterator b, Iterator e
+ , const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : Base(b, e, cmp, v_traits)
+ {}
+
+ static set &container_from_end_iterator(iterator end_iterator)
+ { return static_cast<set &>(Base::container_from_end_iterator(end_iterator)); }
+
+ static const set &container_from_end_iterator(const_iterator end_iterator)
+ { return static_cast<const set &>(Base::container_from_end_iterator(end_iterator)); }
+};
+
+#endif
+
//! The class template multiset is an intrusive container, that mimics most of
//! the interface of std::multiset as described in the C++ standard.
//!
-//! The template parameter ValueTraits is called "value traits". It stores
-//! information and operations about the type to be stored
-//! in list and what type of hook has been chosen to include it in the list.
-//! The value_traits class is supplied by the appropriate hook as a template subtype
-//! called "value_traits".
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
//!
-//! The template parameter Compare, provides a function object that can compare two
-//! element values as sort keys to determine their relative order in the set.
-//!
-//! If the user specifies ConstantTimeSize as "true", a member of type SizeType
-//! will be embedded in the class, that will keep track of the number of stored objects.
-//! This will allow constant-time O(1) size() member, instead of default O(N) size.
-template < class ValueTraits
- , class Compare //= std::less<typename ValueTraits::value_type>
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class multiset
+//! The container supports the following options:
+//! \c base_hook<>/member_hook<>/value_traits<>,
+//! \c constant_time_size<>, \c size_type<> and
+//! \c compare<>.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class multiset_impl
{
/// @cond
- typedef rbtree<ValueTraits, Compare, ConstantTimeSize, SizeType> tree_type;
-
- //! This class is
- //! non-copyable
- multiset (const multiset&);
-
- //! This class is
- //! non-asignable
- multiset &operator =(const multiset&);
+ typedef rbtree_impl<Config> tree_type;
+ //Non-copyable and non-assignable
+ multiset_impl (const multiset_impl&);
+ multiset_impl &operator =(const multiset_impl&);
typedef tree_type implementation_defined;
/// @endcond
public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef value_type key_type;
- typedef Compare value_compare;
- typedef value_compare key_compare;
+ typedef typename implementation_defined::value_type value_type;
+ typedef typename implementation_defined::value_traits value_traits;
+ typedef typename implementation_defined::pointer pointer;
+ typedef typename implementation_defined::const_pointer const_pointer;
+ typedef typename implementation_defined::reference reference;
+ typedef typename implementation_defined::const_reference const_reference;
+ typedef typename implementation_defined::difference_type difference_type;
+ typedef typename implementation_defined::size_type size_type;
+ typedef typename implementation_defined::value_compare value_compare;
+ typedef typename implementation_defined::key_compare key_compare;
typedef typename implementation_defined::iterator iterator;
typedef typename implementation_defined::const_iterator const_iterator;
typedef typename implementation_defined::reverse_iterator reverse_iterator;
typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator;
typedef typename implementation_defined::insert_commit_data insert_commit_data;
+ typedef typename implementation_defined::node_traits node_traits;
+ typedef typename implementation_defined::node node;
+ typedef typename implementation_defined::node_ptr node_ptr;
+ typedef typename implementation_defined::const_node_ptr const_node_ptr;
+ typedef typename implementation_defined::node_algorithms node_algorithms;
/// @cond
private:
@@ -982,9 +1138,10 @@
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
- //! or the copy constructor/operator() of the Compare object throws.
- multiset(const Compare &cmp = Compare())
- : tree_(cmp)
+ //! or the copy constructor/operator() of the value_compare object throws.
+ multiset_impl( const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : tree_(cmp, v_traits)
{}
//! <b>Requires</b>: Dereferencing iterator must yield an lvalue of type value_type.
@@ -993,15 +1150,17 @@
//! <b>Effects</b>: Constructs an empty multiset and inserts elements from
//! [b, e).
//!
- //! <b>Complexity</b>: Linear in N if [b, e) is already sorted using
+ //! <b>Complexity</b>: Linear in N if [b, e) is already sorted using
//! comp and otherwise N * log N, where N is last first.
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
- //! or the copy constructor/operator() of the Compare object throws.
+ //! or the copy constructor/operator() of the value_compare object throws.
template<class Iterator>
- multiset(Iterator b, Iterator e, const Compare &cmp = Compare())
- : tree_(false, b, e, cmp)
+ multiset_impl( Iterator b, Iterator e
+ , const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : tree_(false, b, e, cmp, v_traits)
{}
//! <b>Effects</b>: Detaches all elements from this. The objects in the set
@@ -1011,7 +1170,7 @@
//! auto-unlink value. Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
- ~multiset()
+ ~multiset_impl()
{}
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the multiset.
@@ -1124,11 +1283,11 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static multiset &container_from_end_iterator(iterator end_iterator)
+ static multiset_impl &container_from_end_iterator(iterator end_iterator)
{
- return *detail::parent_from_member<multiset, tree_type>
+ return *detail::parent_from_member<multiset_impl, tree_type>
( &tree_type::container_from_end_iterator(end_iterator)
- , &multiset::tree_);
+ , &multiset_impl::tree_);
}
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator
@@ -1139,11 +1298,11 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static const multiset &container_from_end_iterator(const_iterator end_iterator)
+ static const multiset_impl &container_from_end_iterator(const_iterator end_iterator)
{
- return *detail::parent_from_member<multiset, tree_type>
+ return *detail::parent_from_member<multiset_impl, tree_type>
( &tree_type::container_from_end_iterator(end_iterator)
- , &multiset::tree_);
+ , &multiset_impl::tree_);
}
//! <b>Effects</b>: Returns the key_compare object used by the multiset.
@@ -1173,7 +1332,7 @@
//! <b>Effects</b>: Returns the number of elements stored in the multiset.
//!
//! <b>Complexity</b>: Linear to elements contained in *this if,
- //! ConstantTimeSize is false. Constant-time otherwise.
+ //! constant-time size option is enabled. Constant-time otherwise.
//!
//! <b>Throws</b>: Nothing.
size_type size() const
@@ -1185,7 +1344,7 @@
//!
//! <b>Throws</b>: If the swap() call for the comparison functor
//! found using ADL throws. Strong guarantee.
- void swap(multiset& other)
+ void swap(multiset_impl& other)
{ tree_.swap(other.tree_); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
@@ -1202,7 +1361,7 @@
//!
//! <b>Throws</b>: If cloner throws. Basic guarantee.
template <class Cloner, class Disposer>
- void clone_from(const multiset &src, Cloner cloner, Disposer disposer)
+ void clone_from(const multiset_impl &src, Cloner cloner, Disposer disposer)
{ tree_.clone_from(src.tree_, cloner, disposer); }
//! <b>Requires</b>: value must be an lvalue
@@ -1215,7 +1374,7 @@
//! <b>Complexity</b>: Average complexity for insert element is at
//! most logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Strong guarantee.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
//! No copy-constructors are called.
@@ -1233,7 +1392,7 @@
//! <b>Complexity</b>: Logarithmic in general, but it is amortized
//! constant time if t is inserted immediately before hint.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Strong guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Strong guarantee.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
//! No copy-constructors are called.
@@ -1248,11 +1407,11 @@
//! <b>Returns</b>: An iterator that points to the position where the new
//! element was inserted.
//!
- //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
- //! size of the range. However, it is linear in N if the range is already sorted
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
+ //! size of the range. However, it is linear in N if the range is already sorted
//! by value_comp().
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Basic guarantee.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
//! No copy-constructors are called.
@@ -1293,7 +1452,7 @@
//!
//! <b>Complexity</b>: O(log(size() + this->count(value)).
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
@@ -1359,7 +1518,7 @@
//!
//! <b>Complexity</b>: O(log(size() + this->count(value)).
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws. Basic guarantee.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
@@ -1417,7 +1576,7 @@
//! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal
//! to number of objects with the given key.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
size_type count(const_reference value) const
{ return tree_.count(value); }
@@ -1437,7 +1596,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
iterator lower_bound(const_reference value)
{ return tree_.lower_bound(value); }
@@ -1465,7 +1624,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
const_iterator lower_bound(const_reference value) const
{ return tree_.lower_bound(value); }
@@ -1493,7 +1652,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
iterator upper_bound(const_reference value)
{ return tree_.upper_bound(value); }
@@ -1521,7 +1680,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
const_iterator upper_bound(const_reference value) const
{ return tree_.upper_bound(value); }
@@ -1549,7 +1708,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
iterator find(const_reference value)
{ return tree_.find(value); }
@@ -1577,7 +1736,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
const_iterator find(const_reference value) const
{ return tree_.find(value); }
@@ -1606,7 +1765,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
std::pair<iterator,iterator> equal_range(const_reference value)
{ return tree_.equal_range(value); }
@@ -1636,7 +1795,7 @@
//!
//! <b>Complexity</b>: Logarithmic.
//!
- //! <b>Throws</b>: If the internal Compare ordering function throws.
+ //! <b>Throws</b>: If the internal value_compare ordering function throws.
std::pair<const_iterator, const_iterator>
equal_range(const_reference value) const
{ return tree_.equal_range(value); }
@@ -1671,8 +1830,11 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static iterator iterator_to(reference value)
- { return tree_type::iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static iterator s_iterator_to(reference value)
+ { return tree_type::s_iterator_to(value); }
//! <b>Requires</b>: value must be an lvalue and shall be in a set of
//! appropriate type. Otherwise the behavior is undefined.
@@ -1683,38 +1845,197 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static const_iterator iterator_to(const_reference value)
- { return tree_type::iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_iterator s_iterator_to(const_reference value)
+ { return tree_type::s_iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid iterator i belonging to the set
+ //! that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ iterator iterator_to(reference value)
+ { return tree_.iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid const_iterator i belonging to the
+ //! set that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ const_iterator iterator_to(const_reference value) const
+ { return tree_.iterator_to(value); }
+
+ //! <b>Requires</b>: value shall not be in a set/multiset.
+ //!
+ //! <b>Effects</b>: init_node puts the hook of a value in a well-known default
+ //! state.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant time.
+ //!
+ //! <b>Note</b>: This function puts the hook in the well-known default state
+ //! used by auto_unlink and safe hooks.
+ static void init_node(reference value)
+ { tree_type::init_node(value); }
+
+ //! <b>Requires</b>: replace_this must be a valid iterator of *this
+ //! and with_this must not be inserted in any tree.
+ //!
+ //! <b>Effects</b>: Replaces replace_this in its position in the
+ //! tree with with_this. The tree does not need to be rebalanced.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Note</b>: This function will break container ordering invariants if
+ //! with_this is not equivalent to *replace_this according to the
+ //! ordering rules. This function is faster than erasing and inserting
+ //! the node, since no rebalancing or comparison is needed.
+ void replace_node(iterator replace_this, reference with_this)
+ { tree_.replace_node(replace_this, with_this); }
/// @cond
- friend bool operator==(const multiset &x, const multiset &y)
+ friend bool operator==(const multiset_impl &x, const multiset_impl &y)
{ return x.tree_ == y.tree_; }
- friend bool operator<(const multiset &x, const multiset &y)
+ friend bool operator<(const multiset_impl &x, const multiset_impl &y)
{ return x.tree_ < y.tree_; }
/// @endcond
};
-template <class V, class P, bool C, class S>
-inline bool operator!=(const multiset<V, P, C, S>& x, const multiset<V, P, C, S>& y)
-{ return !(x==y); }
-
-template <class V, class P, bool C, class S>
-inline bool operator>(const multiset<V, P, C, S>& x, const multiset<V, P, C, S>& y)
-{ return y < x; }
-
-template <class V, class P, bool C, class S>
-inline bool operator<=(const multiset<V, P, C, S>& x, const multiset<V, P, C, S>& y)
-{ return !(y > x); }
-
-template <class V, class P, bool C, class S>
-inline bool operator>=(const multiset<V, P, C, S>& x, const multiset<V, P, C, S>& y)
-{ return !(x < y); }
-
-template <class V, class P, bool C, class S>
-inline void swap(multiset<V, P, C, S>& x, multiset<V, P, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator!=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const multiset_impl<T, Options...> &x, const multiset_impl<T, Options...> &y)
+#else
+(const multiset_impl<Config> &x, const multiset_impl<Config> &y)
+#endif
+{ return !(x == y); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const multiset_impl<T, Options...> &x, const multiset_impl<T, Options...> &y)
+#else
+(const multiset_impl<Config> &x, const multiset_impl<Config> &y)
+#endif
+{ return y < x; }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const multiset_impl<T, Options...> &x, const multiset_impl<T, Options...> &y)
+#else
+(const multiset_impl<Config> &x, const multiset_impl<Config> &y)
+#endif
+{ return !(y < x); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const multiset_impl<T, Options...> &x, const multiset_impl<T, Options...> &y)
+#else
+(const multiset_impl<Config> &x, const multiset_impl<Config> &y)
+#endif
+{ return !(x < y); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline void swap
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(multiset_impl<T, Options...> &x, multiset_impl<T, Options...> &y)
+#else
+(multiset_impl<Config> &x, multiset_impl<Config> &y)
+#endif
{ x.swap(y); }
+//! Helper metafunction to define a \c multiset that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none>
+#endif
+struct make_multiset
+{
+ /// @cond
+ typedef multiset_impl
+ < typename make_rbtree_opt<T, O1, O2, O3, O4>::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 multiset
+ : public make_multiset<T, O1, O2, O3, O4>::type
+{
+ typedef typename make_multiset
+ <T, O1, O2, O3, O4>::type Base;
+
+ public:
+ typedef typename Base::value_compare value_compare;
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+
+ //Assert if passed value traits are compatible with the type
+ BOOST_STATIC_ASSERT((detail::is_same<typename value_traits::value_type, T>::value));
+
+ multiset( const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : Base(cmp, v_traits)
+ {}
+
+ template<class Iterator>
+ multiset( Iterator b, Iterator e
+ , const value_compare &cmp = value_compare()
+ , const value_traits &v_traits = value_traits())
+ : Base(b, e, cmp, v_traits)
+ {}
+
+ static multiset &container_from_end_iterator(iterator end_iterator)
+ { return static_cast<multiset &>(Base::container_from_end_iterator(end_iterator)); }
+
+ static const multiset &container_from_end_iterator(const_iterator end_iterator)
+ { return static_cast<const multiset &>(Base::container_from_end_iterator(end_iterator)); }
+};
+
+#endif
+
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/set_hook.hpp
==============================================================================
--- trunk/boost/intrusive/set_hook.hpp (original)
+++ trunk/boost/intrusive/set_hook.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -17,16 +17,45 @@
#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/detail/rbtree_node.hpp>
#include <boost/intrusive/rbtree_algorithms.hpp>
-#include <boost/intrusive/linking_policy.hpp>
-#include <boost/intrusive/tag.hpp>
-#include <boost/static_assert.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/detail/generic_hook.hpp>
namespace boost {
namespace intrusive {
+/// @cond
+template<class VoidPointer>
+struct get_set_node_algo
+{
+ typedef rbtree_algorithms<rbtree_node_traits<VoidPointer> > type;
+};
+/// @endcond
+
+//! Helper metafunction to define a \c set_base_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_set_base_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
+
+ typedef detail::generic_hook
+ < get_set_node_algo<typename packed_options::void_pointer>
+ , typename packed_options::tag
+ , packed_options::link_mode
+ , detail::SetBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
//! Derive a class from set_base_hook in order to store objects in
//! in an set/multiset. set_base_hook holds the data necessary to maintain
//! the set/multiset and provides an appropriate value_traits class for set/multiset.
@@ -40,160 +69,102 @@
//!
//! The third argument is the pointer type that will be used internally in the hook
//! and the set/multiset configured from this hook.
-template< class Tag //= tag
- , linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
class set_base_hook
- : private detail::rbtree_node_traits<VoidPointer>::node
+ : public make_set_base_hook<O1, O2, O3>::type
{
- public:
- typedef detail::rbtree_node_traits<VoidPointer> node_traits;
- enum { linking_policy = Policy };
-
- /// @cond
- private:
- typedef rbtree_algorithms<node_traits> node_algorithms;
- /// @endcond
-
- public:
- typedef typename node_traits::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;
- typedef set_base_hook
- <Tag, Policy, VoidPointer> this_type;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type>::type this_type_ptr;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type>::type const_this_type_ptr;
-
- /// @cond
- private:
-
- node_ptr this_as_node()
- { return node_ptr(static_cast<node *const>(this)); }
-
- const_node_ptr this_as_node() const
- { return const_node_ptr(static_cast<const node *const>(this)); }
- /// @endcond
-
- public:
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
- //! <b>Throws</b>: Nothing.
- set_base_hook()
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ //! <b>Throws</b>: Nothing.
+ set_base_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using set_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- set_base_hook(const set_base_hook& )
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ set_base_hook(const set_base_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using set_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- set_base_hook& operator=(const set_base_hook& )
- { return *this; }
+ set_base_hook& operator=(const set_base_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
- //!
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an set an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
+ //!
+ //! <b>Throws</b>: Nothing.
+ ~set_base_hook();
+
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
+ //! related to those nodes in one or two containers. That is, if the node
+ //! this is part of the element e1, the node x is part of the element e2
+ //! and both elements are included in the containers s1 and s2, then after
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
+ //! at the position of e1. If one element is not in a container, then
+ //! after the swap-operation the other element is not in a container.
+ //! Iterators to e1 and e2 related to those nodes are invalidated.
+ //!
+ //! <b>Complexity</b>: Constant
+ //!
//! <b>Throws</b>: Nothing.
- ~set_base_hook()
- { detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
+ void swap_nodes(set_base_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
- //! otherwise. This function can be used to test whether set::iterator_to
+ //! otherwise. This function can be used to test whether \c set::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
- bool is_linked() const
- {
- //is_linked() can be only used in safe-mode or auto-unlink
- BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
- return !node_algorithms::unique(this_as_node());
- }
+ bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
- //! This function is only allowed if Policy is auto_unlink.
+ //! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
- void unlink()
- {
- BOOST_STATIC_ASSERT((Policy == auto_unlink));
- node_algorithms::unlink_and_rebalance(this_as_node());
- node_algorithms::init(this_as_node());
- }
-
- //! The value_traits class is used as the first template argument for multiset.
- //! The template argument T defines the class type stored in multiset. Objects
- //! of type T and of types derived from T can be stored. T don't need to be
- //! copy-constructible or assignable.
- template<class T>
- struct value_traits
- : detail::derivation_hook_value_traits<T, this_type, Tag>
- {};
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr(static_cast<set_base_hook*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr(static_cast<const set_base_hook*> (detail::get_pointer(p)));
- }
+ void unlink();
+ #endif
+};
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return this_as_node(); }
+//! Helper metafunction to define a \c set_member_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_set_member_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return this_as_node(); }
+ typedef detail::generic_hook
+ < get_set_node_algo<typename packed_options::void_pointer>
+ , member_tag
+ , packed_options::link_mode
+ , detail::NoBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
};
//! Put a public data member set_member_hook in order to store objects of this class in
@@ -204,152 +175,79 @@
//!
//! The second argument is the pointer type that will be used internally in the hook
//! and the set/multiset configured from this hook.
-template< linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
class set_member_hook
- : private detail::rbtree_node_traits<VoidPointer>::node
+ : public make_set_member_hook<O1, O2, O3>::type
{
- public:
- typedef detail::rbtree_node_traits<VoidPointer> node_traits;
- enum { linking_policy = Policy };
-
- /// @cond
- private:
- typedef rbtree_algorithms<node_traits> node_algorithms;
- /// @endcond
-
- public:
- typedef typename node_traits::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;
- typedef set_member_hook
- <Policy, VoidPointer> this_type;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type >::type this_type_ptr;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type >::type const_this_type_ptr;
-
- /// @cond
- private:
- node_ptr this_as_node()
- { return node_ptr(static_cast<node *const>(this)); }
-
- const_node_ptr this_as_node() const
- { return const_node_ptr(static_cast<const node *const>(this)); }
- /// @endcond
-
- public:
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
- set_member_hook()
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ set_member_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using set_member_hook STL-compliant without forcing the
- //! user to do some additional work.
- set_member_hook(const set_member_hook& )
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
+ //! move-semantics.
+ set_member_hook(const set_member_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using set_member_hook STL-compliant without forcing the
- //! user to do some additional work.
- set_member_hook& operator=(const set_member_hook& )
- { return *this; }
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
+ //! move-semantics.
+ set_member_hook& operator=(const set_member_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
- //!
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an set an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
+ //!
+ //! <b>Throws</b>: Nothing.
+ ~set_member_hook();
+
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
+ //! related to those nodes in one or two containers. That is, if the node
+ //! this is part of the element e1, the node x is part of the element e2
+ //! and both elements are included in the containers s1 and s2, then after
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
+ //! at the position of e1. If one element is not in a container, then
+ //! after the swap-operation the other element is not in a container.
+ //! Iterators to e1 and e2 related to those nodes are invalidated.
+ //!
+ //! <b>Complexity</b>: Constant
+ //!
//! <b>Throws</b>: Nothing.
- ~set_member_hook()
- { detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
+ void swap_nodes(set_member_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
- //! <b>Complexity</b>: Constant
- bool is_linked() const
- {
- //is_linked() can be only used in safe-mode or auto-unlink
- BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
- return !node_algorithms::unique(this_as_node());
- }
+ //! <b>Returns</b>: true, if the node belongs to a container, false
+ //! otherwise. This function can be used to test whether \c set::iterator_to
+ //! will return a valid iterator.
+ //!
+ //! <b>Complexity</b>: Constant
+ bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
- //! This function is only allowed if Policy is auto_unlink.
- //!
- //! <b>Throws</b>: Nothing.
- void unlink()
- {
- BOOST_STATIC_ASSERT((Policy == auto_unlink));
- node_algorithms::unlink_and_rebalance(this_as_node());
- node_algorithms::init(this_as_node());
- }
-
- //! The value_traits class is used as the first template argument for multiset.
- //! The template argument is a pointer to member pointing to the node in
- //! the class. Objects of type T and of types derived from T can be stored.
- //! T don't need to be copy-constructible or assignable.
- template<class T, this_type T::* P>
- struct value_traits
- : detail::member_hook_value_traits<T, this_type, P>
- {};
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr(static_cast<this_type*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr(static_cast<const this_type*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return this_as_node(); }
-
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
+ //! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return this_as_node(); }
+ void unlink();
+ #endif
};
} //namespace intrusive
Modified: trunk/boost/intrusive/slist.hpp
==============================================================================
--- trunk/boost/intrusive/slist.hpp (original)
+++ trunk/boost/intrusive/slist.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -16,21 +16,60 @@
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/static_assert.hpp>
-#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
-#include <boost/detail/no_exceptions_support.hpp>
-#endif
+#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>
#include <boost/intrusive/circular_slist_algorithms.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/link_mode.hpp>
+#include <boost/intrusive/options.hpp>
#include <functional>
#include <cstddef>
namespace boost {
namespace intrusive {
+/// @cond
+
+template <class T>
+struct internal_default_slist_hook
+{
+ template <class U> static detail::one test(...);
+ template <class U> static detail::two test(typename U::default_slist_hook* = 0);
+ static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
+};
+
+template <class T>
+struct get_default_slist_hook
+{ typedef typename T::default_slist_hook type; };
+
+template <class ValueTraits, class SizeType, bool ConstantTimeSize>
+struct slistopt
+{
+ typedef ValueTraits value_traits;
+ typedef SizeType size_type;
+ static const bool constant_time_size = ConstantTimeSize;
+};
+
+template <class T>
+struct slist_defaults
+ : pack_options
+ < none
+ , base_hook
+ < typename detail::eval_if_c
+ < internal_default_slist_hook<T>::value
+ , get_default_slist_hook<T>
+ , detail::identity<none>
+ >::type
+ >
+ , constant_time_size<true>
+ , size_type<std::size_t>
+ >::type
+{};
+
+/// @endcond
+
//! The class template slist is an intrusive container, that encapsulates
//! a singly-linked list. You can use such a list to squeeze the last bit
//! of performance from your application. Unfortunately, the little gains
@@ -39,12 +78,13 @@
//! this limitation some other member functions with rather unusual semantics
//! have to be introduced.
//!
-//! The template parameter ValueTraits is called "value traits". It stores
-//! information and operations about the type to be stored in the container.
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
//!
-//! If the user specifies ConstantTimeSize as "true", a member of type SizeType
-//! will be embedded in the class, that will keep track of the number of stored objects.
-//! This will allow constant-time O(1) size() member, instead of default O(N) size.
+//! The container supports the following options:
+//! \c base_hook<>/member_hook<>/value_traits<>,
+//! \c constant_time_size<> and \c size_type<>.
//!
//! The iterators of slist are forward iterators. slist provides a static
//! function called "previous" to compute the previous iterator of a given iterator.
@@ -53,92 +93,131 @@
//! are defined. In addition, whenever you have an end iterator, 'after this
//! iterator' means 'at the beginning of the list'. To improve the self-documentation
//! a "before_begin()" function is defined, returning the end() iterator.
-template < class ValueTraits
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class slist
- : private detail::size_holder<ConstantTimeSize, SizeType>
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class slist_impl
{
+ //Public typedefs
+ public:
+ typedef typename Config::value_traits value_traits;
/// @cond
- private:
- typename ValueTraits::node_traits::node root_;
+ static const bool external_value_traits =
+ detail::external_value_traits_is_true<value_traits>::value;
+ typedef typename detail::eval_if_c
+ < external_value_traits
+ , detail::eval_value_traits<value_traits>
+ , detail::identity<value_traits>
+ >::type real_value_traits;
+ /// @endcond
+ typedef typename real_value_traits::pointer pointer;
+ typedef typename real_value_traits::const_pointer const_pointer;
+ typedef typename std::iterator_traits<pointer>::value_type value_type;
+ typedef typename std::iterator_traits<pointer>::reference reference;
+ typedef typename std::iterator_traits<const_pointer>::reference const_reference;
+ typedef typename std::iterator_traits<pointer>::difference_type difference_type;
+ typedef typename Config::size_type size_type;
+ typedef slist_iterator<slist_impl, false> iterator;
+ typedef slist_iterator<slist_impl, true> const_iterator;
+ typedef typename real_value_traits::node_traits node_traits;
+ typedef typename node_traits::node node;
+ typedef typename boost::pointer_to_other
+ <pointer, node>::type node_ptr;
+ typedef typename boost::pointer_to_other
+ <pointer, const node>::type const_node_ptr;
+ typedef circular_slist_algorithms<node_traits> node_algorithms;
- typedef slist<ValueTraits, ConstantTimeSize, SizeType> this_type;
- typedef typename ValueTraits::node_traits node_traits;
- typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;
+ static const bool constant_time_size = Config::constant_time_size;
+ static const bool stateful_value_traits = detail::store_cont_ptr_on_it<slist_impl>::value;
+
+ /// @cond
+ private:
+ typedef detail::size_holder<constant_time_size, size_type> size_traits;
//! This class is
//! non-copyable
- slist (const slist&);
+ slist_impl (const slist_impl&);
//! This class is
//! non-asignable
- slist &operator =(const slist&);
- /// @endcond
+ slist_impl &operator =(const slist_impl&);
- //Public typedefs
- public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef detail::slist_iterator<value_type, ValueTraits> iterator;
- typedef detail::slist_iterator<const value_type, ValueTraits> const_iterator;
-
- /// @cond
- private:
- typedef typename node_traits::node node;
- typedef typename boost::pointer_to_other
- <pointer, node>::type node_ptr;
- typedef typename boost::pointer_to_other
- <pointer, const node>::type const_node_ptr;
- typedef circular_slist_algorithms<node_traits> node_algorithms;
enum { safemode_or_autounlink =
- (int)ValueTraits::linking_policy == (int)auto_unlink ||
- (int)ValueTraits::linking_policy == (int)safe_link };
+ (int)real_value_traits::link_mode == (int)auto_unlink ||
+ (int)real_value_traits::link_mode == (int)safe_link };
//Constant-time size is incompatible with auto-unlink hooks!
- BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));
+ BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink)));
node_ptr get_root_node()
- { return node_ptr(&root_); }
+ { return node_ptr(&data_.root_plus_size_.root_); }
const_node_ptr get_root_node() const
- { return const_node_ptr(&root_); }
+ { return const_node_ptr(&data_.root_plus_size_.root_); }
static node_ptr uncast(const_node_ptr ptr)
{
return node_ptr(const_cast<node*>(detail::get_pointer(ptr)));
}
- static iterator previous_node(iterator beg, iterator i)
+ struct root_plus_size
+ : public size_traits
{
- return iterator
- (node_algorithms::get_previous_node(beg.pointed_node(), i.pointed_node()));
- }
+ node root_;
+ };
- static const_iterator previous_node(const_iterator beg, const_iterator i)
+ struct data_t
+ : public slist_impl::value_traits
{
- return const_iterator
- (node_algorithms::get_previous_node(beg.pointed_node(), i.pointed_node()));
- }
+ typedef typename slist_impl::value_traits value_traits;
+ data_t(const value_traits &val_traits)
+ : value_traits(val_traits)
+ {}
+
+ root_plus_size root_plus_size_;
+ } data_;
+
+ size_traits &priv_size_traits()
+ { return data_.root_plus_size_; }
+
+ const size_traits &priv_size_traits() const
+ { return data_.root_plus_size_; }
+
+ const real_value_traits &get_real_value_traits(detail::bool_<false>) const
+ { return data_; }
+
+ const real_value_traits &get_real_value_traits(detail::bool_<true>) const
+ { return data_.get_value_traits(*this); }
+
+ real_value_traits &get_real_value_traits(detail::bool_<false>)
+ { return data_; }
+
+ real_value_traits &get_real_value_traits(detail::bool_<true>)
+ { return data_.get_value_traits(*this); }
+
/// @endcond
public:
+
+ const real_value_traits &get_real_value_traits() const
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
+ real_value_traits &get_real_value_traits()
+ { return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
+
+ public:
//! <b>Effects</b>: constructs an empty list.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks).
- slist()
+ slist_impl(const value_traits &v_traits = value_traits())
+ : data_(v_traits)
{
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
node_algorithms::init(this->get_root_node());
}
@@ -151,9 +230,10 @@
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks).
template<class Iterator>
- slist(Iterator b, Iterator e)
+ slist_impl(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
+ : data_(v_traits)
{
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
node_algorithms::init(this->get_root_node());
insert_after(before_begin(), b, e);
}
@@ -162,12 +242,12 @@
//! or auto-unlink value, the destructor does nothing
//! (ie. no code is generated). Otherwise it detaches all elements from this.
//! In this case the objects in the list are not deleted (i.e. no destructors
- //! are called), but the hooks according to the ValueTraits template parameter
+ //! are called), but the hooks according to the value_traits template parameter
//! are set to their default value.
//!
//! <b>Complexity</b>: Linear to the number of elements in the list, if
//! it's a safe-mode or auto-unlink value. Otherwise constant.
- ~slist()
+ ~slist_impl()
{ this->clear(); }
//! <b>Effects</b>: Erases all the elements of the container.
@@ -185,7 +265,7 @@
}
else{
node_algorithms::init(this->get_root_node());
- size_traits::set_size(size_type(0));
+ this->priv_size_traits().set_size(size_type(0));
}
}
@@ -215,11 +295,11 @@
//! <b>Note</b>: Does not affect the validity of iterators and references.
void push_front(reference value)
{
- node_ptr to_insert = ValueTraits::to_node_ptr(value);
+ node_ptr to_insert = get_real_value_traits().to_node_ptr(value);
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
node_algorithms::link_after(this->get_root_node(), to_insert);
- size_traits::increment();
+ this->priv_size_traits().increment();
}
//! <b>Effects</b>: Erases the first element of the list.
@@ -234,7 +314,7 @@
{
node_ptr to_erase = node_traits::get_next(this->get_root_node());
node_algorithms::unlink_after(this->get_root_node());
- size_traits::decrement();
+ this->priv_size_traits().decrement();
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
}
@@ -254,7 +334,7 @@
{
node_ptr to_erase = node_traits::get_next(this->get_root_node());
this->pop_front();
- disposer(ValueTraits::to_value_ptr(to_erase));
+ disposer(get_real_value_traits().to_value_ptr(to_erase));
}
//! <b>Effects</b>: Returns a reference to the first element of the list.
@@ -263,7 +343,7 @@
//!
//! <b>Complexity</b>: Constant.
reference front()
- { return *ValueTraits::to_value_ptr(node_traits::get_next(this->get_root_node())); }
+ { return *get_real_value_traits().to_value_ptr(node_traits::get_next(this->get_root_node())); }
//! <b>Effects</b>: Returns a const_reference to the first element of the list.
//!
@@ -271,7 +351,7 @@
//!
//! <b>Complexity</b>: Constant.
const_reference front() const
- { return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); }
+ { return *get_real_value_traits().to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); }
//! <b>Effects</b>: Returns an iterator to the first element contained in the list.
//!
@@ -279,7 +359,7 @@
//!
//! <b>Complexity</b>: Constant.
iterator begin()
- { return iterator (node_traits::get_next(this->get_root_node())); }
+ { return iterator (node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
//!
@@ -287,7 +367,7 @@
//!
//! <b>Complexity</b>: Constant.
const_iterator begin() const
- { return const_iterator (node_traits::get_next(this->get_root_node())); }
+ { return const_iterator (node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
//!
@@ -295,7 +375,7 @@
//!
//! <b>Complexity</b>: Constant.
const_iterator cbegin() const
- { return const_iterator (node_traits::get_next(this->get_root_node())); }
+ { return const_iterator (node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns an iterator to the end of the list.
//!
@@ -303,7 +383,7 @@
//!
//! <b>Complexity</b>: Constant.
iterator end()
- { return iterator (this->get_root_node()); }
+ { return iterator (this->get_root_node(), this); }
//! <b>Effects</b>: Returns a const_iterator to the end of the list.
//!
@@ -311,7 +391,7 @@
//!
//! <b>Complexity</b>: Constant.
const_iterator end() const
- { return const_iterator (uncast(this->get_root_node())); }
+ { return const_iterator (uncast(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the end of the list.
//!
@@ -319,7 +399,7 @@
//!
//! <b>Complexity</b>: Constant.
const_iterator cend() const
- { return const_iterator (uncast(this->get_root_node())); }
+ { return const_iterator (uncast(this->get_root_node()), this); }
//! <b>Effects</b>: Returns an iterator that points to a position
//! before the first element. Equivalent to "end()"
@@ -356,11 +436,8 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static slist &container_from_end_iterator(iterator end_iterator)
- {
- return *detail::parent_from_member<slist, node>
- ( detail::get_pointer(end_iterator.pointed_node()), &slist::root_);
- }
+ static slist_impl &container_from_end_iterator(iterator end_iterator)
+ { return priv_container_from_end_iterator(end_iterator); }
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator
//! of slist.
@@ -370,24 +447,21 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant.
- static const slist &container_from_end_iterator(const_iterator end_iterator)
- {
- return *detail::parent_from_member<slist, node>
- ( detail::get_pointer(end_iterator.pointed_node()), &slist::root_);
- }
+ static const slist_impl &container_from_end_iterator(const_iterator end_iterator)
+ { return priv_container_from_end_iterator(end_iterator); }
//! <b>Effects</b>: Returns the number of the elements contained in the list.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Linear to the number of elements contained in the list.
- //! if ConstantTimeSize is false. Constant time otherwise.
+ //! if constant_time_size is false. Constant time otherwise.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
size_type size() const
{
- if(ConstantTimeSize)
- return size_traits::get_size();
+ if(constant_time_size)
+ return this->priv_size_traits().get_size();
else
return node_algorithms::count(this->get_root_node()) - 1;
}
@@ -409,13 +483,13 @@
//! <b>Complexity</b>: Linear to the number of elements of both lists.
//!
//! <b>Note</b>: Does not affect the validity of iterators and references.
- void swap(slist& other)
+ void swap(slist_impl& other)
{
node_algorithms::swap_nodes(this->get_root_node(), other.get_root_node());
- if(ConstantTimeSize){
- size_type backup = size_traits::get_size();
- size_traits::set_size(other.get_size());
- other.set_size(backup);
+ if(constant_time_size){
+ size_type backup = this->priv_size_traits().get_size();
+ this->priv_size_traits().set_size(other.priv_size_traits().get_size());
+ other.priv_size_traits().set_size(backup);
}
}
@@ -533,25 +607,21 @@
//!
//! <b>Throws</b>: If cloner throws.
template <class Cloner, class Disposer>
- void clone_from(const slist &src, Cloner cloner, Disposer disposer)
+ void clone_from(const slist_impl &src, Cloner cloner, Disposer disposer)
{
this->clear_and_dispose(disposer);
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
- BOOST_TRY{
- #endif
+ 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));
}
- #ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
}
- BOOST_CATCH(...){
+ BOOST_INTRUSIVE_CATCH(...){
this->clear_and_dispose(disposer);
BOOST_RETHROW;
}
- BOOST_CATCH_END
- #endif
+ BOOST_INTRUSIVE_CATCH_END
}
//! <b>Requires</b>: value must be an lvalue and prev_p must point to an element
@@ -569,12 +639,12 @@
//! <b>Note</b>: Does not affect the validity of iterators and references.
iterator insert_after(iterator prev_p, reference value)
{
- node_ptr n = ValueTraits::to_node_ptr(value);
+ node_ptr n = get_real_value_traits().to_node_ptr(value);
if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n));
node_algorithms::link_after(prev_p.pointed_node(), n);
- size_traits::increment();
- return iterator (n);
+ this->priv_size_traits().increment();
+ return iterator (n, this);
}
//! <b>Requires</b>: Dereferencing iterator must yield
@@ -644,7 +714,7 @@
iterator it(prev); ++it;
node_ptr to_erase(it.pointed_node());
node_algorithms::unlink_after(prev.pointed_node());
- size_traits::decrement();
+ this->priv_size_traits().decrement();
iterator ret(++prev);
if(safemode_or_autounlink)
node_algorithms::init(to_erase);
@@ -725,7 +795,7 @@
iterator it(prev); ++it;
node_ptr to_erase(it.pointed_node());
iterator ret(this->erase_after(prev));
- disposer(ValueTraits::to_value_ptr(to_erase));
+ disposer(get_real_value_traits().to_value_ptr(to_erase));
return ret;
}
@@ -853,7 +923,7 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- iterator splice_after(iterator prev, slist &x)
+ iterator splice_after(iterator prev, slist_impl &x)
{
if (!x.empty()){
iterator last_x(x.previous(x.end()));
@@ -861,8 +931,8 @@
( prev.pointed_node()
, x.end().pointed_node()
, last_x.pointed_node());
- size_traits::set_size(size_traits::get_size() + x.get_size());
- x.set_size(size_type(0));
+ this->priv_size_traits().set_size(this->priv_size_traits().get_size() + x.priv_size_traits().get_size());
+ x.priv_size_traits().set_size(size_type(0));
return last_x;
}
else{
@@ -883,15 +953,15 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice_after(iterator prev, slist &x, iterator prev_ele)
+ void splice_after(iterator prev, slist_impl &x, iterator prev_ele)
{
iterator nxt = prev_ele;
++nxt;
if (nxt != prev && prev_ele != prev){
node_algorithms::transfer_after
(prev.pointed_node(), prev_ele.pointed_node(), nxt.pointed_node());
- size_traits::increment();
- x.decrement();
+ this->priv_size_traits().increment();
+ x.priv_size_traits().decrement();
}
}
@@ -906,19 +976,19 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Linear to the number of elements transferred
- //! if ConstantTimeSize is true. Constant-time otherwise.
+ //! if constant_time_size is true. Constant-time otherwise.
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice_after(iterator prev_pos, slist &x, iterator before_first, iterator before_last)
+ void splice_after(iterator prev_pos, slist_impl &x, iterator before_first, iterator before_last)
{
if (before_first != before_last){
- if(ConstantTimeSize){
+ if(constant_time_size){
size_type increment = std::distance(before_first, before_last);
node_algorithms::transfer_after
(prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node());
- size_traits::set_size(size_traits::get_size() + increment);
- x.set_size(x.get_size() - increment);
+ this->priv_size_traits().set_size(this->priv_size_traits().get_size() + increment);
+ x.priv_size_traits().set_size(x.priv_size_traits().get_size() - increment);
}
else{
node_algorithms::transfer_after
@@ -941,15 +1011,15 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice_after(iterator prev_pos, slist &x, iterator before_first, iterator before_last, difference_type n)
+ void splice_after(iterator prev_pos, slist_impl &x, iterator before_first, iterator before_last, difference_type n)
{
if(n){
- if(ConstantTimeSize){
+ if(constant_time_size){
BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(before_first, before_last) == n);
node_algorithms::transfer_after
(prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node());
- size_traits::set_size(size_traits::get_size() + n);
- x.set_size(x.get_size() - n);
+ this->priv_size_traits().set_size(this->priv_size_traits().get_size() + n);
+ x.priv_size_traits().set_size(x.priv_size_traits().get_size() - n);
}
else{
node_algorithms::transfer_after
@@ -975,7 +1045,7 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- iterator splice(iterator it, slist &x)
+ iterator splice(iterator it, slist_impl &x)
{ return splice_after(this->previous(it), x); }
//! <b>Requires</b>: it p must be a valid iterator of *this.
@@ -991,7 +1061,7 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice(iterator pos, slist &x, iterator elem)
+ void splice(iterator pos, slist_impl &x, iterator elem)
{ return splice_after(this->previous(pos), x, this->previous(elem)); }
//! <b>Requires</b>: pos must be a dereferenceable iterator in *this
@@ -1004,11 +1074,11 @@
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Linear to the sum of elements before pos, first, and last.
- //! Plus linear to the number of elements transferred if ConstantTimeSize is true.
+ //! Plus linear to the number of elements transferred if constant_time_size is true.
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice(iterator pos, slist &x, iterator first, iterator last)
+ void splice(iterator pos, slist_impl &x, iterator first, iterator last)
{ return splice_after(this->previous(pos), x, this->previous(first), this->previous(last)); }
//! <b>Requires</b>: pos must be a dereferenceable iterator in *this
@@ -1025,7 +1095,7 @@
//!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated.
- void splice(iterator pos, slist &x, iterator first, iterator last, difference_type n)
+ void splice(iterator pos, slist_impl &x, iterator first, iterator last, difference_type n)
{ return splice_after(this->previous(pos), x, this->previous(first), this->previous(last), n); }
//! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
@@ -1044,8 +1114,8 @@
{
if (node_traits::get_next(node_traits::get_next(this->get_root_node()))
!= this->get_root_node()) {
- slist carry;
- slist counter[64];
+ slist_impl carry;
+ slist_impl counter[64];
int fill = 0;
iterator last_inserted;
while(!this->empty()){
@@ -1057,8 +1127,10 @@
}
BOOST_INTRUSIVE_INVARIANT_ASSERT(counter[i].empty());
- iterator last_element(previous_node(last_inserted, carry.end()));
- if(ConstantTimeSize){
+ node_ptr p = node_algorithms::get_previous_node
+ (last_inserted.pointed_node(), carry.end().pointed_node());
+ iterator last_element(p, this);
+ if(constant_time_size){
counter[i].splice_after( counter[i].end(), carry
, carry.before_begin(), last_element
, carry.size());
@@ -1067,19 +1139,18 @@
counter[i].splice_after( counter[i].end(), carry
, carry.before_begin(), last_element);
}
- //counter[i].splice_after(counter[i].end(), carry, carry.end(), previous_node(last_inserted, carry.end()));
- //carry.swap(counter[i]);
if(i == fill)
++fill;
}
for (int i = 1; i < fill; ++i)
last_inserted = counter[i].merge(counter[i-1], p);
- //this->swap(counter[fill-1]);
BOOST_INTRUSIVE_INVARIANT_ASSERT(this->empty());
- iterator last_element(previous_node(last_inserted, counter[--fill].end()));
- if(ConstantTimeSize){
+ node_ptr p = node_algorithms::get_previous_node
+ (last_inserted.pointed_node(), counter[--fill].end().pointed_node());
+ iterator last_element(p, this);
+ if(constant_time_size){
this->splice_after( end(), counter[fill], counter[fill].before_begin()
, last_element, counter[fill].size());
}
@@ -1126,7 +1197,7 @@
//!
//! <b>Note</b>: Iterators and references are not invalidated.
template<class Predicate>
- iterator merge(slist& x, Predicate p)
+ iterator merge(slist_impl& x, Predicate p)
{
iterator a(before_begin()), e(end()), ax(x.before_begin());
iterator last_inserted(e);
@@ -1161,7 +1232,7 @@
//! size() + x.size() - 1 comparisons.
//!
//! <b>Note</b>: Iterators and references are not invalidated
- void merge(slist& x)
+ void merge(slist_impl& x)
{ this->merge(x, std::less<value_type>()); }
//! <b>Effects</b>: Reverses the order of elements in the list.
@@ -1328,10 +1399,46 @@
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
- static iterator iterator_to(reference value)
+ //! This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static iterator s_iterator_to(reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(value)));
+ return iterator (value_traits::to_node_ptr(value), 0);
+ }
+
+ //! <b>Requires</b>: value must be a const reference to a value inserted in a list.
+ //!
+ //! <b>Effects</b>: This function returns an iterator pointing to the element.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant time.
+ //!
+ //! <b>Note</b>: Iterators and references are not invalidated.
+ //! This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_iterator s_iterator_to(const_reference value)
+ {
+ BOOST_STATIC_ASSERT((!stateful_value_traits));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(const_cast<reference> (value))));
+ return const_iterator (value_traits::to_node_ptr(const_cast<reference> (value)), 0);
+ }
+
+ //! <b>Requires</b>: value must be a reference to a value inserted in a list.
+ //!
+ //! <b>Effects</b>: This function returns a const_iterator pointing to the element
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant time.
+ //!
+ //! <b>Note</b>: Iterators and references are not invalidated.
+ iterator iterator_to(reference value)
{
- BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(value)));
- return iterator (ValueTraits::to_node_ptr(value));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(value)));
+ return iterator (value_traits::to_node_ptr(value), this);
}
//! <b>Requires</b>: value must be a const reference to a value inserted in a list.
@@ -1343,10 +1450,10 @@
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
- static const_iterator iterator_to(const_reference value)
+ const_iterator iterator_to(const_reference value) const
{
- BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast<reference> (value))));
- return const_iterator (ValueTraits::to_node_ptr(const_cast<reference> (value)));
+ BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(const_cast<reference> (value))));
+ return const_iterator (value_traits::to_node_ptr(const_cast<reference> (value)), this);
}
//! <b>Returns</b>: The iterator to the element before i in the list.
@@ -1360,7 +1467,7 @@
{
return iterator
(node_algorithms::get_previous_node
- (before_begin().pointed_node(), i.pointed_node()));
+ (before_begin().pointed_node(), i.pointed_node()), 0);
}
//! <b>Returns</b>: The const_iterator to the element before i in the list.
@@ -1374,17 +1481,52 @@
{
return const_iterator
(node_algorithms::get_previous_node
- (before_begin().pointed_node(), i.pointed_node()));
+ (before_begin().pointed_node(), i.pointed_node()), 0);
+ }
+
+ private:
+ static slist_impl &priv_container_from_end_iterator(const const_iterator &end_iterator)
+ {
+ root_plus_size *r = detail::parent_from_member<root_plus_size, node>
+ ( detail::get_pointer(end_iterator.pointed_node()), &root_plus_size::root_);
+ data_t *d = detail::parent_from_member<data_t, root_plus_size>
+ ( r, &data_t::root_plus_size_);
+ slist_impl *s = detail::parent_from_member<slist_impl, data_t>(d, &slist_impl::data_);
+ return *s;
}
};
-template <class V, bool C, class S>
-inline bool operator==(const slist<V, C, S>& x, const slist<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
+#else
+(const slist_impl<Config> &x, const slist_impl<Config> &y)
+#endif
+{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
+
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+bool operator==
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
+#else
+(const slist_impl<Config> &x, const slist_impl<Config> &y)
+#endif
{
+ typedef slist_impl<Config> slist_type;
+ typedef typename slist_type::const_iterator const_iterator;
+ const bool C = slist_type::constant_time_size;
if(C && x.size() != y.size()){
return false;
}
- typedef typename slist<V, C, S>::const_iterator const_iterator;
const_iterator end1 = x.end();
const_iterator i1 = x.begin();
@@ -1406,31 +1548,131 @@
}
}
-template <class V, bool C, class S>
-inline bool operator<(const slist<V, C, S>& x,
- const slist<V, C, S>& y)
-{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
-
-template <class V, bool C, class S>
-inline bool operator!=(const slist<V, C, S>& x, const slist<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator!=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
+#else
+(const slist_impl<Config> &x, const slist_impl<Config> &y)
+#endif
{ return !(x == y); }
-template <class V, bool C, class S>
-inline bool operator>(const slist<V, C, S>& x, const slist<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
+#else
+(const slist_impl<Config> &x, const slist_impl<Config> &y)
+#endif
{ return y < x; }
-template <class V, bool C, class S>
-inline bool operator<=(const slist<V, C, S>& x, const slist<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator<=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
+#else
+(const slist_impl<Config> &x, const slist_impl<Config> &y)
+#endif
{ return !(y < x); }
-template <class V, bool C, class S>
-inline bool operator>=(const slist<V, C, S>& x, const slist<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline bool operator>=
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
+#else
+(const slist_impl<Config> &x, const slist_impl<Config> &y)
+#endif
{ return !(x < y); }
-template <class V, bool C, class S>
-inline void swap(slist<V, C, S>& x, slist<V, C, S>& y)
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+inline void swap
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+(slist_impl<T, Options...> &x, slist_impl<T, Options...> &y)
+#else
+(slist_impl<Config> &x, slist_impl<Config> &y)
+#endif
{ x.swap(y); }
+//! Helper metafunction to define a \c slist that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_slist
+{
+ /// @cond
+ typedef typename pack_options
+ < slist_defaults<T>, O1, O2, O3>::type packed_options;
+ typedef typename detail::get_value_traits
+ <T, typename packed_options::value_traits>::type value_traits;
+ typedef slist_impl
+ <
+ slistopt
+ < value_traits
+ , typename packed_options::size_type
+ , packed_options::constant_time_size
+ >
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
+
+#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class O1, class O2, class O3>
+class slist
+ : public make_slist<T, O1, O2, O3>::type
+{
+ typedef typename make_slist
+ <T, O1, O2, O3>::type Base;
+ typedef typename Base::real_value_traits real_value_traits;
+ //Assert if passed value traits are compatible with the type
+ BOOST_STATIC_ASSERT((detail::is_same<typename real_value_traits::value_type, T>::value));
+ public:
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+
+ slist(const value_traits &v_traits = value_traits())
+ : Base(v_traits)
+ {}
+
+ template<class Iterator>
+ slist(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
+ : Base(b, e, v_traits)
+ {}
+
+ static slist &container_from_end_iterator(iterator end_iterator)
+ { return static_cast<slist &>(Base::container_from_end_iterator(end_iterator)); }
+
+ static const slist &container_from_end_iterator(const_iterator end_iterator)
+ { return static_cast<const slist &>(Base::container_from_end_iterator(end_iterator)); }
+};
+
+#endif
+
} //namespace intrusive
} //namespace boost
Modified: trunk/boost/intrusive/slist_hook.hpp
==============================================================================
--- trunk/boost/intrusive/slist_hook.hpp (original)
+++ trunk/boost/intrusive/slist_hook.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -17,19 +17,48 @@
#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/detail/slist_node.hpp>
#include <boost/intrusive/circular_slist_algorithms.hpp>
-#include <boost/intrusive/linking_policy.hpp>
-#include <boost/intrusive/tag.hpp>
-#include <boost/static_assert.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/detail/generic_hook.hpp>
namespace boost {
namespace intrusive {
+/// @cond
+template<class VoidPointer>
+struct get_slist_node_algo
+{
+ typedef circular_slist_algorithms<slist_node_traits<VoidPointer> > type;
+};
+/// @endcond
+
+//! Helper metafunction to define a \c slist_base_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_slist_base_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
+
+ typedef detail::generic_hook
+ < get_slist_node_algo<typename packed_options::void_pointer>
+ , typename packed_options::tag
+ , packed_options::link_mode
+ , detail::SlistBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
//! Derive a class from slist_base_hook in order to store objects in
-//! in an slist. slist_base_hook holds the data necessary to maintain the
-//! list and provides an appropriate value_traits class for slist.
+//! in an list. slist_base_hook holds the data necessary to maintain the
+//! list and provides an appropriate value_traits class for list.
//!
//! The first integer template argument defines a tag to identify the node.
//! The same tag value can be used in different classes, but if a class is
@@ -39,97 +68,50 @@
//! The second boolean template parameter will specify the linking mode of the hook.
//!
//! The third argument is the pointer type that will be used internally in the hook
-//! and the slist configured from this hook.
-template< class Tag //= tag
- , linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
+//! and the list configured from this hook.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
class slist_base_hook
- : private detail::slist_node_traits<VoidPointer>::node
+ : public make_slist_base_hook<O1, O2, O3>::type
{
- public:
- typedef detail::slist_node_traits<VoidPointer> node_traits;
- enum { linking_policy = Policy };
-
- /// @cond
- private:
- typedef circular_slist_algorithms<node_traits> node_algorithms;
- /// @endcond
-
- public:
- typedef typename node_traits::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;
- typedef slist_base_hook
- <Tag, Policy, VoidPointer> this_type;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type>::type this_type_ptr;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type>::type const_this_type_ptr;
-
- /// @cond
- private:
- node_ptr this_as_node()
- { return node_ptr(static_cast<node *const>(this)); }
-
- const_node_ptr this_as_node() const
- { return const_node_ptr(static_cast<const node *const>(this)); }
- /// @endcond
-
- public:
-
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
- slist_base_hook()
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ slist_base_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using slist_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- slist_base_hook(const slist_base_hook& )
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ slist_base_hook(const slist_base_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using slist_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- slist_base_hook& operator=(const slist_base_hook& )
- { return *this; }
+ slist_base_hook& operator=(const slist_base_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an slist an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
- ~slist_base_hook()
- { detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
+ ~slist_base_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
@@ -143,174 +125,99 @@
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
- void swap_nodes(slist_base_hook &other)
- { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
+ void swap_nodes(slist_base_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
- //! otherwise. This function can be used to test whether list::iterator_to
+ //! otherwise. This function can be used to test whether \c slist::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
- bool is_linked() const
- {
- //is_linked() can be only used in safe-mode or auto-unlink
- BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
- return !node_algorithms::unique(this_as_node());
- }
+ bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
- //! This function is only allowed if Policy is auto_unlink.
- //!
- //! <b>Throws</b>: Nothing.
- void unlink()
- {
- BOOST_STATIC_ASSERT((Policy == auto_unlink));
- node_algorithms::unlink(this_as_node());
- node_algorithms::init(this_as_node());
- }
-
- //! The value_traits class is used as the first template argument for list.
- //! The template argument T defines the class type stored in list. Objects
- //! of type T and of types derived from T can be stored. T doesn't need to be
- //! copy-constructible or assignable.
- template<class T>
- struct value_traits
- : detail::derivation_hook_value_traits<T, this_type, Tag>
- {};
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
+ //! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr(static_cast<slist_base_hook*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr(static_cast<const slist_base_hook*> (detail::get_pointer(p)));
- }
+ void unlink();
+ #endif
+};
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return this_as_node(); }
+//! Helper metafunction to define a \c slist_member_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_slist_member_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return this_as_node(); }
+ typedef detail::generic_hook
+ < get_slist_node_algo<typename packed_options::void_pointer>
+ , member_tag
+ , packed_options::link_mode
+ , detail::NoBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
};
//! Put a public data member slist_member_hook in order to store objects of this class in
-//! an slist. slist_member_hook holds the data necessary for maintaining the list and
-//! provides an appropriate value_traits class for slist.
-//!
-//! The template argument T defines the class type stored in slist. Objects of type
-//! T and of types derived from T can be stored. T doesn't need to be
-//! copy-constructible or assignable.
+//! an list. slist_member_hook holds the data necessary for maintaining the list and
+//! provides an appropriate value_traits class for list.
//!
-//! The second boolean template parameter will specify the linking mode of the hook.
+//! The first boolean template parameter will specify the linking mode of the hook.
//!
-//! The third argument is the pointer type that will be used internally in the hook
-//! and the slist configured from this hook.
-template< linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
-class slist_member_hook
- : private detail::slist_node_traits<VoidPointer>::node
+//! The second argument is the pointer type that will be used internally in the hook
+//! and the list configured from this hook.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
+class slist_member_hook
+ : public make_slist_member_hook<O1, O2, O3>::type
{
- public:
- typedef detail::slist_node_traits<VoidPointer> node_traits;
- enum { linking_policy = Policy };
-
- /// @cond
- private:
- typedef circular_slist_algorithms<node_traits> node_algorithms;
- /// @endcond
-
- public:
- typedef typename node_traits::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;
- typedef slist_member_hook
- <Policy, VoidPointer> this_type;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type >::type this_type_ptr;
-
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type >::type const_this_type_ptr;
-
- /// @cond
- private:
- node_ptr this_as_node()
- { return node_ptr(static_cast<node *const>(this)); }
-
- const_node_ptr this_as_node() const
- { return const_node_ptr(static_cast<const node *const>(this)); }
- /// @endcond
-
- public:
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
- slist_member_hook()
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ slist_member_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using slist_member_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- slist_member_hook(const slist_member_hook& )
- : node()
- {
- if(Policy == safe_link || Policy == auto_unlink){
- node_algorithms::init(this_as_node());
- }
- }
+ slist_member_hook(const slist_member_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using slist_member_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- slist_member_hook& operator=(const slist_member_hook& )
- { return *this; }
+ slist_member_hook& operator=(const slist_member_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an slist an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
- ~slist_member_hook()
- { detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
+ ~slist_member_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
@@ -323,78 +230,29 @@
//!
//! <b>Complexity</b>: Constant
//!
- //! <b>Throws</b>: Nothing.
- void swap_nodes(slist_member_hook& other)
- { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
+ //! <b>Throws</b>: Nothing.
+ void swap_nodes(slist_member_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
- //! otherwise. This function can be used to test whether list::iterator_to
+ //! otherwise. This function can be used to test whether \c slist::iterator_to
//! will return a valid iterator.
//!
- //! <b>Complexity</b>: Constant
- bool is_linked() const
- {
- //is_linked() can be only used in safe-mode or auto-unlink
- BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
- return !node_algorithms::unique(this_as_node());
- }
+ //! <b>Complexity</b>: Constant
+ bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
- //! This function is only allowed if Policy is auto_unlink.
- //!
- //! <b>Throws</b>: Nothing.
- void unlink()
- {
- BOOST_STATIC_ASSERT((Policy == auto_unlink));
- node_algorithms::unlink(this_as_node());
- node_algorithms::init(this_as_node());
- }
-
- //! The value_traits class is used as the first template argument for list.
- //! The template argument is a pointer to member pointing to the node in
- //! the class. Objects of type T and of types derived from T can be stored.
- //! T doesn't need to be copy-constructible or assignable.
- template<class T, this_type T::* M>
- struct value_traits
- : detail::member_hook_value_traits<T, this_type, M>
- {};
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr(static_cast<this_type*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr(static_cast<const this_type*> (detail::get_pointer(p)));
- }
-
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return this_as_node(); }
-
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
+ //! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return this_as_node(); }
+ void unlink();
+ #endif
};
} //namespace intrusive
} //namespace boost
-#include<boost/intrusive/detail/config_end.hpp>
+#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_SLIST_HOOK_HPP
Deleted: trunk/boost/intrusive/tag.hpp
==============================================================================
--- trunk/boost/intrusive/tag.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
+++ (empty file)
@@ -1,26 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////
-//
-// (C) Copyright Ion Gaztanaga 2006-2007
-//
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-//
-// See http://www.boost.org/libs/intrusive for documentation.
-//
-/////////////////////////////////////////////////////////////////////////////
-
-#ifndef BOOST_INTRUSIVE_DEFAULT_TAG_HPP
-#define BOOST_INTRUSIVE_DEFAULT_TAG_HPP
-
-namespace boost {
-namespace intrusive {
-
-//!This is the declaration of the default
-//!hook used by base hooks
-class tag;
-
-} //namespace intrusive
-} //namespace boost
-
-#endif //BOOST_INTRUSIVE_DEFAULT_TAG_HPP
Modified: trunk/boost/intrusive/trivial_value_traits.hpp
==============================================================================
--- trunk/boost/intrusive/trivial_value_traits.hpp (original)
+++ trunk/boost/intrusive/trivial_value_traits.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -13,7 +13,7 @@
#ifndef BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP
-#include <boost/intrusive/linking_policy.hpp>
+#include <boost/intrusive/link_mode.hpp>
namespace boost {
namespace intrusive {
@@ -21,7 +21,7 @@
//!This value traits template is used to create value traits
//!from user defined node traits where value_traits::value_type and
//!node_traits::node should be equal
-template<class NodeTraits, linking_policy LinkingPolicy = safe_link>
+template<class NodeTraits, link_mode_type LinkMode = normal_link>
struct trivial_value_traits
{
typedef NodeTraits node_traits;
@@ -30,11 +30,11 @@
typedef typename node_traits::node value_type;
typedef node_ptr pointer;
typedef const_node_ptr const_pointer;
- enum { linking_policy = LinkingPolicy };
- static node_ptr to_node_ptr (value_type &value) { return node_ptr(&value); }
+ static const link_mode_type link_mode = LinkMode;
+ static node_ptr to_node_ptr (value_type &value) { return node_ptr(&value); }
static const_node_ptr to_node_ptr (const value_type &value) { return const_node_ptr(&value); }
- static pointer to_value_ptr(node_ptr n) { return pointer(n); }
- static const_pointer to_value_ptr(const_node_ptr n) { return const_pointer(n); }
+ static pointer to_value_ptr(node_ptr n) { return pointer(n); }
+ static const_pointer to_value_ptr(const_node_ptr n) { return const_pointer(n); }
};
} //namespace intrusive
Modified: trunk/boost/intrusive/unordered_set.hpp
==============================================================================
--- trunk/boost/intrusive/unordered_set.hpp (original)
+++ trunk/boost/intrusive/unordered_set.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -10,8 +10,8 @@
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
-#ifndef BOOST_INTRUSIVE_HASHSET_HPP
-#define BOOST_INTRUSIVE_HASHSET_HPP
+#ifndef BOOST_INTRUSIVE_UNORDERED_SET_HPP
+#define BOOST_INTRUSIVE_UNORDERED_SET_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
@@ -32,27 +32,22 @@
//! unordered_set more complicated than purely intrusive containers.
//! `bucket_type` is default-constructible, copyable and assignable
//!
-//! The template parameter ValueTraits is called "value traits". It stores
-//! information and operations about the type to be stored in the container.
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
//!
-//! The template parameter Hash is a unary function object that take an argument
-//! of type ValueTraits::value_type and returns a value of type std::size_t.
-//!
-//! The template parameter Equal is a binary predicate that takes two arguments of
-//! type ValueTraits::value_type. Equal is an equivalence relation.
-//!
-//! If the user specifies ConstantTimeSize as "true", a member of type SizeType
-//! will be embedded in the class, that will keep track of the number of stored objects.
-//! This will allow constant-time O(1) size() member, instead of default O(N) size.
+//! 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<> .
//!
//! unordered_set only provides forward iterators but it provides 4 iterator types:
//! iterator and const_iterator to navigate through the whole container and
//! local_iterator and const_local_iterator to navigate through the values
//! stored in a single bucket. Local iterators are faster and smaller.
//!
-//! It's not recommended to use non ConstantTimeSize unordered_sets because several
+//! It's not recommended to use non constant-time size unordered_sets because several
//! key functions, like "empty()", become non-constant time functions. Non
-//! ConstantTimeSize unordered_sets are mainly provided to support auto-unlink hooks.
+//! constant-time size unordered_sets are mainly provided to support auto-unlink hooks.
//!
//! unordered_set, unlike std::unordered_set, does not make automatic rehashings nor
//! offers functions related to a load factor. Rehashing can be explicitly requested
@@ -60,48 +55,53 @@
//!
//! Since no automatic rehashing is done, iterators are never invalidated when
//! inserting or erasing elements. Iterators are only invalidated when rehasing.
-template< class ValueTraits
- , class Hash //= boost::hash<typename ValueTraits::value_type>
- , class Equal //= std::equal_to<typename ValueTraits::value_type>
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class unordered_set
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class unordered_set_impl
{
/// @cond
private:
- typedef hashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType> table_type;
+ typedef hashtable_impl<Config> table_type;
//! This class is
//! non-copyable
- unordered_set (const unordered_set&);
+ unordered_set_impl (const unordered_set_impl&);
//! This class is
//! non-assignable
- unordered_set &operator =(const unordered_set&);
+ unordered_set_impl &operator =(const unordered_set_impl&);
typedef table_type implementation_defined;
/// @endcond
public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef value_type key_type;
- typedef Equal key_equal;
- typedef Hash hasher;
+ typedef typename implementation_defined::value_type value_type;
+ typedef typename implementation_defined::value_traits value_traits;
+ typedef typename implementation_defined::bucket_traits bucket_traits;
+ typedef typename implementation_defined::pointer pointer;
+ typedef typename implementation_defined::const_pointer const_pointer;
+ typedef typename implementation_defined::reference reference;
+ typedef typename implementation_defined::const_reference const_reference;
+ typedef typename implementation_defined::difference_type difference_type;
+ typedef typename implementation_defined::size_type size_type;
+ typedef typename implementation_defined::key_type key_type;
+ typedef typename implementation_defined::key_equal key_equal;
+ typedef typename implementation_defined::hasher hasher;
typedef typename implementation_defined::bucket_type bucket_type;
- typedef typename boost::pointer_to_other<pointer, bucket_type>::type bucket_ptr;
+ typedef typename implementation_defined::bucket_ptr bucket_ptr;
typedef typename implementation_defined::iterator iterator;
typedef typename implementation_defined::const_iterator const_iterator;
typedef typename implementation_defined::insert_commit_data insert_commit_data;
typedef typename implementation_defined::local_iterator local_iterator;
typedef typename implementation_defined::const_local_iterator const_local_iterator;
+ typedef typename implementation_defined::node_traits node_traits;
+ typedef typename implementation_defined::node node;
+ typedef typename implementation_defined::node_ptr node_ptr;
+ typedef typename implementation_defined::const_node_ptr const_node_ptr;
+ typedef typename implementation_defined::node_algorithms node_algorithms;
/// @cond
private:
@@ -112,7 +112,7 @@
//! <b>Requires</b>: buckets must not be being used by any other resource.
//!
- //! <b>Effects</b>: Constructs an empty unordered_set, storing a reference
+ //! <b>Effects</b>: Constructs an empty unordered_set_impl, storing a reference
//! to the bucket array and copies of the hasher and equal functors.
//!
//! <b>Complexity</b>: Constant.
@@ -123,11 +123,11 @@
//!
//! <b>Notes</b>: buckets array must be disposed only after
//! *this is disposed.
- unordered_set( bucket_ptr buckets
- , size_type buckets_len
- , const Hash & hasher = Hash()
- , const Equal &equal = Equal())
- : table_(buckets, buckets_len, hasher, equal)
+ unordered_set_impl( const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : table_(b_traits, hash_func, equal_func, v_traits)
{}
//! <b>Requires</b>: buckets must not be being used by any other resource
@@ -141,18 +141,18 @@
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
- //! or the copy constructor or invocation of Hash or Equal throws.
+ //! or the copy constructor or invocation of hasher or key_equal throws.
//!
//! <b>Notes</b>: buckets array must be disposed only after
//! *this is disposed.
template<class Iterator>
- unordered_set( bucket_ptr buckets
- , size_type buckets_len
- , Iterator b
- , Iterator e
- , const Hash & hasher = Hash()
- , const Equal &equal = Equal())
- : table_(buckets, buckets_len, hasher, equal)
+ unordered_set_impl( Iterator b
+ , Iterator e
+ , const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : table_(b_traits, hash_func, equal_func, v_traits)
{ table_.insert_unique(b, e); }
//! <b>Effects</b>: Detaches all elements from this. The objects in the unordered_set
@@ -162,7 +162,7 @@
//! it's a safe-mode or auto-unlink value. Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
- ~unordered_set()
+ ~unordered_set_impl()
{}
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_set.
@@ -236,7 +236,7 @@
//! <b>Effects</b>: Returns true is the container is empty.
//!
- //! <b>Complexity</b>: if ConstantTimeSize is false, average constant time
+ //! <b>Complexity</b>: if constant-time size option is disabled, average constant time
//! (worst case, with empty() == true): O(this->bucket_count()).
//! Otherwise constant.
//!
@@ -247,7 +247,7 @@
//! <b>Effects</b>: Returns the number of elements stored in the unordered_set.
//!
//! <b>Complexity</b>: Linear to elements contained in *this if
- //! ConstantTimeSize is false. Constant-time otherwise.
+ //! constant-time size option is enabled. Constant-time otherwise.
//!
//! <b>Throws</b>: Nothing.
size_type size() const
@@ -263,7 +263,7 @@
//!
//! <b>Throws</b>: If the swap() call for the comparison or hash functors
//! found using ADL throw. Basic guarantee.
- void swap(unordered_set& other)
+ void swap(unordered_set_impl& other)
{ table_.swap(other.table_); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
@@ -280,7 +280,7 @@
//!
//! <b>Throws</b>: If cloner throws. Basic guarantee.
template <class Cloner, class Disposer>
- void clone_from(const unordered_set &src, Cloner cloner, Disposer disposer)
+ void clone_from(const unordered_set_impl &src, Cloner cloner, Disposer disposer)
{ table_.clone_from(src.table_, cloner, disposer); }
//! <b>Requires</b>: value must be an lvalue
@@ -433,13 +433,13 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw. Basic guarantee.
+ //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)
- { return table_.erase(key, hasher, equal); }
+ size_type erase(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func)
+ { return table_.erase(key, hash_func, equal_func); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
@@ -493,7 +493,7 @@
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
//! <b>Effects</b>: Erases all the elements with the given key.
- //! according to the comparison functor "equal".
+ //! according to the comparison functor "equal_func".
//! Disposer::operator()(pointer) is called for the removed elements.
//!
//! <b>Returns</b>: The number of erased elements.
@@ -501,13 +501,13 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or key_value_equal throw. Basic guarantee.
+ //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators
//! to the erased elements.
template<class KeyType, class KeyHasher, class KeyValueEqual, class Disposer>
- size_type erase_and_dispose(const KeyType& key, KeyHasher hasher, KeyValueEqual equal, Disposer disposer)
- { return table_.erase_and_dispose(key, hasher, equal, disposer); }
+ size_type erase_and_dispose(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func, Disposer disposer)
+ { return table_.erase_and_dispose(key, hash_func, equal_func, disposer); }
//! <b>Effects</b>: Erases all of the elements.
//!
@@ -544,22 +544,22 @@
size_type count(const_reference value) const
{ return table_.find(value) != end(); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Returns the number of contained elements with the given key
//!
//! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw.
+ //! <b>Throws</b>: If hash_func or equal_func throw.
template<class KeyType, class KeyHasher, class KeyValueEqual, class Disposer>
- size_type count(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const
- { return table_.find(key, hasher, equal) != end(); }
+ size_type count(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) const
+ { return table_.find(key, hash_func, equal_func) != end(); }
//! <b>Effects</b>: Finds an iterator to the first element is equal to
//! "value" or end() if that element does not exist.
@@ -570,13 +570,13 @@
iterator find(const_reference value)
{ return table_.find(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Finds an iterator to the first element whose key is
//! "key" according to the given hasher and equality functor or end() if
@@ -584,14 +584,14 @@
//!
//! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw.
+ //! <b>Throws</b>: If hash_func or equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)
- { return table_.find(key, hasher, equal); }
+ iterator find(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func)
+ { return table_.find(key, hash_func, equal_func); }
//! <b>Effects</b>: Finds a const_iterator to the first element whose key is
//! "key" or end() if that element does not exist.
@@ -602,13 +602,13 @@
const_iterator find(const_reference value) const
{ return table_.find(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Finds an iterator to the first element whose key is
//! "key" according to the given hasher and equality functor or end() if
@@ -616,14 +616,14 @@
//!
//! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw.
+ //! <b>Throws</b>: If hash_func or equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- const_iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const
- { return table_.find(key, equal); }
+ const_iterator find(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) const
+ { return table_.find(key, hash_func, equal_func); }
//! <b>Effects</b>: Returns a range containing all elements with values equivalent
//! to value. Returns std::make_pair(this->end(), this->end()) if no such
@@ -635,28 +635,29 @@
std::pair<iterator,iterator> equal_range(const_reference value)
{ return table_.equal_range(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Returns a range containing all elements with equivalent
//! keys. Returns std::make_pair(this->end(), this->end()) if no such
//! elements exist.
//!
- //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).
+ //! <b>Complexity</b>: Average case O(this->count(key, hash_func, hash_func)).
+ //! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or the equal throw.
+ //! <b>Throws</b>: If hash_func or the equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- std::pair<iterator,iterator> equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)
- { return table_.equal_range(key, hasher, equal); }
+ std::pair<iterator,iterator> equal_range(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func)
+ { return table_.equal_range(key, hash_func, equal_func); }
//! <b>Effects</b>: Returns a range containing all elements with values equivalent
//! to value. Returns std::make_pair(this->end(), this->end()) if no such
@@ -669,29 +670,30 @@
equal_range(const_reference value) const
{ return table_.equal_range(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
- //! "key_value_equal" must be a equality function that induces
+ //! "equal_func" must be a equality function that induces
//! the same equality as key_equal. The difference is that
- //! "key_value_equal" compares an arbitrary key with the contained values.
+ //! "equal_func" compares an arbitrary key with the contained values.
//!
//! <b>Effects</b>: Returns a range containing all elements with equivalent
//! keys. Returns std::make_pair(this->end(), this->end()) if no such
//! elements exist.
//!
- //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).
+ //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
+ //! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If the hasher or equal throw.
+ //! <b>Throws</b>: If the hash_func or equal_func throw.
//!
//! <b>Note</b>: This function is used when constructing a value_type
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
std::pair<const_iterator, const_iterator>
- equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const
- { return table_.equal_range(key, equal); }
+ equal_range(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) const
+ { return table_.equal_range(key, hash_func, equal_func); }
//! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
//! appropriate type. Otherwise the behavior is undefined.
@@ -726,8 +728,11 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static local_iterator local_iterator_to(reference value)
- { return table_type::local_iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static local_iterator s_local_iterator_to(reference value)
+ { return table_type::s_local_iterator_to(value); }
//! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
//! appropriate type. Otherwise the behavior is undefined.
@@ -738,8 +743,35 @@
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static const_local_iterator local_iterator_to(const_reference value)
- { return table_type::local_iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_local_iterator s_local_iterator_to(const_reference value)
+ { return table_type::s_local_iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
+ //! that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ local_iterator local_iterator_to(reference value)
+ { return table_.local_iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
+ //! the unordered_set that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ const_local_iterator local_iterator_to(const_reference value) const
+ { return table_.local_iterator_to(value); }
//! <b>Effects</b>: Returns the number of buckets passed in the constructor
//! or the last rehash function.
@@ -771,21 +803,21 @@
size_type bucket(const value_type& k) const
{ return table_.bucket(k); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! <b>Effects</b>: Returns the index of the bucket in which elements
//! with keys equivalent to k would be found, if any such element existed.
//!
//! <b>Complexity</b>: Constant.
//!
- //! <b>Throws</b>: If hasher throws.
+ //! <b>Throws</b>: If hash_func throws.
//!
//! <b>Note</b>: the return value is in the range [0, this->bucket_count()).
template<class KeyType, class KeyHasher>
- size_type bucket(const KeyType& k, KeyHasher hasher) const
- { return table_.bucket(k, hasher); }
+ size_type bucket(const KeyType& k, KeyHasher hash_func) const
+ { return table_.bucket(k, hash_func); }
//! <b>Effects</b>: Returns the bucket array pointer passed in the constructor
//! or the last rehash function.
@@ -891,8 +923,8 @@
//! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.
//!
//! <b>Throws</b>: If the hasher functor throws. Basic guarantee.
- void rehash(bucket_ptr new_buckets, size_type new_size)
- { table_.rehash(new_buckets, new_size); }
+ void rehash(const bucket_traits &new_bucket_traits)
+ { table_.rehash(new_bucket_traits); }
//! <b>Effects</b>: Returns the nearest new bucket count optimized for
//! the container that is bigger than n. This suggestion can be used
@@ -919,6 +951,70 @@
{ return table_type::suggested_lower_bucket_count(n); }
};
+//! Helper metafunction to define an \c unordered_set that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none
+ , class O5 = none, class O6 = none
+ , class O7 = none
+ >
+#endif
+struct make_unordered_set
+{
+ /// @cond
+ typedef unordered_set_impl
+ < typename make_hashtable_opt
+ <T, O1, O2, O3, O4, O5, O6, O7>::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>
+class unordered_set
+ : public make_unordered_set<T, O1, O2, O3, O4, O5, O6, O7>::type
+{
+ typedef typename make_unordered_set
+ <T, O1, O2, O3, O4, O5, O6, O7>::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));
+
+ public:
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::bucket_traits bucket_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+ typedef typename Base::bucket_ptr bucket_ptr;
+ typedef typename Base::size_type size_type;
+ typedef typename Base::hasher hasher;
+ typedef typename Base::key_equal key_equal;
+
+ unordered_set ( const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : Base(b_traits, hash_func, equal_func, v_traits)
+ {}
+
+ template<class Iterator>
+ unordered_set ( Iterator b
+ , Iterator e
+ , const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : Base(b, e, b_traits, hash_func, equal_func, v_traits)
+ {}
+};
+
+#endif
+
+
//! The class template unordered_multiset is an intrusive container, that mimics most of
//! the interface of std::tr1::unordered_multiset as described in the C++ TR1.
//!
@@ -930,27 +1026,22 @@
//! unordered_multiset more complicated than purely intrusive containers.
//! `bucket_type` is default-constructible, copyable and assignable
//!
-//! The template parameter ValueTraits is called "value traits". It stores
-//! information and operations about the type to be stored in the container.
-//!
-//! The template parameter Hash is a unary function object that take an argument
-//! of type ValueTraits::value_type and returns a value of type std::size_t.
+//! The template parameter \c T is the type to be managed by the container.
+//! The user can specify additional options and if no options are provided
+//! default options are used.
//!
-//! The template parameter Equal is a binary predicate that takes two arguments of
-//! type ValueTraits::value_type. Equal is an equivalence relation.
-//!
-//! If the user specifies ConstantTimeSize as "true", a member of type SizeType
-//! will be embedded in the class, that will keep track of the number of stored objects.
-//! This will allow constant-time O(1) size() member, instead of default O(N) size.
+//! 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<> .
//!
//! unordered_multiset only provides forward iterators but it provides 4 iterator types:
//! iterator and const_iterator to navigate through the whole container and
//! local_iterator and const_local_iterator to navigate through the values
//! stored in a single bucket. Local iterators are faster and smaller.
//!
-//! It's not recommended to use non ConstantTimeSize unordered_multisets because several
+//! It's not recommended to use non constant-time size unordered_multisets because several
//! key functions, like "empty()", become non-constant time functions. Non
-//! ConstantTimeSize unordered_multisets are mainly provided to support auto-unlink hooks.
+//! constant-time size unordered_multisets are mainly provided to support auto-unlink hooks.
//!
//! unordered_multiset, unlike std::unordered_set, does not make automatic rehashings nor
//! offers functions related to a load factor. Rehashing can be explicitly requested
@@ -958,48 +1049,53 @@
//!
//! Since no automatic rehashing is done, iterators are never invalidated when
//! inserting or erasing elements. Iterators are only invalidated when rehasing.
-template< class ValueTraits
- , class Hash //= boost::hash<typename ValueTraits::value_type>
- , class Equal //= std::equal_to<typename ValueTraits::value_type>
- , bool ConstantTimeSize //= true
- , class SizeType //= std::size_t
- >
-class unordered_multiset
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class Config>
+#endif
+class unordered_multiset_impl
{
/// @cond
private:
- typedef hashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType> table_type;
+ typedef hashtable_impl<Config> table_type;
/// @endcond
//! This class is
//! non-copyable
- unordered_multiset (const unordered_multiset&);
+ unordered_multiset_impl (const unordered_multiset_impl&);
//! This class is
//! non-assignable
- unordered_multiset &operator =(const unordered_multiset&);
+ unordered_multiset_impl &operator =(const unordered_multiset_impl&);
typedef table_type implementation_defined;
public:
- typedef ValueTraits value_traits;
- typedef typename ValueTraits::value_type value_type;
- typedef typename ValueTraits::pointer pointer;
- typedef typename ValueTraits::const_pointer const_pointer;
- typedef typename std::iterator_traits<pointer>::reference reference;
- typedef typename std::iterator_traits<const_pointer>::reference const_reference;
- typedef typename std::iterator_traits<pointer>::difference_type difference_type;
- typedef SizeType size_type;
- typedef value_type key_type;
- typedef Equal key_equal;
- typedef Hash hasher;
+ typedef typename implementation_defined::value_type value_type;
+ typedef typename implementation_defined::value_traits value_traits;
+ typedef typename implementation_defined::bucket_traits bucket_traits;
+ typedef typename implementation_defined::pointer pointer;
+ typedef typename implementation_defined::const_pointer const_pointer;
+ typedef typename implementation_defined::reference reference;
+ typedef typename implementation_defined::const_reference const_reference;
+ typedef typename implementation_defined::difference_type difference_type;
+ typedef typename implementation_defined::size_type size_type;
+ typedef typename implementation_defined::key_type key_type;
+ typedef typename implementation_defined::key_equal key_equal;
+ typedef typename implementation_defined::hasher hasher;
typedef typename implementation_defined::bucket_type bucket_type;
- typedef typename boost::pointer_to_other<pointer, bucket_type>::type bucket_ptr;
+ typedef typename implementation_defined::bucket_ptr bucket_ptr;
typedef typename implementation_defined::iterator iterator;
typedef typename implementation_defined::const_iterator const_iterator;
typedef typename implementation_defined::insert_commit_data insert_commit_data;
typedef typename implementation_defined::local_iterator local_iterator;
typedef typename implementation_defined::const_local_iterator const_local_iterator;
+ typedef typename implementation_defined::node_traits node_traits;
+ typedef typename implementation_defined::node node;
+ typedef typename implementation_defined::node_ptr node_ptr;
+ typedef typename implementation_defined::const_node_ptr const_node_ptr;
+ typedef typename implementation_defined::node_algorithms node_algorithms;
/// @cond
private:
@@ -1021,11 +1117,11 @@
//!
//! <b>Notes</b>: buckets array must be disposed only after
//! *this is disposed.
- unordered_multiset ( bucket_ptr buckets
- , size_type buckets_len
- , const Hash & hasher = Hash()
- , const Equal &equal = Equal())
- : table_(buckets, buckets_len, hasher, equal)
+ unordered_multiset_impl ( const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : table_(b_traits, hash_func, equal_func, v_traits)
{}
//! <b>Requires</b>: buckets must not be being used by any other resource
@@ -1039,18 +1135,18 @@
//!
//! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
- //! or the copy constructor or invocation of Hash or Equal throws.
+ //! or the copy constructor or invocation of hasher or key_equal throws.
//!
//! <b>Notes</b>: buckets array must be disposed only after
//! *this is disposed.
template<class Iterator>
- unordered_multiset ( bucket_ptr buckets
- , size_type buckets_len
- , Iterator b
- , Iterator e
- , const Hash & hasher = Hash()
- , const Equal &equal = Equal())
- : table_(buckets, buckets_len, hasher, equal)
+ unordered_multiset_impl ( Iterator b
+ , Iterator e
+ , const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : table_(b_traits, hash_func, equal_func, v_traits)
{ table_.insert_equal(b, e); }
//! <b>Effects</b>: Detaches all elements from this. The objects in the unordered_multiset
@@ -1060,7 +1156,7 @@
//! it's a safe-mode or auto-unlink value. Otherwise constant.
//!
//! <b>Throws</b>: Nothing.
- ~unordered_multiset()
+ ~unordered_multiset_impl()
{}
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_multiset.
@@ -1134,7 +1230,7 @@
//! <b>Effects</b>: Returns true is the container is empty.
//!
- //! <b>Complexity</b>: if ConstantTimeSize is false, average constant time
+ //! <b>Complexity</b>: if constant-time size option is disabled, average constant time
//! (worst case, with empty() == true): O(this->bucket_count()).
//! Otherwise constant.
//!
@@ -1145,7 +1241,7 @@
//! <b>Effects</b>: Returns the number of elements stored in the unordered_multiset.
//!
//! <b>Complexity</b>: Linear to elements contained in *this if
- //! ConstantTimeSize is false. Constant-time otherwise.
+ //! constant-time size option is enabled. Constant-time otherwise.
//!
//! <b>Throws</b>: Nothing.
size_type size() const
@@ -1162,7 +1258,7 @@
//!
//! <b>Throws</b>: If the swap() call for the comparison or hash functors
//! found using ADL throw. Basic guarantee.
- void swap(unordered_multiset& other)
+ void swap(unordered_multiset_impl& other)
{ table_.swap(other.table_); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
@@ -1179,7 +1275,7 @@
//!
//! <b>Throws</b>: If cloner throws.
template <class Cloner, class Disposer>
- void clone_from(const unordered_multiset &src, Cloner cloner, Disposer disposer)
+ void clone_from(const unordered_multiset_impl &src, Cloner cloner, Disposer disposer)
{ table_.clone_from(src.table_, cloner, disposer); }
//! <b>Requires</b>: value must be an lvalue
@@ -1202,8 +1298,8 @@
//!
//! <b>Effects</b>: Equivalent to this->insert(t) for each element in [b, e).
//!
- //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
- //! size of the range. However, it is linear in N if the range is already sorted
+ //! <b>Complexity</b>: Insert range is in general O(N * log(N)), where N is the
+ //! size of the range. However, it is linear in N if the range is already sorted
//! by value_comp().
//!
//! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.
@@ -1251,9 +1347,9 @@
size_type erase(const_reference value)
{ return table_.erase(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! "key_value_equal" must be a equality function that induces
//! the same equality as key_equal. The difference is that
@@ -1267,13 +1363,14 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If the hasher or the equal functors throws. Basic guarantee.
+ //! <b>Throws</b>: If the hash_func or the equal_func functors throws.
+ //! Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators (but not the references)
//! to the erased elements. No destructors are called.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)
- { return table_.erase(key, hasher, equal); }
+ size_type erase(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func)
+ { return table_.erase(key, hash_func, equal_func); }
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
@@ -1327,7 +1424,7 @@
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
//! <b>Effects</b>: Erases all the elements with the given key.
- //! according to the comparison functor "equal".
+ //! according to the comparison functor "equal_func".
//! Disposer::operator()(pointer) is called for the removed elements.
//!
//! <b>Returns</b>: The number of erased elements.
@@ -1335,13 +1432,13 @@
//! <b>Complexity</b>: Average case O(this->count(value)).
//! Worst case O(this->size()).
//!
- //! <b>Throws</b>: If hasher or equal throw. Basic guarantee.
+ //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
//!
//! <b>Note</b>: Invalidates the iterators
//! to the erased elements.
template<class KeyType, class KeyHasher, class KeyValueEqual, class Disposer>
- size_type erase_and_dispose(const KeyType& key, KeyHasher hasher, KeyValueEqual equal, Disposer disposer)
- { return table_.erase_and_dispose(key, hasher, equal, disposer); }
+ size_type erase_and_dispose(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func, Disposer disposer)
+ { return table_.erase_and_dispose(key, hash_func, equal_func, disposer); }
//! <b>Effects</b>: Erases all the elements of the container.
//!
@@ -1378,9 +1475,9 @@
size_type count(const_reference value) const
{ return table_.count(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! "key_value_equal" must be a equality function that induces
//! the same equality as key_equal. The difference is that
@@ -1392,8 +1489,8 @@
//!
//! <b>Throws</b>: If the internal hasher or the equality functor throws.
template<class KeyType, class KeyHasher, class KeyValueEqual, class Disposer>
- size_type count(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const
- { return table_.count(key, hasher, equal); }
+ size_type count(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) const
+ { return table_.count(key, hash_func, equal_func); }
//! <b>Effects</b>: Finds an iterator to the first element whose value is
//! "value" or end() if that element does not exist.
@@ -1404,9 +1501,9 @@
iterator find(const_reference value)
{ return table_.find(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! "key_value_equal" must be a equality function that induces
//! the same equality as key_equal. The difference is that
@@ -1424,8 +1521,8 @@
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)
- { return table_.find(key, hasher, equal); }
+ iterator find(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func)
+ { return table_.find(key, hash_func, equal_func); }
//! <b>Effects</b>: Finds a const_iterator to the first element whose key is
//! "key" or end() if that element does not exist.
@@ -1436,9 +1533,9 @@
const_iterator find(const_reference value) const
{ return table_.find(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! "key_value_equal" must be a equality function that induces
//! the same equality as key_equal. The difference is that
@@ -1456,8 +1553,8 @@
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- const_iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const
- { return table_.find(key, equal); }
+ const_iterator find(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) const
+ { return table_.find(key, hash_func, equal_func); }
//! <b>Effects</b>: Returns a range containing all elements with values equivalent
//! to value. Returns std::make_pair(this->end(), this->end()) if no such
@@ -1469,9 +1566,9 @@
std::pair<iterator,iterator> equal_range(const_reference value)
{ return table_.equal_range(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! "key_value_equal" must be a equality function that induces
//! the same equality as key_equal. The difference is that
@@ -1481,7 +1578,8 @@
//! keys. Returns std::make_pair(this->end(), this->end()) if no such
//! elements exist.
//!
- //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).
+ //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
+ //! Worst case O(this->size()).
//!
//! <b>Throws</b>: If the internal hasher or the equality functor throws.
//!
@@ -1489,8 +1587,9 @@
//! is expensive and the value_type can be compared with a cheaper
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
- std::pair<iterator,iterator> equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)
- { return table_.equal_range(key, hasher, equal); }
+ std::pair<iterator,iterator> equal_range
+ (const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func)
+ { return table_.equal_range(key, hash_func, equal_func); }
//! <b>Effects</b>: Returns a range containing all elements with values equivalent
//! to value. Returns std::make_pair(this->end(), this->end()) if no such
@@ -1503,9 +1602,9 @@
equal_range(const_reference value) const
{ return table_.equal_range(value); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! "key_value_equal" must be a equality function that induces
//! the same equality as key_equal. The difference is that
@@ -1515,7 +1614,8 @@
//! keys. Returns std::make_pair(this->end(), this->end()) if no such
//! elements exist.
//!
- //! <b>Complexity</b>: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()).
+ //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
+ //! Worst case O(this->size()).
//!
//! <b>Throws</b>: If the internal hasher or the equality functor throws.
//!
@@ -1524,8 +1624,8 @@
//! key type. Usually this key is part of the value_type.
template<class KeyType, class KeyHasher, class KeyValueEqual>
std::pair<const_iterator, const_iterator>
- equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const
- { return table_.equal_range(key, equal); }
+ equal_range(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) const
+ { return table_.equal_range(key, hash_func, equal_func); }
//! <b>Requires</b>: value must be an lvalue and shall be in a unordered_multiset of
//! appropriate type. Otherwise the behavior is undefined.
@@ -1551,29 +1651,59 @@
const_iterator iterator_to(const_reference value) const
{ return table_.iterator_to(value); }
- //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_multiset of
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
//! appropriate type. Otherwise the behavior is undefined.
//!
- //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_multiset
+ //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
//! that points to the value
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static local_iterator local_iterator_to(reference value)
- { return table_type::local_iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static local_iterator s_local_iterator_to(reference value)
+ { return table_type::s_local_iterator_to(value); }
- //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_multiset of
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
//! appropriate type. Otherwise the behavior is undefined.
//!
//! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
- //! the unordered_multiset that points to the value
+ //! the unordered_set that points to the value
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
- static const_local_iterator local_iterator_to(const_reference value)
- { return table_type::local_iterator_to(value); }
+ //!
+ //! <b>Note</b>: This static function is available only if the <i>value traits</i>
+ //! is stateless.
+ static const_local_iterator s_local_iterator_to(const_reference value)
+ { return table_type::s_local_iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
+ //! that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ local_iterator local_iterator_to(reference value)
+ { return table_.local_iterator_to(value); }
+
+ //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
+ //! appropriate type. Otherwise the behavior is undefined.
+ //!
+ //! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
+ //! the unordered_set that points to the value
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Throws</b>: Nothing.
+ const_local_iterator local_iterator_to(const_reference value) const
+ { return table_.local_iterator_to(value); }
//! <b>Effects</b>: Returns the number of buckets passed in the constructor
//! or the last rehash function.
@@ -1605,9 +1735,9 @@
size_type bucket(const value_type& k) const
{ return table_.bucket(k); }
- //! <b>Requires</b>: "hasher" must be a hash function that induces
+ //! <b>Requires</b>: "hash_func" must be a hash function that induces
//! the same hash values as the stored hasher. The difference is that
- //! "hasher" hashes the given key instead of the value_type.
+ //! "hash_func" hashes the given key instead of the value_type.
//!
//! <b>Effects</b>: Returns the index of the bucket in which elements
//! with keys equivalent to k would be found, if any such element existed.
@@ -1618,8 +1748,8 @@
//!
//! <b>Note</b>: the return value is in the range [0, this->bucket_count()).
template<class KeyType, class KeyHasher>
- size_type bucket(const KeyType& k, const KeyHasher &hasher) const
- { return table_.bucket(k, hasher); }
+ size_type bucket(const KeyType& k, const KeyHasher &hash_func) const
+ { return table_.bucket(k, hash_func); }
//! <b>Effects</b>: Returns the bucket array pointer passed in the constructor
//! or the last rehash function.
@@ -1725,8 +1855,8 @@
//! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.
//!
//! <b>Throws</b>: If the hasher functor throws.
- void rehash(bucket_ptr new_buckets, size_type new_size)
- { table_.rehash(new_buckets, new_size); }
+ void rehash(const bucket_traits &new_bucket_traits)
+ { table_.rehash(new_bucket_traits); }
//! <b>Effects</b>: Returns the nearest new bucket count optimized for
//! the container that is bigger than n. This suggestion can be used
@@ -1753,9 +1883,71 @@
{ return table_type::suggested_lower_bucket_count(n); }
};
+//! Helper metafunction to define an \c unordered_multiset that yields to the same type when the
+//! same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class T, class ...Options>
+#else
+template<class T, class O1 = none, class O2 = none
+ , class O3 = none, class O4 = none
+ , class O5 = none, class O6 = none
+ , class O7 = none
+ >
+#endif
+struct make_unordered_multiset
+{
+ /// @cond
+ typedef unordered_multiset_impl
+ < typename make_hashtable_opt
+ <T, O1, O2, O3, O4, O5, O6, O7>::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>
+class unordered_multiset
+ : public make_unordered_multiset<T, O1, O2, O3, O4, O5, O6, O7>::type
+{
+ typedef typename make_unordered_multiset
+ <T, O1, O2, O3, O4, O5, O6, O7>::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));
+
+ public:
+ typedef typename Base::value_traits value_traits;
+ typedef typename Base::bucket_traits bucket_traits;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+ typedef typename Base::bucket_ptr bucket_ptr;
+ typedef typename Base::size_type size_type;
+ typedef typename Base::hasher hasher;
+ typedef typename Base::key_equal key_equal;
+
+ unordered_multiset( const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : Base(b_traits, hash_func, equal_func, v_traits)
+ {}
+
+ template<class Iterator>
+ unordered_multiset( Iterator b
+ , Iterator e
+ , const bucket_traits &b_traits
+ , const hasher & hash_func = hasher()
+ , const key_equal &equal_func = key_equal()
+ , const value_traits &v_traits = value_traits())
+ : Base(b, e, b_traits, hash_func, equal_func, v_traits)
+ {}
+};
+
+#endif
+
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
-#endif //BOOST_INTRUSIVE_HASHSET_HPP
+#endif //BOOST_INTRUSIVE_UNORDERED_SET_HPP
Modified: trunk/boost/intrusive/unordered_set_hook.hpp
==============================================================================
--- trunk/boost/intrusive/unordered_set_hook.hpp (original)
+++ trunk/boost/intrusive/unordered_set_hook.hpp 2007-09-26 11:26:35 EDT (Wed, 26 Sep 2007)
@@ -11,19 +11,50 @@
//
/////////////////////////////////////////////////////////////////////////////
-#ifndef BOOST_INTRUSIVE_HASHSET_HOOK_HPP
-#define BOOST_INTRUSIVE_HASHSET_HOOK_HPP
+#ifndef BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
+#define BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
#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/linking_policy.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/detail/generic_hook.hpp>
namespace boost {
namespace intrusive {
+/// @cond
+template<class VoidPointer>
+struct get_uset_node_algo
+{
+ typedef circular_slist_algorithms<slist_node_traits<VoidPointer> > type;
+};
+/// @endcond
+
+//! Helper metafunction to define a \c unordered_set_base_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_unordered_set_base_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
+
+ typedef detail::generic_hook
+ < get_slist_node_algo<typename packed_options::void_pointer>
+ , typename packed_options::tag
+ , packed_options::link_mode
+ , detail::UsetBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
+};
+
//! Derive a class from unordered_set_base_hook in order to store objects in
//! in an unordered_set/unordered_multi_set. unordered_set_base_hook holds the data necessary to maintain
//! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
@@ -37,122 +68,103 @@
//!
//! The third argument is the pointer type that will be used internally in the hook
//! and the unordered_set/unordered_multi_set configured from this hook.
-template< class Tag //= tag
- , linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
class unordered_set_base_hook
+ : public make_unordered_set_base_hook<O1, O2, O3>::type
{
- /// @cond
- typedef slist_base_hook<Tag, Policy, VoidPointer> IsListHook;
- IsListHook m_slisthook;
- typedef IsListHook implementation_defined;
- /// @endcond
-
- public:
- enum { linking_policy = Policy };
- typedef typename implementation_defined::node_traits node_traits;
- typedef typename node_traits::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;
- typedef unordered_set_base_hook
- <Tag, Policy, VoidPointer> this_type;
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type>::type this_type_ptr;
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type>::type const_this_type_ptr;
-
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
- //! <b>Throws</b>: Nothing.
- unordered_set_base_hook()
- : m_slisthook()
- {}
+ //! <b>Throws</b>: Nothing.
+ unordered_set_base_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
- //! <b>Throws</b>: Nothing.
+ //! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using unordered_set_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- unordered_set_base_hook(const unordered_set_base_hook &other)
- : m_slisthook(other.m_slisthook)
- {}
+ unordered_set_base_hook(const unordered_set_base_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
- //! <b>Throws</b>: Nothing.
+ //! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using unordered_set_base_hook STL-compliant without forcing the
- //! user to do some additional work. "swap" can be used to emulate
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
- unordered_set_base_hook& operator=(const unordered_set_base_hook &other)
- { return *this; }
+ unordered_set_base_hook& operator=(const unordered_set_base_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
- //!
- //! <b>Throws</b>: Nothing.
- ~unordered_set_base_hook()
- {} //m_slisthook's destructor does the job
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an unordered_set an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
+ //!
+ //! <b>Throws</b>: Nothing.
+ ~unordered_set_base_hook();
+
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
+ //! related to those nodes in one or two containers. That is, if the node
+ //! this is part of the element e1, the node x is part of the element e2
+ //! and both elements are included in the containers s1 and s2, then after
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
+ //! at the position of e1. If one element is not in a container, then
+ //! after the swap-operation the other element is not in a container.
+ //! Iterators to e1 and e2 related to those nodes are invalidated.
+ //!
+ //! <b>Complexity</b>: Constant
+ //!
+ //! <b>Throws</b>: Nothing.
+ void swap_nodes(unordered_set_base_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
- //! otherwise. This function can be used to test whether unordered_set/unordered_multiset::iterator_to
+ //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
//! will return a valid iterator.
//!
- //! <b>Complexity</b>: Constant
- bool is_linked() const
- { return m_slisthook.is_linked(); }
-
- //! The value_traits class is used as the first template argument for unordered_set/unordered_multiset.
- //! The template argument T defines the class type stored in unordered_set/unordered_multiset. Objects
- //! of type T and of types derived from T can be stored. T doesn't need to be
- //! copy-constructible or assignable.
- template<class T>
- struct value_traits
- : detail::derivation_hook_value_traits<T, this_type, Tag>
- {};
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr((this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr((const this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p)));
- }
-
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return m_slisthook.to_node_ptr(); }
-
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return m_slisthook.to_node_ptr(); }
+ //! <b>Complexity</b>: Constant
+ bool is_linked() const;
+
+ //! <b>Effects</b>: Removes the node if it's inserted in a container.
+ //! This function is only allowed if link_mode is \c auto_unlink.
+ //!
+ //! <b>Throws</b>: Nothing.
+ void unlink();
+ #endif
+};
+
+
+//! Helper metafunction to define a \c unordered_set_member_hook that yields to the same
+//! type when the same options (either explicitly or implicitly) are used.
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1 = none, class O2 = none, class O3 = none>
+#endif
+struct make_unordered_set_member_hook
+{
+ /// @cond
+ typedef typename pack_options
+ < hook_defaults, O1, O2, O3>::type packed_options;
+
+ typedef detail::generic_hook
+ < get_uset_node_algo<typename packed_options::void_pointer>
+ , member_tag
+ , packed_options::link_mode
+ , detail::NoBaseHook
+ > implementation_defined;
+ /// @endcond
+ typedef implementation_defined type;
};
//! Put a public data member unordered_set_member_hook in order to store objects of this class in
@@ -163,123 +175,79 @@
//!
//! The second argument is the pointer type that will be used internally in the hook
//! and the unordered_set/unordered_multi_set configured from this hook.
-template< linking_policy Policy //= safe_link
- , class VoidPointer //= void *
- >
+#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+template<class ...Options>
+#else
+template<class O1, class O2, class O3>
+#endif
class unordered_set_member_hook
+ : public make_unordered_set_member_hook<O1, O2, O3>::type
{
- /// @cond
- typedef slist_member_hook<Policy, VoidPointer> IsListHook;
- IsListHook m_slisthook;
- typedef IsListHook implementation_defined;
- /// @endcond
-
- public:
- enum { linking_policy = Policy };
- typedef typename implementation_defined::node_traits node_traits;
- typedef typename node_traits::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;
- typedef unordered_set_member_hook
- <Policy, VoidPointer> this_type;
- typedef typename boost::pointer_to_other
- <VoidPointer, this_type>::type this_type_ptr;
- typedef typename boost::pointer_to_other
- <VoidPointer, const this_type>::type const_this_type_ptr;
-
- public:
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
- unordered_set_member_hook()
- : m_slisthook()
- {}
+ unordered_set_member_hook();
- //! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
+ //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
- //! makes classes using unordered_set_member_hook STL-compliant without forcing the
- //! user to do some additional work.
- unordered_set_member_hook(const unordered_set_member_hook &other)
- : m_slisthook(other.m_slisthook)
- {}
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
+ //! move-semantics.
+ unordered_set_member_hook(const unordered_set_member_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
- //! makes classes using unordered_set_member_hook STL-compliant without forcing the
- //! user to do some additional work.
- unordered_set_member_hook& operator=(const unordered_set_member_hook &other)
- { return *this; }
+ //! makes classes using the hook STL-compliant without forcing the
+ //! user to do some additional work. \c swap can be used to emulate
+ //! move-semantics.
+ unordered_set_member_hook& operator=(const unordered_set_member_hook& );
- //! <b>Effects</b>: If Policy is normal_link, the destructor does
- //! nothing (ie. no code is generated). If Policy is safe_link and the
- //! object is stored in an list an assertion is raised. If Policy is
- //! auto_unlink and "is_linked()" is true, the node is unlinked.
- //!
+ //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
+ //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
+ //! object is stored in an unordered_set an assertion is raised. If link_mode is
+ //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
+ //!
+ //! <b>Throws</b>: Nothing.
+ ~unordered_set_member_hook();
+
+ //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
+ //! related to those nodes in one or two containers. That is, if the node
+ //! this is part of the element e1, the node x is part of the element e2
+ //! and both elements are included in the containers s1 and s2, then after
+ //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
+ //! at the position of e1. If one element is not in a container, then
+ //! after the swap-operation the other element is not in a container.
+ //! Iterators to e1 and e2 related to those nodes are invalidated.
+ //!
+ //! <b>Complexity</b>: Constant
+ //!
//! <b>Throws</b>: Nothing.
- ~unordered_set_member_hook()
- {} //m_slisthook's destructor does the job
+ void swap_nodes(unordered_set_member_hook &other);
- //! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
+ //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
+ //!
+ //! <b>Returns</b>: true, if the node belongs to a container, false
+ //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
+ //! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
- bool is_linked() const
- { return m_slisthook.is_linked(); }
-
- //! The value_traits class is used as the first template argument for unordered_set/unordered_multiset.
- //! The template argument is a pointer to member pointing to the node in
- //! the class. Objects of type T and of types derived from T can be stored.
- //! T doesn't need to be copy-constructible or assignable.
- template<class T, this_type T::* M>
- struct value_traits
- : detail::member_hook_value_traits<T, this_type, M>
- {};
+ bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
- //! This function is only allowed if Policy is auto_unlink.
- //!
- //! <b>Throws</b>: Nothing.
- void unlink()
- { m_slisthook.unlink(); }
-
- //! <b>Effects</b>: Converts a pointer to a node into
- //! a pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static this_type_ptr to_hook_ptr(node_ptr p)
- {
- return this_type_ptr((this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p)));
- }
-
- //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
- //! a const pointer to the hook that holds that node.
- //!
- //! <b>Throws</b>: Nothing.
- static const_this_type_ptr to_hook_ptr(const_node_ptr p)
- {
- return const_this_type_ptr((const this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p)));
- }
-
- //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
- //!
- //! <b>Throws</b>: Nothing.
- node_ptr to_node_ptr()
- { return m_slisthook.to_node_ptr(); }
-
- //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
+ //! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
- const_node_ptr to_node_ptr() const
- { return m_slisthook.to_node_ptr(); }
+ void unlink();
+ #endif
};
} //namespace intrusive
@@ -287,4 +255,4 @@
#include <boost/intrusive/detail/config_end.hpp>
-#endif //BOOST_INTRUSIVE_HASHSET_HOOK_HPP
+#endif //BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk