From 2ddf5b904b147ab1045c6a9f5357e8ff671ac3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 26 Sep 2007 15:26:35 +0000 Subject: [PATCH] Changes introduced by the new intrusive version. [SVN r39548] --- .../intrusive/circular_slist_algorithms.hpp | 1 + .../intrusive/derivation_value_traits.hpp | 7 +- .../boost/intrusive/detail/config_begin.hpp | 6 +- .../intrusive/detail/ebo_functor_holder.hpp | 2 +- .../boost/intrusive/detail/generic_hook.hpp | 185 +++ .../boost/intrusive/detail/hashtable_node.hpp | 302 ++--- include/boost/intrusive/detail/list_node.hpp | 220 ++-- include/boost/intrusive/detail/mpl.hpp | 128 +- .../detail/no_exceptions_support.hpp | 28 + .../intrusive/detail/parent_from_member.hpp | 13 +- .../boost/intrusive/detail/rbtree_node.hpp | 209 +-- include/boost/intrusive/detail/slist_node.hpp | 206 +-- .../intrusive/detail/transform_iterator.hpp | 173 +++ include/boost/intrusive/detail/utilities.hpp | 457 +++++-- include/boost/intrusive/hashtable.hpp | 1172 ++++++++++++----- include/boost/intrusive/intrusive_fwd.hpp | 205 +-- .../{linking_policy.hpp => link_mode.hpp} | 12 +- include/boost/intrusive/list.hpp | 578 +++++--- include/boost/intrusive/list_hook.hpp | 463 +++---- .../boost/intrusive/member_value_traits.hpp | 7 +- include/boost/intrusive/options.hpp | 429 ++++++ include/boost/intrusive/pointer_plus_bit.hpp | 4 +- include/boost/intrusive/rbtree.hpp | 706 +++++++--- include/boost/intrusive/rbtree_algorithms.hpp | 547 +++++++- include/boost/intrusive/set.hpp | 675 +++++++--- include/boost/intrusive/set_hook.hpp | 388 ++---- include/boost/intrusive/slist.hpp | 574 +++++--- include/boost/intrusive/slist_hook.hpp | 386 ++---- include/boost/intrusive/tag.hpp | 26 - .../boost/intrusive/trivial_value_traits.hpp | 12 +- include/boost/intrusive/unordered_set.hpp | 616 ++++++--- .../boost/intrusive/unordered_set_hook.hpp | 332 +++-- 32 files changed, 5852 insertions(+), 3217 deletions(-) create mode 100644 include/boost/intrusive/detail/generic_hook.hpp create mode 100644 include/boost/intrusive/detail/no_exceptions_support.hpp create mode 100644 include/boost/intrusive/detail/transform_iterator.hpp rename include/boost/intrusive/{linking_policy.hpp => link_mode.hpp} (86%) create mode 100644 include/boost/intrusive/options.hpp delete mode 100644 include/boost/intrusive/tag.hpp diff --git a/include/boost/intrusive/circular_slist_algorithms.hpp b/include/boost/intrusive/circular_slist_algorithms.hpp index cbb1d20..20dcafa 100644 --- a/include/boost/intrusive/circular_slist_algorithms.hpp +++ b/include/boost/intrusive/circular_slist_algorithms.hpp @@ -48,6 +48,7 @@ class circular_slist_algorithms public: typedef typename NodeTraits::node_ptr node_ptr; typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef NodeTraits node_traits; //! Requires: this_node must be in a circular list or be an empty circular list. //! diff --git a/include/boost/intrusive/derivation_value_traits.hpp b/include/boost/intrusive/derivation_value_traits.hpp index 5ff3bae..2036890 100644 --- a/include/boost/intrusive/derivation_value_traits.hpp +++ b/include/boost/intrusive/derivation_value_traits.hpp @@ -13,7 +13,7 @@ #ifndef BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP #define BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP -#include +#include #include namespace boost { @@ -22,7 +22,7 @@ namespace intrusive { //!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 +template struct derivation_value_traits { public: @@ -35,8 +35,7 @@ struct derivation_value_traits typedef typename boost::pointer_to_other::type const_pointer; typedef typename std::iterator_traits::reference reference; typedef typename std::iterator_traits::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); } diff --git a/include/boost/intrusive/detail/config_begin.hpp b/include/boost/intrusive/detail/config_begin.hpp index b4b20c6..f30069d 100644 --- a/include/boost/intrusive/detail/config_begin.hpp +++ b/include/boost/intrusive/detail/config_begin.hpp @@ -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 #endif -#define BOOST_INTRUSIVE_SELECT_COMPILER_INCLUDED -#endif #ifdef BOOST_MSVC diff --git a/include/boost/intrusive/detail/ebo_functor_holder.hpp b/include/boost/intrusive/detail/ebo_functor_holder.hpp index d58516f..69c50cd 100644 --- a/include/boost/intrusive/detail/ebo_functor_holder.hpp +++ b/include/boost/intrusive/detail/ebo_functor_holder.hpp @@ -35,7 +35,7 @@ class ebo_functor_holder_impl template class ebo_functor_holder_impl - : private T + : public T { public: ebo_functor_holder_impl(){} diff --git a/include/boost/intrusive/detail/generic_hook.hpp b/include/boost/intrusive/detail/generic_hook.hpp new file mode 100644 index 0000000..e01c5e9 --- /dev/null +++ b/include/boost/intrusive/detail/generic_hook.hpp @@ -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 +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +/// @cond + +enum +{ NoBaseHook +, ListBaseHook +, SlistBaseHook +, SetBaseHook +, UsetBaseHook +}; + +struct no_default_definer{}; + +template +struct default_definer; + +template +struct default_definer +{ typedef Hook default_list_hook; }; + +template +struct default_definer +{ typedef Hook default_slist_hook; }; + +template +struct default_definer +{ typedef Hook default_set_hook; }; + +template +struct default_definer +{ typedef Hook default_uset_hook; }; + +template +struct make_default_definer +{ + typedef typename detail::if_c + < BaseHookType != 0 + , default_definer + , 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 + ::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 + , detail::is_same::value*HookType + >::type + , public make_node_holder::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::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(this)); + } + } + + generic_hook(const generic_hook& ) + { + if(boost_intrusive_tags::safemode_or_autounlink){ + boost_intrusive_tags::node_algorithms::init + (static_cast(this)); + } + } + + generic_hook& operator=(const generic_hook& ) + { return *this; } + + ~generic_hook() + { + destructor_impl + (*this, detail::link_dispatch()); + } + + void swap_nodes(generic_hook &other) + { + boost_intrusive_tags::node_algorithms::swap_nodes + ( static_cast(this) + , static_cast(&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(this)); + } + + void unlink() + { + BOOST_STATIC_ASSERT(( (int)boost_intrusive_tags::link_mode == (int)auto_unlink )); + boost_intrusive_tags::node_algorithms::unlink + (static_cast(this)); + boost_intrusive_tags::node_algorithms::init + (static_cast(this)); + } +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_GENERIC_HOOK_HPP diff --git a/include/boost/intrusive/detail/hashtable_node.hpp b/include/boost/intrusive/detail/hashtable_node.hpp index 7e875cf..d10ad2c 100644 --- a/include/boost/intrusive/detail/hashtable_node.hpp +++ b/include/boost/intrusive/detail/hashtable_node.hpp @@ -18,14 +18,9 @@ #include #include #include -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE -#include -#endif -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE -#include -#include -#endif #include +#include +#include //remove-me #include namespace boost { @@ -52,27 +47,34 @@ template const std::size_t prime_list_holder::prime_list_size = sizeof(prime_list)/sizeof(std::size_t); -template -struct bucket_type_impl - : public SlistImpl +template +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(); } - - static typename std::iterator_traits - ::difference_type - get_bucket_num - ( typename SlistImpl::const_iterator it - , const bucket_type_impl &first_bucket - , const bucket_type_impl &last_bucket) + ~bucket_impl() { - typename SlistImpl::const_iterator + //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 Slist::difference_type get_bucket_num + ( typename Slist::const_iterator it + , const bucket_impl &first_bucket + , const bucket_impl &last_bucket) + { + 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 @@ struct bucket_type_impl it.pointed_node() <= last.pointed_node())){ ++it; } - //Now get the bucket_type_impl from the iterator - const bucket_type_impl &b = static_cast - (SlistImpl::container_from_end_iterator(it)); + //Now get the bucket_impl from the iterator + const bucket_impl &b = static_cast + (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 &b) - { return static_cast(b); } - - static const SlistImpl &bucket_to_slist(const bucket_type_impl &b) - { return static_cast(b); } }; -template -struct bucket_info_impl +template +struct bucket_traits_impl { + /// @cond typedef typename boost::pointer_to_other - < typename SlistImpl::pointer - , bucket_type_impl >::type bucket_ptr; - typedef typename SlistImpl::size_type size_type; + < typename Slist::pointer, bucket_impl >::type bucket_ptr; + typedef typename Slist::size_type size_type; + /// @endcond + + bucket_traits_impl(bucket_ptr buckets, size_type len) + : buckets_(buckets), buckets_len_(len) + {} + + bucket_ptr bucket_begin() const + { return buckets_; } + + size_type bucket_count() const + { return buckets_len_; } + + private: bucket_ptr buckets_; size_type buckets_len_; }; -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE - -template +template class hashtable_iterator - : public boost::iterator_facade - < hashtable_iterator - , Value - , boost::forward_traversal_tag - , Value& - , typename std::iterator_traits::difference_type + : public std::iterator + < std::forward_iterator_tag + , typename detail::add_const_if_c + ::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 bucket_type; + 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 - < 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 bucket_info_t; - typedef typename boost::pointer_to_other - ::type bucket_info_ptr; - typedef typename boost::pointer_to_other - ::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: - 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 - hashtable_iterator(hashtable_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : local_it_(other.local_it_), bucket_info_(other.bucket_info_) - {} - #else - template - hashtable_iterator(hashtable_iterator const& other, - typename enable_if< - is_convertible - >::type* = 0) - : local_it_(other.local_it_), bucket_info_(other.bucket_info_) - {} - #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_; } - - private: - friend class boost::iterator_core_access; - template friend class hashtable_iterator; - - template - bool equal(hashtable_iterator 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_; -}; - -#else - -template -class hashtable_iterator - : public std::iterator -{ - 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 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 bucket_info_t; - typedef typename boost::pointer_to_other - ::type bucket_info_ptr; - typedef typename boost::pointer_to_other - ::type const_bucket_info_ptr; - typedef typename SlistImpl::size_type size_type; - struct enabler {}; - - public: - typedef T & reference; - typedef T * pointer; + typedef typename detail::add_const_if_c + ::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 - hashtable_iterator(hashtable_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : local_it_(other.local_it_), bucket_info_(other.bucket_info_) + hashtable_iterator(const hashtable_iterator &other) + : slist_it_(other.slist_it()), cont_(other.get_container()) {} - #else - template - hashtable_iterator(hashtable_iterator const& other, - typename enable_if >::type* = 0) - : local_it_(other.local_it_), bucket_info_(other.bucket_info_) - {} - #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(); + 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()); - ++local_it_; - if(first.pointed_node() <= local_it_.pointed_node() && - local_it_.pointed_node() <= last.pointed_node()){ + ++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 { diff --git a/include/boost/intrusive/detail/list_node.hpp b/include/boost/intrusive/detail/list_node.hpp index 03c8927..ec48a6d 100644 --- a/include/boost/intrusive/detail/list_node.hpp +++ b/include/boost/intrusive/detail/list_node.hpp @@ -19,35 +19,31 @@ #include #include #include -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE -#include -#endif -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE -#include -#include -#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 +struct list_node +{ + typedef typename boost::pointer_to_other + ::type node_ptr; + node_ptr prev_, next_; +}; + template struct list_node_traits { - struct node; + typedef list_node node; typedef typename boost::pointer_to_other ::type node_ptr; typedef typename boost::pointer_to_other ::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 @@ struct list_node_traits { n->next_ = next; } }; -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE - -// list_iterator provides some basic functions for a -// node oriented forward iterator: -template -class list_iterator - : public boost::iterator_facade - < list_iterator - , T - , boost::bidirectional_traversal_tag - , T& - , typename std::iterator_traits::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::type pointer; - typedef typename std::iterator_traits::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 - list_iterator(list_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : node_(other.pointed_node()) - {} - #else - template - list_iterator(list_iterator const& other, - typename enable_if< - is_convertible - >::type* = 0) - : node_(other.pointed_node()) - {} - #endif - - const node_ptr &pointed_node() const - { return node_; } - - private: - friend class boost::iterator_core_access; - template friend class list_iterator; - - template - bool equal(list_iterator 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 +template class list_iterator - : public std::iterator + : public std::iterator + < std::bidirectional_iterator_tag + , typename detail::add_const_if_c + ::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 + ::type void_pointer; + static const bool store_container_ptr = + detail::store_cont_ptr_on_it::value; + public: - typedef T & reference; - typedef T * pointer; + typedef typename detail::add_const_if_c + + ::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 - list_iterator(list_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : node_(other.pointed_node()) + + list_iterator(list_iterator const& other) + : members_(other.pointed_node(), other.get_container()) {} - #else - template - list_iterator(list_iterator const& other, - typename enable_if< - is_convertible - >::type* = 0) - : node_(other.pointed_node()) - {} - #endif const node_ptr &pointed_node() const - { return node_; } + { return members_.nodeptr_; } list_iterator &operator=(const node_ptr &node) - { node_ = node; return static_cast(*this); } + { members_.nodeptr_ = node; return static_cast(*this); } public: list_iterator& operator++() { - node_ = node_traits::get_next(node_); + members_.nodeptr_ = node_traits::get_next(members_.nodeptr_); return static_cast (*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 (*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(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 + ::type + { + typedef typename detail::select_constptr + ::type Base; + + members(const node_ptr &n_ptr, const void *cont) + : Base(cont), nodeptr_(n_ptr) + {} + + node_ptr nodeptr_; + } members_; }; -#endif - -} //namespace detail } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/detail/mpl.hpp b/include/boost/intrusive/detail/mpl.hpp index 821c640..f4fd3f6 100644 --- a/include/boost/intrusive/detail/mpl.hpp +++ b/include/boost/intrusive/detail/mpl.hpp @@ -17,6 +17,9 @@ namespace boost { namespace intrusive { namespace detail { +typedef char one; +struct two {one _[2];}; + template< bool C_ > struct bool_ { @@ -55,7 +58,61 @@ class is_convertible 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 +{ + 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::type +{}; + +template< + typename C + , typename T1 + , typename T2 + > +struct eval_if + : if_::type +{}; + +// identity is an extension: it is not part of the standard. +template +struct identity +{ + typedef T type; }; #if defined(BOOST_MSVC) || defined(__BORLANDC_) @@ -130,18 +187,20 @@ yes_type is_function_ptr_tester(R (__cdecl*)( T0 , T1)); template 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 struct is_unary_or_binary_function_impl -{ enum {value = false }; }; +{ + static const bool value = false; +}; template struct is_unary_or_binary_function { - enum{ value = is_unary_or_binary_function_impl::value }; + static const bool value = is_unary_or_binary_function_impl::value; }; //boost::alignment_of yields to 10K lines of preprocessed code, so we @@ -159,15 +218,68 @@ struct alignment_of_hack template 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) - sizeof(T) - , sizeof(T)>::value }; + , sizeof(T) + >::value; +}; + +template +struct is_same +{ + typedef char yes_type; + struct no_type + { + char padding[8]; + }; + + template + 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 +struct add_const +{ typedef const T type; }; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +class is_empty_class +{ + template + 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) == sizeof(empty_helper_t2); }; } //namespace detail diff --git a/include/boost/intrusive/detail/no_exceptions_support.hpp b/include/boost/intrusive/detail/no_exceptions_support.hpp new file mode 100644 index 0000000..4344684 --- /dev/null +++ b/include/boost/intrusive/detail/no_exceptions_support.hpp @@ -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 +# 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 diff --git a/include/boost/intrusive/detail/parent_from_member.hpp b/include/boost/intrusive/detail/parent_from_member.hpp index c0225ae..4a5d48a 100644 --- a/include/boost/intrusive/detail/parent_from_member.hpp +++ b/include/boost/intrusive/detail/parent_from_member.hpp @@ -13,6 +13,7 @@ #define BOOST_INTRUSIVE_PARENT_FROM_MEMBER_HPP #include +#include #include namespace boost { @@ -22,14 +23,18 @@ namespace detail { template 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(&(parent->*ptr_to_member)); + return std::size_t(member - reinterpret_cast(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 } diff --git a/include/boost/intrusive/detail/rbtree_node.hpp b/include/boost/intrusive/detail/rbtree_node.hpp index 12eab42..55a9110 100644 --- a/include/boost/intrusive/detail/rbtree_node.hpp +++ b/include/boost/intrusive/detail/rbtree_node.hpp @@ -18,19 +18,11 @@ #include #include #include -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE -#include -#endif -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE -#include -#include -#endif #include #include namespace boost { namespace intrusive { -namespace detail { ///////////////////////////////////////////////////////////////////////////// // // @@ -164,14 +156,14 @@ struct rbtree_node_traits_dispatch : public compact_rbtree_node_traits_impl {}; -//Inherit from the dispatcher depending on the embedding capabilities +//Inherit from the detail::link_dispatch depending on the embedding capabilities template struct rbtree_node_traits : public rbtree_node_traits_dispatch - - >::value + < VoidPointer + , has_pointer_plus_bit + < VoidPointer + , detail::alignment_of >::value >::value > {}; @@ -182,179 +174,124 @@ struct rbtree_node_traits // // ///////////////////////////////////////////////////////////////////////////// -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE - -template -class rbtree_iterator - : public boost::iterator_facade - < rbtree_iterator - , T - , boost::bidirectional_traversal_tag - , T& - , typename std::iterator_traits::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_algorithms; - struct enabler{}; - - public: - typedef typename pointer_to_other::type pointer; - typedef typename std::iterator_traits::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 - rbtree_iterator(rbtree_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : node_(other.pointed_node()) - {} - #else - template - rbtree_iterator(rbtree_iterator const& other, - typename enable_if< - is_convertible - >::type* = 0) - : node_(other.pointed_node()) - {} - #endif - - const node_ptr &pointed_node() const - { return node_; } - - private: - friend class boost::iterator_core_access; - template friend class rbtree_iterator; - - template - bool equal(rbtree_iterator 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 +template class rbtree_iterator - : public std::iterator + : public std::iterator + < std::bidirectional_iterator_tag + , typename detail::add_const_if_c + ::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_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_algorithms; + typedef typename boost::pointer_to_other + ::type void_pointer; + static const bool store_container_ptr = + detail::store_cont_ptr_on_it::value; + public: - typedef T & reference; - typedef T * pointer; + public: + typedef typename detail::add_const_if_c + + ::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 - rbtree_iterator(rbtree_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : node_(other.pointed_node()) + rbtree_iterator(rbtree_iterator const& other) + : members_(other.pointed_node(), other.get_container()) {} - #else - template - rbtree_iterator(rbtree_iterator const& other, - typename enable_if< - is_convertible - >::type* = 0) - : node_(other.pointed_node()) - {} - #endif const node_ptr &pointed_node() const - { return node_; } + { return members_.nodeptr_; } rbtree_iterator &operator=(const node_ptr &node) - { node_ = node; return static_cast(*this); } + { members_.nodeptr_ = node; return static_cast(*this); } public: rbtree_iterator& operator++() { - node_ = node_algorithms::next_node(node_); + members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_); return static_cast (*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 (*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(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 + ::type + { + typedef typename detail::select_constptr + ::type Base; + + members(const node_ptr &n_ptr, const void *cont) + : Base(cont), nodeptr_(n_ptr) + {} + + node_ptr nodeptr_; + } members_; }; -#endif - -} //namespace detail } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/detail/slist_node.hpp b/include/boost/intrusive/detail/slist_node.hpp index a22c117..a5d8883 100644 --- a/include/boost/intrusive/detail/slist_node.hpp +++ b/include/boost/intrusive/detail/slist_node.hpp @@ -19,17 +19,17 @@ #include #include #include -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE -#include -#endif -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE -#include -#include -#endif namespace boost { namespace intrusive { -namespace detail { + +template +struct slist_node +{ + typedef typename boost::pointer_to_other + ::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 @@ namespace detail { template struct slist_node_traits { - struct node; - + typedef slist_node node; typedef typename boost::pointer_to_other ::type node_ptr; typedef typename boost::pointer_to_other ::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 @@ struct slist_node_traits { n->next_ = next; } }; -#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE - -// slist_iterator provides some basic functions for a -// node oriented forward iterator: -template -class slist_iterator - : public boost::iterator_facade - < slist_iterator - , T - , boost::forward_traversal_tag - , T& - , typename std::iterator_traits::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::type pointer; - typedef typename std::iterator_traits::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 - slist_iterator(slist_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : node_(other.pointed_node()) - {} - #else - template - slist_iterator(slist_iterator const& other, - typename enable_if< - is_convertible - >::type* = 0) - : node_(other.pointed_node()) - {} - #endif - - const node_ptr &pointed_node() const - { return node_; } - - private: - friend class boost::iterator_core_access; - template friend class slist_iterator; - - template - bool equal(slist_iterator 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 +template class slist_iterator - : public std::iterator + : public std::iterator + < std::forward_iterator_tag + , typename detail::add_const_if_c + ::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 + ::type void_pointer; + static const bool store_container_ptr = + detail::store_cont_ptr_on_it::value; + public: - typedef T & reference; - typedef T * pointer; + typedef typename detail::add_const_if_c + + ::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 - slist_iterator(slist_iterator const& other - ,typename boost::enable_if< - boost::is_convertible - , enabler - >::type = enabler() - ) - : node_(other.pointed_node()) + slist_iterator(slist_iterator const& other) + : members_(other.pointed_node(), other.get_container()) {} - #else - template - slist_iterator(slist_iterator const& other, - typename enable_if< - is_convertible - >::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(*this); } + { members_.nodeptr_ = node; return static_cast(*this); } public: slist_iterator& operator++() { - node_ = node_traits::get_next(node_); + members_.nodeptr_ = node_traits::get_next(members_.nodeptr_); return static_cast (*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(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 + ::type + { + typedef typename detail::select_constptr + ::type Base; + + members(const node_ptr &n_ptr, const void *cont) + : Base(cont), nodeptr_(n_ptr) + {} + + node_ptr nodeptr_; + } members_; }; -#endif - -} //namespace detail } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/detail/transform_iterator.hpp b/include/boost/intrusive/detail/transform_iterator.hpp new file mode 100644 index 0000000..f5fe05c --- /dev/null +++ b/include/boost/intrusive/detail/transform_iterator.hpp @@ -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 +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +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 +struct operator_arrow_proxy +{ + 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 transform_iterator + : public std::iterator + < typename Iterator::iterator_category + , typename detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , 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 + operator->() const + { return operator_arrow_proxy(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 + +#endif //BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index 5b95f29..92449a8 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,6 +26,64 @@ namespace boost { namespace intrusive { namespace detail { +template +struct internal_member_value_traits +{ + template static detail::one test(...); + template static detail::two test(typename U::member_value_traits* = 0); + static const bool value = sizeof(test(0)) == sizeof(detail::two); +}; + +template +struct internal_base_hook_bool +{ + template + struct two_or_three {one _[2 + Add];}; + template static one test(...); + template static two_or_three + test (detail::bool_* = 0); + static const int value = sizeof(test(0)); +}; + +template +struct internal_base_hook_bool_is_true +{ + static const bool value = internal_base_hook_bool::value == 3; +}; + +template +struct external_value_traits_bool +{ + template + struct two_or_three {one _[2 + Add];}; + template static one test(...); + template static two_or_three + test (detail::bool_* = 0); + static const int value = sizeof(test(0)); +}; + +template +struct external_bucket_traits_bool +{ + template + struct two_or_three {one _[2 + Add];}; + template static one test(...); + template static two_or_three + test (detail::bool_* = 0); + static const int value = sizeof(test(0)); +}; + +template +struct external_value_traits_is_true +{ + static const bool value = external_value_traits_bool::value == 3; +}; + +template +struct node_holder + : public Node +{}; + template struct smart_ptr_type { @@ -49,7 +107,6 @@ template inline typename smart_ptr_type::pointer get_pointer(const Ptr &ptr) { return smart_ptr_type::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 @@ class null_disposer {} }; +template +class init_disposer +{ + typedef typename NodeAlgorithms::node_ptr node_ptr; + + public: + void operator()(node_ptr p) + { NodeAlgorithms::init(p); } +}; + template 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 @@ struct size_holder template struct size_holder { - enum { constant_time_size = false }; + static const bool constant_time_size = false; typedef SizeType size_type; size_type get_size() const @@ -115,11 +182,235 @@ struct size_holder {} }; -template -struct derivation_hook_value_traits +template +struct key_nodeptr_comp + : private detail::ebo_functor_holder +{ + typedef typename Container::real_value_traits real_value_traits; + typedef typename real_value_traits::node_ptr node_ptr; + typedef detail::ebo_functor_holder base_t; + key_nodeptr_comp(KeyValueCompare kcomp, const Container *cont) + : base_t(kcomp), cont_(cont) + {} + + template + bool operator()(node_ptr node, const KeyType &key) const + { return base_t::get()(*cont_->get_real_value_traits().to_value_ptr(node), key); } + + template + bool operator()(const KeyType &key, node_ptr node) const + { return base_t::get()(key, *cont_->get_real_value_traits().to_value_ptr(node)); } + + 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) + ); + } + + const Container *cont_; +}; + +template +struct node_cloner + : private detail::ebo_functor_holder +{ + 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 base_t; + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + node_cloner(F f, const Container *cont) + : base_t(f), cont_(cont) + {} + + node_ptr operator()(node_ptr p) + { + node_ptr n = cont_->get_real_value_traits().to_node_ptr + (*base_t::get()(*cont_->get_real_value_traits().to_value_ptr(p))); + //Cloned node must be in default mode if the linking mode requires it + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n)); + return n; + } + + node_ptr operator()(const node &to_clone) + { + 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; + } + + const Container *cont_; +}; + +template +struct node_disposer + : private detail::ebo_functor_holder +{ + typedef typename Container::real_value_traits real_value_traits; + typedef typename real_value_traits::node_ptr node_ptr; + typedef detail::ebo_functor_holder 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) + { + if(safemode_or_autounlink) + node_algorithms::init(p); + base_t::get()(cont_->get_real_value_traits().to_value_ptr(p)); + } + const Container *cont_; +}; + +struct dummy_constptr +{ + dummy_constptr(const void *) + {} + + const void *get_ptr() const + { return 0; } +}; + +template +struct constptr +{ + typedef typename boost::pointer_to_other + ::type ConstVoidPtr; + + constptr(const void *ptr) + : const_void_ptr_(ptr) + {} + + const void *get_ptr() const + { return detail::get_pointer(const_void_ptr_); } + + ConstVoidPtr const_void_ptr_; +}; + +template +struct select_constptr +{ + typedef typename detail::if_c + < store_ptr + , constptr + , dummy_constptr + >::type type; +}; + +template +struct store_cont_ptr_on_it +{ + typedef typename Container::value_traits value_traits; + static const bool value = + !detail::is_empty_class::value + || detail::external_value_traits_is_true::value + ; +}; + +template +struct add_const_if_c +{ + typedef typename detail::if_c + < Add + , typename detail::add_const::type + , T + >::type type; +}; + +template +struct node_to_value + : public detail::select_constptr + < typename boost::pointer_to_other + ::type + , detail::store_cont_ptr_on_it::value + >::type +{ + static const bool store_container_ptr = + detail::store_cont_ptr_on_it::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 + ::type + , store_container_ptr >::type Base; + typedef typename real_value_traits::node_traits::node node; + typedef typename detail::add_const_if_c + ::type vtype; + typedef typename detail::add_const_if_c + ::type ntype; + typedef typename boost::pointer_to_other + ::type npointer; + + node_to_value(const Container *cont) + : Base(cont) + {} + + typedef vtype & result_type; + typedef ntype & first_argument_type; + + const Container *get_container() const + { + if(store_container_ptr) + return static_cast(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 +struct link_dispatch +{}; + +template +void destructor_impl(Container &cont, detail::link_dispatch) +{ (void)cont; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!cont.is_linked()); } + +template +void destructor_impl(Container &cont, detail::link_dispatch) +{ cont.unlink(); } + +template +void destructor_impl(Container &, detail::link_dispatch) +{} + +template +struct base_hook_traits { public: - typedef typename DerivationHookType::node_traits node_traits; + typedef detail::node_holder + 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; @@ -127,173 +418,61 @@ struct derivation_hook_value_traits typedef typename boost::pointer_to_other::type const_pointer; typedef typename std::iterator_traits::reference reference; typedef typename std::iterator_traits::reference const_reference; - enum { linking_policy = DerivationHookType::linking_policy }; + static const link_mode_type link_mode = LinkMode; static node_ptr to_node_ptr(reference value) - { return static_cast(value).to_node_ptr(); } + { return static_cast(&value); } static const_node_ptr to_node_ptr(const_reference value) - { return static_cast(value).to_node_ptr(); } + { return static_cast(&value); } static pointer to_value_ptr(node_ptr n) - { - return static_cast(detail::get_pointer(DerivationHookType::to_hook_ptr(n))); - } + { return static_cast(static_cast(&*n)); } static const_pointer to_value_ptr(const_node_ptr n) - { - return static_cast(detail::get_pointer(DerivationHookType::to_hook_ptr(n))); - } + { return static_cast(static_cast(&*n)); } }; - -template -struct member_hook_value_traits +template +struct member_hook_traits { public: - typedef typename MemberHookType::node_traits node_traits; + 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::type pointer; typedef typename boost::pointer_to_other::type const_pointer; - typedef value_type & reference; - typedef const value_type & const_reference; - enum { linking_policy = MemberHookType::linking_policy }; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + static const link_mode_type link_mode = Hook::boost_intrusive_tags::link_mode; - public: static node_ptr to_node_ptr(reference value) { - MemberHookType* result = &(value.*P); - return result->to_node_ptr(); + return reinterpret_cast(&(value.*P)); } static const_node_ptr to_node_ptr(const_reference value) { - const MemberHookType* result = &(value.*P); - return result->to_node_ptr(); + return static_cast(&(value.*P)); } static pointer to_value_ptr(node_ptr n) { - return pointer - ( - parent_from_member - (detail::get_pointer(MemberHookType::to_hook_ptr(n)), P) - ); + return detail::parent_from_member + (static_cast(detail::get_pointer(n)), P); } static const_pointer to_value_ptr(const_node_ptr n) { - return const_pointer - ( - parent_from_member - (detail::get_pointer(MemberHookType::to_hook_ptr(n)), P) - ); + return detail::parent_from_member + (static_cast(detail::get_pointer(n)), P); } }; -template -struct key_node_ptr_compare - : private detail::ebo_functor_holder -{ - typedef typename ValueTraits::node_ptr node_ptr; - typedef detail::ebo_functor_holder base_t; - key_node_ptr_compare(KeyValueCompare kcomp) - : base_t(kcomp) - {} - - template - bool operator()(node_ptr node, const KeyType &key) const - { return base_t::get()(*ValueTraits::to_value_ptr(node), key); } - - template - 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)); - } -}; - -template -struct value_to_node_cloner - : private detail::ebo_functor_holder -{ - typedef typename ValueTraits::node_ptr node_ptr; - typedef detail::ebo_functor_holder base_t; - - value_to_node_cloner(F f) - : base_t(f) - {} - - node_ptr operator()(node_ptr p) - { return ValueTraits::to_node_ptr(*base_t::get()(*ValueTraits::to_value_ptr(p))); } -}; - -template -struct value_to_node_disposer - : private detail::ebo_functor_holder -{ - typedef typename ValueTraits::node_ptr node_ptr; - typedef detail::ebo_functor_holder base_t; - value_to_node_disposer(F f) - : base_t(f) - {} - - void operator()(node_ptr p) - { base_t::get()(ValueTraits::to_value_ptr(p)); } -}; - -template -struct dispatcher -{}; - -template -void destructor_impl(Container &cont, dispatcher) -{ (void)cont; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!cont.is_linked()); } - -template -void destructor_impl(Container &cont, dispatcher) -{ cont.unlink(); } - -template -void destructor_impl(Container &, dispatcher) -{} - -template -struct node_plus_pred - : public ebo_functor_holder - , public Node -{ - node_plus_pred() - {} - - node_plus_pred(const Node &x, const MaybeClass &y) - : Node(x), ebo_functor_holder(y) {} - - node_plus_pred(const MaybeClass &y) - : ebo_functor_holder(y) {} - - Node &first() - { return *this; } - const Node &first() const - { return *this; } - MaybeClass &second() - { return ebo_functor_holder::get(); } - const MaybeClass &second() const - { return ebo_functor_holder::get(); } - - static node_plus_pred *this_from_node(Node *n) - { return static_cast(n); } - - static node_plus_pred *this_from_node(const Node *n) - { return static_cast(n); } -}; - -} //namespace detail +} //namespace detail } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index e9bcd4c..1eeb2ff 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -22,156 +22,390 @@ #include #include #include -#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING -#include -#endif +#include //General intrusive utilities #include #include #include -#include +#include +#include #include //Implementation utilities +#include #include #include namespace boost { namespace intrusive { +/// @cond + +namespace detail{ + +template +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 +struct bucket_hash_t : public detail::ebo_functor_holder +{ + 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(h), bucket_plus_size_(b_traits) + {} + + bucket_plus_size bucket_plus_size_; +}; + +template +struct bucket_hash_equal_t : public detail::ebo_functor_holder +{ + 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(e), bucket_hash(b_traits, h) + {} + bucket_hash_t bucket_hash; +}; + +template +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 bucket_hash_equal_; +}; + +} //namespace detail { + +template +struct internal_default_uset_hook +{ + template static detail::one test(...); + template static detail::two test(typename U::default_uset_hook* = 0); + static const bool value = sizeof(test(0)) == sizeof(detail::two); +}; + +template +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 +struct uset_defaults + : pack_options + < none + , base_hook + < typename detail::eval_if_c + < internal_default_uset_hook::value + , get_default_uset_hook + , detail::identity + >::type + > + , constant_time_size + , size_type + , equal > + , hash > + , bucket_traits + , power_2_buckets + >::type +{}; + +template +struct get_slist_impl +{ + typedef trivial_value_traits trivial_traits; + + //Reducing symbol length + struct type : make_slist + < typename NodeTraits::node + , boost::intrusive::value_traits + , boost::intrusive::constant_time_size + , boost::intrusive::size_type + >::type + {}; +}; + +/// @endcond + +template +struct unordered_bucket +{ + /// @cond + typedef typename ValueTraitsOrHookOption:: + template pack::value_traits supposed_value_traits; + + typedef typename detail::eval_if_c + < detail::external_value_traits_is_true + ::value + , detail::eval_value_traits + + , detail::identity + + >::type real_value_traits; + + typedef typename detail::get_node_traits + ::type node_traits; + typedef typename get_slist_impl + ::type slist_impl; + typedef detail::bucket_impl implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +template +struct unordered_bucket_ptr +{ + /// @cond + typedef typename ValueTraitsOrHookOption:: + template pack::value_traits supposed_value_traits; + typedef typename detail::eval_if_c + < detail::external_value_traits_is_true + ::value + , detail::eval_value_traits + + , detail::identity + + >::type real_value_traits; + typedef typename detail::get_node_traits + ::type::node_ptr node_ptr; + typedef typename unordered_bucket + ::type bucket_type; + typedef typename boost::pointer_to_other + ::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 - , class Equal //= std::equal_to - , bool ConstantTimeSize //= true - , class SizeType //= std::size_t - > -class hashtable - : private detail::size_holder +//! +//! 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 +#else +template +#endif +class hashtable_impl + : private detail::data_t { - /// @cond - private: - typedef slist slist_impl; - typedef hashtable this_type; - typedef typename ValueTraits::node_traits node_traits; - typedef detail::size_holder size_traits; + public: + typedef typename Config::value_traits value_traits; - //noncopyable - hashtable (const hashtable&); - hashtable operator =(const hashtable&); + /// @cond + + static const bool external_value_traits = + detail::external_value_traits_is_true::value; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::type real_value_traits; + typedef typename Config::bucket_traits bucket_traits; + static const bool external_bucket_traits = + detail::external_bucket_traits_is_true::value; + typedef typename detail::eval_if_c + < external_bucket_traits + , detail::eval_bucket_traits + , detail::identity + >::type real_bucket_traits; + typedef typename get_slist_impl + ::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::reference reference; - typedef typename std::iterator_traits::reference const_reference; - typedef typename std::iterator_traits::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 bucket_type; + typedef typename real_value_traits::pointer pointer; + typedef typename real_value_traits::const_pointer const_pointer; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::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 bucket_type; typedef typename boost::pointer_to_other - ::type bucket_ptr; - typedef typename slist_impl::iterator local_iterator; - typedef typename slist_impl::const_iterator const_local_iterator; + ::type bucket_ptr; + typedef typename slist_impl::iterator siterator; + typedef typename slist_impl::const_iterator const_siterator; + typedef detail::hashtable_iterator iterator; + typedef detail::hashtable_iterator const_iterator; + typedef typename real_value_traits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef typename slist_impl::node_algorithms node_algorithms; - typedef detail::hashtable_iterator iterator; - typedef detail::hashtable_iterator const_iterator; + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; /// @cond private: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; + typedef detail::size_holder size_traits; + typedef detail::data_t base_type; + typedef detail::transform_iterator + < typename slist_impl::iterator + , detail::node_to_value > local_iterator_impl; + typedef detail::transform_iterator + < typename slist_impl::iterator + , detail::node_to_value > 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 bucket_info_t; - typedef typename boost::pointer_to_other - ::type bucket_info_ptr; - typedef typename boost::pointer_to_other - ::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 -// -// ,Equal> members_; - struct bucket_hash_t - : public detail::ebo_functor_holder - { - bucket_hash_t(const Hash & h) - : detail::ebo_functor_holder(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_()); } - struct bucket_hash_equal_t - : public detail::ebo_functor_holder - { - bucket_hash_equal_t(const Hash & h, const Equal &e) - : detail::ebo_functor_holder(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_) const + { return hash_value % this->get_real_bucket_traits().bucket_count(); } - const Equal &priv_equal() const - { return static_cast(bucket_hash_equal_.get()); } + std::size_t from_hash_to_bucket(std::size_t hash_value, detail::bool_) const + { return hash_value & (this->get_real_bucket_traits().bucket_count() - 1); } - Equal &priv_equal() - { return static_cast(bucket_hash_equal_.get()); } + const key_equal &priv_equal() const + { return static_cast(this->bucket_hash_equal_.get()); } - const bucket_info_t &priv_bucket_info() const - { return bucket_hash_equal_.bucket_hash.bucket_info; } + key_equal &priv_equal() + { return static_cast(this->bucket_hash_equal_.get()); } - bucket_info_t &priv_bucket_info() - { return bucket_hash_equal_.bucket_hash.bucket_info; } + const real_bucket_traits &get_real_bucket_traits(detail::bool_) const + { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; } - const Hash &priv_hasher() const - { return static_cast(bucket_hash_equal_.bucket_hash.get()); } + const real_bucket_traits &get_real_bucket_traits(detail::bool_) const + { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); } - Hash &priv_hasher() - { return static_cast(bucket_hash_equal_.bucket_hash.get()); } + real_bucket_traits &get_real_bucket_traits(detail::bool_) + { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_; } - const bucket_ptr &priv_buckets() const - { return priv_bucket_info().buckets_; } + real_bucket_traits &get_real_bucket_traits(detail::bool_) + { return this->bucket_hash_equal_.bucket_hash.bucket_plus_size_.bucket_traits_.get_bucket_traits(*this); } - bucket_ptr &priv_buckets() - { return priv_bucket_info().buckets_; } + const real_bucket_traits &get_real_bucket_traits() const + { return this->get_real_bucket_traits(detail::bool_()); } - const size_type &priv_buckets_len() const - { return priv_bucket_info().buckets_len_; } + real_bucket_traits &get_real_bucket_traits() + { return this->get_real_bucket_traits(detail::bool_()); } - size_type &priv_buckets_len() - { return priv_bucket_info().buckets_len_; } + const hasher &priv_hasher() const + { return static_cast(this->bucket_hash_equal_.bucket_hash.get()); } + + hasher &priv_hasher() + { return static_cast(this->bucket_hash_equal_.bucket_hash.get()); } + + bucket_ptr priv_buckets() const + { return this->get_real_bucket_traits().bucket_begin(); } + + 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(detail::get_pointer(ptr))); } -// static bucket_info_ptr uncast(const_bucket_info_ptr ptr) -// { -// return bucket_info_ptr(const_cast(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(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(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 @@ class hashtable /// @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_) const + { return *this; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return base_type::get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return *this; } + + real_value_traits &get_real_value_traits(detail::bool_) + { 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_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + //! Requires: buckets must not be being used by any other resource. //! //! Effects: 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. //! //! Complexity: Constant. //! //! Throws: 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. //! //! Notes: 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)))); } //! Effects: Detaches all elements from this. The objects in the unordered_set @@ -216,7 +499,7 @@ class hashtable //! it's a safe-mode or auto-unlink value. Otherwise constant. //! //! Throws: Nothing. - ~hashtable() + ~hashtable_impl() { this->clear(); } //! Effects: Returns an iterator pointing to the beginning of the unordered_set. @@ -228,8 +511,7 @@ class hashtable 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); } //! Effects: Returns a const_iterator pointing to the beginning @@ -240,7 +522,7 @@ class hashtable //! //! Throws: Nothing. const_iterator begin() const - { return cbegin(); } + { return this->cbegin(); } //! Effects: Returns a const_iterator pointing to the beginning //! of the unordered_set. @@ -252,8 +534,7 @@ class hashtable 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); } //! Effects: Returns an iterator pointing to the end of the unordered_set. @@ -262,7 +543,7 @@ class hashtable //! //! Throws: Nothing. iterator end() - { return iterator(invalid_local_it(this->priv_bucket_info()), 0); } + { return iterator(invalid_local_it(this->get_real_bucket_traits()), 0); } //! Effects: Returns a const_iterator pointing to the end of the unordered_set. //! @@ -270,7 +551,7 @@ class hashtable //! //! Throws: Nothing. const_iterator end() const - { return cend(); } + { return this->cend(); } //! Effects: Returns a const_iterator pointing to the end of the unordered_set. //! @@ -278,7 +559,7 @@ class hashtable //! //! Throws: 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); } //! Effects: Returns the hasher object used by the unordered_set. //! @@ -298,15 +579,15 @@ class hashtable //! Effects: Returns true is the container is empty. //! - //! Complexity: if ConstantTimeSize is false, average constant time + //! Complexity: if constant_time_size is false, average constant time //! (worst case, with empty() == true): O(this->bucket_count()). //! Otherwise constant. //! //! Throws: 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 @@ class hashtable //! Effects: Returns the number of elements stored in the unordered_set. //! //! Complexity: Linear to elements contained in *this if - //! ConstantTimeSize is false. Constant-time otherwise. + //! constant_time_size is false. Constant-time otherwise. //! //! Throws: 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 @@ class hashtable //! //! Throws: 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 @@ class hashtable //! //! Throws: If cloner throws. Basic guarantee. template - 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 @@ class hashtable 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, this) + , detail::node_disposer(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, 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, 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 @@ -488,10 +777,12 @@ class hashtable std::pair insert_unique(reference value) { insert_commit_data commit_data; - std::pair ret = insert_unique_check(value, this->priv_hasher(), this->priv_equal(), commit_data); + std::pair ret = this->insert_unique_check + (value, this->priv_hasher(), this->priv_equal(), commit_data); if(!ret.second) return ret; - return std::pair (insert_unique_commit(value, commit_data), true); + return std::pair + (this->insert_unique_commit(value, commit_data), true); } //! Requires: Dereferencing iterator must yield an lvalue @@ -513,13 +804,13 @@ class hashtable this->insert_unique(*b); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: 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 @@ class hashtable //! //! Complexity: Average case O(1), worst case O(this->size()). //! - //! Throws: If hasher or key_value_equal throw. Strong guarantee. + //! Throws: If hash_func or equal_func throw. Strong guarantee. //! //! Notes: This function is used to improve performance when constructing //! a value_type is expensive: if there is an equivalent value @@ -551,20 +842,18 @@ class hashtable template std::pair 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(prev_pos, const_bucket_info_ptr(&this->priv_bucket_info())) - ,success); + return std::pair(iterator(prev_pos, this),success); } //! Requires: value must be an lvalue of type value_type. commit_data @@ -588,11 +877,13 @@ class hashtable //! 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); } //! Effects: Erases the element pointed to by i. @@ -604,7 +895,7 @@ class hashtable //! Note: 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()); } //! Effects: Erases the range pointed to by b end e. //! @@ -616,7 +907,7 @@ class hashtable //! Note: 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()); } //! Effects: Erases all the elements with the given value. //! @@ -625,20 +916,21 @@ class hashtable //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! Throws: If the internal hasher or the equality functor throws. + //! Basic guarantee. //! //! Note: 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()); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Erases all the elements that have the same hash and //! compare equal with the given key. @@ -648,13 +940,13 @@ class hashtable //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If hasher or equal throw. Basic guarantee. + //! Throws: If hash_func or equal_func throw. Basic guarantee. //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - 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()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -670,11 +962,12 @@ class hashtable template 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, this)); + this->priv_size_traits().decrement(); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -696,12 +989,12 @@ class hashtable //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 @@ class hashtable 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 @@ class hashtable //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, this)); + this->priv_size_traits().decrement(); } } @@ -731,23 +1026,26 @@ class hashtable 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, 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, this)); + this->priv_size_traits().decrement(); } } } @@ -762,18 +1060,19 @@ class hashtable //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! Throws: If the internal hasher or the equality functor throws. + //! Basic guarantee. //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template 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); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: 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. //! //! Returns: The number of erased elements. @@ -781,28 +1080,30 @@ class hashtable //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If hasher or key_value_equal throw. Basic guarantee. + //! Throws: If hash_func or equal_func throw. Basic guarantee. //! //! Note: Invalidates the iterators //! to the erased elements. template - 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 @@ class hashtable 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, this)); + this->priv_size_traits().decrement(); } return count; } @@ -832,10 +1136,8 @@ class hashtable //! 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)); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -852,13 +1154,14 @@ class hashtable template 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, this)); } - size_traits::set_size(size_type(0)); + this->priv_size_traits().set_size(size_type(0)); } } @@ -870,24 +1173,24 @@ class hashtable size_type count(const_reference value) const { return this->count(value, this->priv_hasher(), this->priv_equal()); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns the number of contained elements with the given key //! //! Complexity: Average case O(1), worst case O(this->size()). //! - //! Throws: If hasher or equal throw. + //! Throws: If hash_func or equal throw. template - 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 @@ class hashtable //! //! Throws: 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()); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: 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. //! //! Complexity: Average case O(1), worst case O(this->size()). //! - //! Throws: If hasher or equal throw. + //! Throws: If hash_func or equal_func throw. //! //! Note: 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 - 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); } //! Effects: Finds a const_iterator to the first element whose key is @@ -935,15 +1237,15 @@ class hashtable //! //! Throws: 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()); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: 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 @@ class hashtable //! //! Complexity: Average case O(1), worst case O(this->size()). //! - //! Throws: If hasher or equal throw. + //! Throws: If hash_func or equal_func throw. //! //! Note: 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 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); } //! Effects: Returns a range containing all elements with values equivalent @@ -976,36 +1277,35 @@ class hashtable std::pair equal_range(const_reference value) { return this->equal_range(value, this->priv_hasher(), this->priv_equal()); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns a range containing all elements with equivalent //! keys. Returns std::make_pair(this->end(), this->end()) if no such //! elements exist. //! - //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! Complexity: Average case O(this->count(key, hash_func, equal_func)). + //! Worst case O(this->size()). //! - //! Throws: If hasher or the equal throw. + //! Throws: If hash_func or the equal_func throw. //! //! Note: 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 std::pair 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 ret - = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count); - const_bucket_info_ptr info_ptr (&this->priv_bucket_info()); + std::pair ret = this->priv_equal_range + (key, hash_func, equal_func, bucket_n1, bucket_n2, count); return std::pair - ( iterator( ret.first, info_ptr) - , iterator( ret.second, info_ptr) ); + (iterator(ret.first, this), iterator(ret.second, this)); } //! Effects: Returns a range containing all elements with values equivalent @@ -1019,36 +1319,35 @@ class hashtable equal_range(const_reference value) const { return this->equal_range(value, this->priv_hasher(), this->priv_equal()); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns a range containing all elements with equivalent //! keys. Returns std::make_pair(this->end(), this->end()) if no such //! elements exist. //! - //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! Complexity: Average case O(this->count(key, hash_func, equal_func)). + //! Worst case O(this->size()). //! - //! Throws: If the hasher or equal throw. + //! Throws: If the hasher or equal_func throw. //! //! Note: 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 std::pair 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 ret - = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count); - const_bucket_info_ptr info_ptr (&this->priv_bucket_info()); + std::pair ret = + this->priv_equal_range(key, hash_func, equal_func, bucket_n1, bucket_n2, count); return std::pair - ( const_iterator( ret.first, info_ptr) - , const_iterator( ret.second, info_ptr) ); + (const_iterator(ret.first, this), const_iterator(ret.second, this)); } //! Requires: value must be an lvalue and shall be in a unordered_set of @@ -1062,8 +1361,7 @@ class hashtable //! Throws: 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); } //! Requires: value must be an lvalue and shall be in a unordered_set of @@ -1077,8 +1375,48 @@ class hashtable //! Throws: If the internal hash function throws. const_iterator iterator_to(const_reference value) const { - return const_iterator( bucket_type::iterator_to(const_cast(value)) - , const_bucket_info_ptr(&this->priv_bucket_info())); + return const_iterator(bucket_type::s_iterator_to(from_value_to_node(const_cast(value))), this); + } + + + + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid local_iterator belonging to the unordered_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! 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); + } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_local_iterator belonging to + //! the unordered_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! 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))); + return const_local_iterator(sit, (hashtable_impl*)0); } //! Requires: value must be an lvalue and shall be in a unordered_set of @@ -1090,8 +1428,11 @@ class hashtable //! Complexity: Constant. //! //! Throws: Nothing. - static local_iterator local_iterator_to(reference value) - { return bucket_type::iterator_to(value); } + 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); + } //! Requires: value must be an lvalue and shall be in a unordered_set of //! appropriate type. Otherwise the behavior is undefined. @@ -1102,8 +1443,12 @@ class hashtable //! Complexity: Constant. //! //! Throws: Nothing. - static const_local_iterator local_iterator_to(const_reference value) - { return bucket_type::iterator_to(value); } + const_local_iterator local_iterator_to(const_reference value) const + { + siterator sit = bucket_type::s_iterator_to + (const_cast(this->from_value_to_node(value))); + return const_local_iterator(sit, this); + } //! Effects: Returns the number of buckets passed in the constructor //! or the last rehash function. @@ -1135,21 +1480,21 @@ class hashtable size_type bucket(const key_type& k) const { return this->bucket(k, this->priv_hasher()); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns the index of the bucket in which elements //! with keys equivalent to k would be found, if any such element existed. //! //! Complexity: Constant. //! - //! Throws: If hasher throws. + //! Throws: If hash_func throws. //! //! Note: the return value is in the range [0, this->bucket_count()). template - 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)); } //! Effects: Returns the bucket array pointer passed in the constructor //! or the last rehash function. @@ -1172,7 +1517,7 @@ class hashtable //! Note: [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); } //! Requires: n is in the range [0, this->bucket_count()). //! @@ -1200,7 +1545,10 @@ class hashtable //! Note: [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(this->priv_buckets()[n]).begin(); } + { + siterator sit = const_cast(this->priv_buckets()[n]).begin(); + return const_local_iterator(sit, this); + } //! Requires: n is in the range [0, this->bucket_count()). //! @@ -1214,7 +1562,7 @@ class hashtable //! Note: [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); } //! Requires: n is in the range [0, this->bucket_count()). //! @@ -1242,7 +1590,7 @@ class hashtable //! Note: [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(this->priv_buckets()[n]).end(); } + { return const_local_iterator(const_cast(this->priv_buckets()[n]).end(), this); } //! Requires: 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 @@ class hashtable //! Complexity: Average case linear in this->size(), worst case quadratic. //! //! Throws: 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 @@ class hashtable 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 @@ class hashtable } } 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()); + old_buckets[n].clear_and_dispose + (detail::init_disposer()); + } + 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 } //! Effects: Returns the nearest new bucket count optimized for @@ -1360,10 +1723,10 @@ class hashtable /// @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 @@ class hashtable 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 @@ class hashtable 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()); + } + else{ + buckets_ptr->clear(); + } } } template - local_iterator priv_find - ( const KeyType &key, KeyHasher hasher - , KeyValueEqual equal, size_type &bucket_number, size_type &h) const + siterator priv_find + ( const KeyType &key, KeyHasher hash_func + , KeyValueEqual equal_func, size_type &bucket_number, size_type &h) const { - size_type b_len(this->priv_buckets_len()); - h = hasher(key); - bucket_number = h % b_len; + 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 - std::pair priv_equal_range + std::pair 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 @@ class hashtable size_type h; count = 0; //Let's see if the element is present - std::pair to_return - ( priv_find(key, hasher, equal, bucket_number_first, h) - , invalid_local_it(this->priv_bucket_info())); + std::pair 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 @@ class hashtable //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 @@ class hashtable } //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 +struct make_hashtable_opt +{ + typedef typename pack_options + < uset_defaults, O1, O2, O3, O4, O5, O6, O7>::type packed_options; + + //Real value traits must be calculated from options + typedef typename detail::get_value_traits + ::type value_traits; + /// @cond + static const bool external_value_traits = + detail::external_value_traits_is_true::value; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::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 + ::type slist_impl; + typedef typename + detail::if_c< detail::is_same + < specified_bucket_traits + , default_bucket_traits + >::value + , detail::bucket_traits_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 +#else +template +#endif +struct make_hashtable +{ + /// @cond + typedef hashtable_impl + < typename make_hashtable_opt + ::type + > implementation_defined; + + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class hashtable + : public make_hashtable::type +{ + typedef typename make_hashtable + ::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::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 diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp index 07f624b..451bdb8 100644 --- a/include/boost/intrusive/intrusive_fwd.hpp +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -14,8 +14,9 @@ #define BOOST_INTRUSIVE_FWD_HPP #include -#include -#include +#include + +/// @cond //std predeclarations namespace std{ @@ -36,6 +37,14 @@ struct hash; namespace intrusive { +struct none; + +} //namespace intrusive{ +} //namespace boost{ + +namespace boost { +namespace intrusive { + //////////////////////////// // Node algorithms //////////////////////////// @@ -55,104 +64,148 @@ class rbtree_algorithms; //////////////////////////// //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; -//hash/unordered -template< class ValueTraits - , class Hash = boost::hash - , class Equal = std::equal_to - , bool ConstantTimeSize = true - , class SizeType = std::size_t - > -class hashtable; - -template< class ValueTraits - , class Hash = boost::hash - , class Equal = std::equal_to - , bool ConstantTimeSize = true - , class SizeType = std::size_t - > -class unordered_set; - -template< class ValueTraits - , class Hash = boost::hash - , class Equal = std::equal_to - , bool ConstantTimeSize = true - , class SizeType = std::size_t - > -class unordered_multiset; - -template< class Tag = tag - , linking_policy Policy = safe_link - , class VoidPointer = void * - > -class unordered_set_base_hook; - -template< linking_policy Policy = safe_link - , class VoidPointer = void *> -class unordered_set_member_hook; - - -//rbtree/set -template < class ValueTraits - , class Compare = std::less - , 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 rbtree; -template < class ValueTraits - , class Compare = std::less - , bool ConstantTimeSize = true - , class SizeType = std::size_t> +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > class set; -template < class ValueTraits - , class Compare = std::less - , bool ConstantTimeSize = true - , class SizeType = std::size_t> +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > class multiset; -template< class Tag = tag - , linking_policy Policy = safe_link - , class VoidPointer = void * - > +template + < class O1 = none + , class O2 = none + , class O3 = none + > class set_base_hook; -template< linking_policy Policy = safe_link - , class VoidPointer = void *> +template + < class O1 = none + , class O2 = none + , class O3 = none + > class set_member_hook; +//hash/unordered +//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 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 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 O1 = none + , class O2 = none + , class O3 = none + > +class unordered_set_base_hook; + +template + < class O1 = none + , class O2 = none + , class O3 = none + > +class unordered_set_member_hook; + } //namespace intrusive { } //namespace boost { +/// @endcond + #endif //#ifndef BOOST_INTRUSIVE_FWD_HPP diff --git a/include/boost/intrusive/linking_policy.hpp b/include/boost/intrusive/link_mode.hpp similarity index 86% rename from include/boost/intrusive/linking_policy.hpp rename to include/boost/intrusive/link_mode.hpp index a50124b..525e150 100644 --- a/include/boost/intrusive/linking_policy.hpp +++ b/include/boost/intrusive/link_mode.hpp @@ -10,24 +10,24 @@ // ///////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP -#define BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP +#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 linking_policy{ +enum link_mode_type{ //!If this linking policy is specified in a value_traits class - //!as the linking_policy, containers + //!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 linking_policy, containers + //!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. @@ -43,4 +43,4 @@ enum linking_policy{ } //namespace intrusive } //namespace boost -#endif //BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP +#endif //BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index 12738b8..7f6854b 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -20,79 +20,127 @@ #include #include #include -#include +#include +#include #include -#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING -#include -#endif +#include +#include #include #include #include #include -#include namespace boost { namespace intrusive { +/// @cond + +template +struct internal_default_list_hook +{ + template static detail::one test(...); + template static detail::two test(typename U::default_list_hook* = 0); + static const bool value = sizeof(test(0)) == sizeof(detail::two); +}; + +template +struct get_default_list_hook +{ + typedef typename T::default_list_hook type; +}; + +template +struct listopt +{ + typedef ValueTraits value_traits; + typedef SizeType size_type; + static const bool constant_time_size = ConstantTimeSize; +}; + +template +struct list_defaults + : pack_options + < none + , base_hook + < typename detail::eval_if_c + < internal_default_list_hook::value + , get_default_list_hook + , detail::identity + >::type + > + , constant_time_size + , size_type + >::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 +//! 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 +#else +template +#endif +class list_impl { - /// @cond - private: - typename ValueTraits::node_traits::node root_; - typedef list this_type; - typedef typename ValueTraits::node_traits node_traits; - typedef detail::size_holder 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; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::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::value_type value_type; typedef typename std::iterator_traits::reference reference; typedef typename std::iterator_traits::reference const_reference; typedef typename std::iterator_traits::difference_type difference_type; - typedef SizeType size_type; - typedef detail::list_iterator iterator; - typedef detail::list_iterator const_iterator; + typedef typename Config::size_type size_type; + typedef list_iterator iterator; + typedef list_iterator const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_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_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::store_cont_ptr_on_it::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_algorithms; + typedef detail::size_holder 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 @@ class list } 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_) const + { return data_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_.get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_; } + + real_value_traits &get_real_value_traits(detail::bool_) + { 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_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + //! Effects: constructs an empty list. //! //! Complexity: Constant //! - //! Throws: If value_traits::node_traits::node + //! Throws: 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 @@ class list //! //! Complexity: Linear in std::distance(b, e). No copy constructors are called. //! - //! Throws: If value_traits::node_traits::node + //! Throws: If real_value_traits::node_traits::node //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). template - 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 @@ class list //! //! Complexity: 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 @@ class list //! Note: 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(); } //! Requires: value must be an lvalue. @@ -184,11 +275,11 @@ class list //! Note: 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(); } //! Effects: Erases the last element of the list. @@ -203,7 +294,7 @@ class list { 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 @@ class list { 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)); } //! Effects: Erases the first element of the list. @@ -242,7 +333,7 @@ class list { 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 @@ class list { 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)); } //! Effects: Returns a reference to the first element of the list. @@ -275,7 +366,7 @@ class list //! //! Complexity: 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())); } //! Effects: Returns a const_reference to the first element of the list. //! @@ -283,7 +374,7 @@ class list //! //! Complexity: 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()))); } //! Effects: Returns a reference to the last element of the list. //! @@ -291,7 +382,7 @@ class list //! //! Complexity: 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())); } //! Effects: Returns a const_reference to the last element of the list. //! @@ -299,7 +390,7 @@ class list //! //! Complexity: 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()))); } //! Effects: Returns an iterator to the first element contained in the list. //! @@ -307,7 +398,7 @@ class list //! //! Complexity: Constant. iterator begin() - { return iterator(node_traits::get_next(this->get_root_node())); } + { return iterator(node_traits::get_next(this->get_root_node()), this); } //! Effects: Returns a const_iterator to the first element contained in the list. //! @@ -323,7 +414,7 @@ class list //! //! Complexity: 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); } //! Effects: Returns an iterator to the end of the list. //! @@ -331,7 +422,7 @@ class list //! //! Complexity: Constant. iterator end() - { return iterator(this->get_root_node()); } + { return iterator(this->get_root_node(), this); } //! Effects: Returns a const_iterator to the end of the list. //! @@ -347,7 +438,7 @@ class list //! //! Complexity: Constant. const_iterator cend() const - { return const_iterator(uncast(this->get_root_node())); } + { return const_iterator(uncast(this->get_root_node()), this); } //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed list. @@ -411,11 +502,8 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - static list &container_from_end_iterator(iterator end_iterator) - { - return *detail::parent_from_member - ( 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); } //! Precondition: end_iterator must be a valid end const_iterator //! of list. @@ -425,24 +513,21 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. - static const list &container_from_end_iterator(const_iterator end_iterator) - { - return *detail::parent_from_member - ( 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); } //! Effects: Returns the number of the elements contained in the list. //! //! Throws: Nothing. //! //! Complexity: 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. //! //! Note: 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 @@ class list //! Complexity: Constant. //! //! Note: 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 @@ class list ++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 @@ class list //! 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 @@ class list ++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 @@ class list } 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 @@ class list //! //! Throws: If cloner throws. Basic guarantee. template - 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 } //! Requires: value must be an lvalue and p must be a valid iterator of *this. @@ -711,12 +792,12 @@ class list //! Note: 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); } //! Requires: Dereferencing iterator must yield @@ -793,13 +874,15 @@ class list //! //! Note: 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 @@ class list //! //! Note: 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(); } //! Requires: p must be a valid iterator of *this. @@ -832,18 +915,20 @@ class list //! Throws: Nothing. //! //! Complexity: Linear to the number of elements transferred - //! if ConstantTimeSize is true. Constant-time otherwise. + //! if constant-time size option is enabled. Constant-time otherwise. //! //! Note: 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 @@ class list //! //! Note: 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 @@ class list //! Effects: This function sorts the list *this according to std::less. //! The sort is stable, that is, the relative order of equivalent elements is preserved. //! - //! Throws: If value_traits::node_traits::node + //! Throws: If real_value_traits::node_traits::node //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) //! or std::less throws. Basic guarantee. //! @@ -898,12 +985,12 @@ class list //! Effects: This function sorts the list *this according to p. The sort is //! stable, that is, the relative order of equivalent elements is preserved. //! - //! Throws: If value_traits::node_traits::node + //! Throws: If real_value_traits::node_traits::node //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) //! or the predicate throws. Basic guarantee. //! - //! Notes: This won't throw if list_base_hook<>::value_traits or - //! list_member_hook::::value_traits are used as value traits. + //! Notes: This won't throw if list_base_hook<> or + //! list_member_hook are used. //! Iterators and references are not invalidated. //! //! Complexity: The number of comparisons is approximately N log N, where N @@ -913,8 +1000,8 @@ class list { 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 @@ class list //! size() + x.size() - 1 comparisons. //! //! Note: Iterators and references are not invalidated - void merge(list& x) + void merge(list_impl& x) { merge(x, std::less()); } //! Requires: p must be a comparison function that induces a strict weak @@ -961,7 +1048,7 @@ class list //! //! Note: Iterators and references are not invalidated. template - void merge(list& x, Predicate p) + void merge(list_impl& x, Predicate p) { iterator e = this->end(); iterator bx = x.begin(); @@ -1142,10 +1229,13 @@ class list //! Complexity: Constant time. //! //! Note: Iterators and references are not invalidated. - static iterator iterator_to(reference value) - { - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(value))); - return iterator(ValueTraits::to_node_ptr(value)); + //! This static function is available only if the value traits + //! 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); } //! Requires: value must be a const reference to a value inserted in a list. @@ -1157,20 +1247,91 @@ class list //! Complexity: Constant time. //! //! Note: Iterators and references are not invalidated. - static const_iterator iterator_to(const_reference value) - { - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast (value)))); - return const_iterator(ValueTraits::to_node_ptr(const_cast (value))); + //! This static function is available only if the value traits + //! 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 (value)))); + return const_iterator(real_value_traits::to_node_ptr(const_cast (value)), 0); } + + //! Requires: value must be a reference to a value inserted in a list. + //! + //! Effects: This function returns a const_iterator pointing to the element + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + iterator iterator_to(reference 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); + } + + //! Requires: value must be a const reference to a value inserted in a list. + //! + //! Effects: This function returns an iterator pointing to the element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + const_iterator iterator_to(const_reference value) const + { + BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(const_cast (value)))); + return const_iterator(real_value_traits::to_node_ptr(const_cast (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 + ( detail::get_pointer(end_iterator.pointed_node()), &root_plus_size::root_); + data_t *d = detail::parent_from_member + ( r, &data_t::root_plus_size_); + list_impl *s = detail::parent_from_member(d, &list_impl::data_); + return *s; + } + /// @endcond }; -template -inline bool operator==(const list& x, const list& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator< +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const list_impl &x, const list_impl &y) +#else +(const list_impl &x, const list_impl &y) +#endif +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +bool operator== +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const list_impl &x, const list_impl &y) +#else +(const list_impl &x, const list_impl &y) +#endif { + typedef list_impl 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::const_iterator const_iterator; const_iterator end1 = x.end(); const_iterator i1 = x.begin(); @@ -1192,31 +1353,132 @@ inline bool operator==(const list& x, const list& y) } } -template -inline bool operator<(const list& x, - const list& y) -{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - -template -inline bool operator!=(const list& x, const list& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const list_impl &x, const list_impl &y) +#else +(const list_impl &x, const list_impl &y) +#endif { return !(x == y); } -template -inline bool operator>(const list& x, const list& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const list_impl &x, const list_impl &y) +#else +(const list_impl &x, const list_impl &y) +#endif { return y < x; } -template -inline bool operator<=(const list& x, const list& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const list_impl &x, const list_impl &y) +#else +(const list_impl &x, const list_impl &y) +#endif { return !(y < x); } -template -inline bool operator>=(const list& x, const list& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const list_impl &x, const list_impl &y) +#else +(const list_impl &x, const list_impl &y) +#endif { return !(x < y); } -template -inline void swap(list& x, list& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(list_impl &x, list_impl &y) +#else +(list_impl &x, list_impl &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 +#else +template +#endif +struct make_list +{ + /// @cond + typedef typename pack_options + < list_defaults, O1, O2, O3>::type packed_options; + typedef typename detail::get_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 list + : public make_list::type +{ + typedef typename make_list + ::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::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 + 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(Base::container_from_end_iterator(end_iterator)); } + + static const list &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/list_hook.hpp b/include/boost/intrusive/list_hook.hpp index 746ef1c..1133b4b 100644 --- a/include/boost/intrusive/list_hook.hpp +++ b/include/boost/intrusive/list_hook.hpp @@ -17,293 +17,104 @@ #include #include #include -#include #include #include -#include -#include -#include +#include +#include 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. -//! -//! 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 -//! derived from more than one list_base_hook, then each list_base_hook needs its -//! unique tag. -//! -//! 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 list configured from this hook. -template< class Tag //= tag - , linking_policy Policy //= safe_link - , class VoidPointer //= void * - > -class list_base_hook - : private detail::list_node_traits::node +/// @cond +template +struct get_list_node_algo { - public: - typedef detail::list_node_traits node_traits; - enum { linking_policy = Policy }; + typedef circular_list_algorithms > 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 +#else +template +#endif +struct make_list_base_hook +{ /// @cond - private: - typedef circular_list_algorithms node_algorithms; + typedef typename pack_options + < hook_defaults, O1, O2, O3>::type packed_options; - public: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef list_base_hook - this_type; - - typedef typename boost::pointer_to_other - ::type this_type_ptr; - - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - private: - node_ptr this_as_node() - { return node_ptr(static_cast(this)); } - - const_node_ptr this_as_node() const - { return const_node_ptr(static_cast(this)); } + typedef detail::generic_hook + < get_list_node_algo + , typename packed_options::tag + , packed_options::link_mode + , detail::ListBaseHook + > implementation_defined; /// @endcond - - public: - //! Effects: If Policy is auto_unlink or safe_mode_linnk - //! initializes the node to an unlinked state. - //! - //! Throws: Nothing. - list_base_hook() - : node() - { - if(Policy == safe_link || Policy == auto_unlink){ - node_algorithms::init(this_as_node()); - } - } - - //! Effects: If Policy is auto_unlink or safe_mode_linnk - //! initializes the node to an unlinked state. The argument is ignored. - //! - //! Throws: Nothing. - //! - //! Rationale: 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 - //! move-semantics. - list_base_hook(const list_base_hook& ) - : node() - { - if(Policy == safe_link || Policy == auto_unlink){ - node_algorithms::init(this_as_node()); - } - } - - //! Effects: Empty function. The argument is ignored. - //! - //! Throws: Nothing. - //! - //! Rationale: 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 - //! move-semantics. - list_base_hook& operator=(const list_base_hook& ) - { return *this; } - - //! Effects: 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. - //! - //! Throws: Nothing. - ~list_base_hook() - { detail::destructor_impl(*this, detail::dispatcher()); } - - //! Effects: 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. - //! - //! Complexity: Constant - //! - //! Throws: Nothing. - void swap_nodes(list_base_hook &other) - { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); } - - //! Precondition: Policy must be safe_link or auto_unlink. - //! - //! Returns: true, if the node belongs to a container, false - //! otherwise. This function can be used to test whether list::iterator_to - //! will return a valid iterator. - //! - //! Complexity: 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()); - } - - //! Effects: Removes the node if it's inserted in a container. - //! This function is only allowed if Policy is auto_unlink. - //! - //! Throws: 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 - struct value_traits - : detail::derivation_hook_value_traits - {}; - - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static this_type_ptr to_hook_ptr(node_ptr p) - { - return this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static const_this_type_ptr to_hook_ptr(const_node_ptr p) - { - return const_this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Returns a pointer to the node that this hook holds. - //! - //! Throws: Nothing. - node_ptr to_node_ptr() - { return this_as_node(); } - - //! Effects: Returns a const pointer to the node that this hook holds. - //! - //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return this_as_node(); } + 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. +//! Derive a class from this hook in order to store objects of that class +//! in an list. //! -//! The first boolean template parameter will specify the linking mode of the hook. +//! The hook admits the following options: \c tag<>, \c void_pointer<> and +//! \c link_mode<>. //! -//! 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 * - > -class list_member_hook - : private detail::list_node_traits::node +//! \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 \c list_base_hook, then each \c list_base_hook needs its +//! unique tag. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \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 +#else +template +#endif +class list_base_hook + : public make_list_base_hook::type { - public: - typedef detail::list_node_traits node_traits; - enum { linking_policy = Policy }; - - /// @cond - private: - typedef circular_list_algorithms node_algorithms; - /// @endcond - - public: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef list_member_hook - this_type; - - typedef typename boost::pointer_to_other - ::type this_type_ptr; - - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - /// @cond - private: - node_ptr this_as_node() - { return node_ptr(static_cast(this)); } - - const_node_ptr this_as_node() const - { return const_node_ptr(static_cast(this)); } - /// @endcond - - public: - //! Effects: If Policy is auto_unlink or safe_mode_linnk + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! //! Throws: Nothing. - list_member_hook() - : node() - { - if(Policy == safe_link || Policy == auto_unlink){ - node_algorithms::init(this_as_node()); - } - } + list_base_hook(); - //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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_base_hook(const list_base_hook& ); //! Effects: Empty function. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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_base_hook& operator=(const list_base_hook& ); - //! Effects: 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. + //! Effects: 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. //! //! Throws: Nothing. - ~list_member_hook() - { detail::destructor_impl(*this, detail::dispatcher()); } + ~list_base_hook(); //! Effects: 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 +127,133 @@ class list_member_hook //! //! Complexity: Constant //! - //! Throws: Nothing. - void swap_nodes(list_member_hook& other) - { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); } + //! Throws: Nothing. + void swap_nodes(list_base_hook &other); - //! Precondition: Policy must be safe_link or auto_unlink. + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. //! //! Returns: 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. //! - //! Complexity: 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()); - } + //! Complexity: Constant + bool is_linked() const; //! Effects: 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. //! //! Throws: Nothing. - void unlink() - { - BOOST_STATIC_ASSERT((Policy == auto_unlink)); - node_algorithms::unlink(this_as_node()); - node_algorithms::init(this_as_node()); - } + void unlink(); + #endif +}; - //! 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 - struct value_traits - : detail::member_hook_value_traits - {}; +//! 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 +#else +template +#endif +struct make_list_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3>::type packed_options; - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. + typedef detail::generic_hook + < get_list_node_algo + , member_tag + , packed_options::link_mode + , detail::NoBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Store this hook in a class to be inserted +//! in an list. +//! +//! 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). +//! +//! \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 +#else +template +#endif +class list_member_hook + : public make_list_member_hook::type +{ + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. //! //! Throws: Nothing. - static this_type_ptr to_hook_ptr(node_ptr p) - { - return this_type_ptr(static_cast (detail::get_pointer(p))); - } + list_member_hook(); - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. //! //! Throws: Nothing. - static const_this_type_ptr to_hook_ptr(const_node_ptr p) - { - return const_this_type_ptr(static_cast (detail::get_pointer(p))); - } + //! + //! Rationale: Providing a copy-constructor + //! 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& ); - //! Effects: Returns a pointer to the node that this hook holds. + //! Effects: Empty function. The argument is ignored. //! //! Throws: Nothing. - node_ptr to_node_ptr() - { return this_as_node(); } + //! + //! Rationale: Providing an assignment operator + //! 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& ); - //! Effects: Returns a const pointer to the node that this hook holds. + //! Effects: 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. //! //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return this_as_node(); } + ~list_member_hook(); + + //! Effects: 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. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(list_member_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c list::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif }; } //namespace intrusive diff --git a/include/boost/intrusive/member_value_traits.hpp b/include/boost/intrusive/member_value_traits.hpp index 06c90ea..b32f8c4 100644 --- a/include/boost/intrusive/member_value_traits.hpp +++ b/include/boost/intrusive/member_value_traits.hpp @@ -13,7 +13,7 @@ #ifndef BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP #define BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP -#include +#include #include #include @@ -25,7 +25,7 @@ namespace intrusive { //!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 @@ struct member_value_traits typedef typename boost::pointer_to_other::type const_pointer; typedef typename std::iterator_traits::reference reference; typedef typename std::iterator_traits::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)); } diff --git a/include/boost/intrusive/options.hpp b/include/boost/intrusive/options.hpp new file mode 100644 index 0000000..c7683f7 --- /dev/null +++ b/include/boost/intrusive/options.hpp @@ -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 +#include +#include +#include +#include +#include + + +namespace boost { +namespace intrusive { + +/// @cond + +struct default_tag; +struct member_tag; + +namespace detail{ + +template +struct eval_value_traits +{ + typedef typename ValueTraits::value_traits type; +}; + +template +struct external_bucket_traits_is_true +{ + static const bool value = external_bucket_traits_bool::value == 3; +}; + +template +struct eval_bucket_traits +{ + typedef typename BucketTraits::bucket_traits type; +}; + +template +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 +struct get_member_value_traits +{ + typedef typename MemberHook::member_value_traits type; +}; + +template +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::value + //...get it's internal value traits using + //the provided T value type. + , get_base_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::value + , get_member_value_traits + , detail::identity + > + >::type type; +}; + +template +struct get_base_node_traits +{ + typedef typename BaseHook::boost_intrusive_tags::node_traits type; +}; + +template +struct get_member_node_traits +{ + typedef typename MemberHook::member_value_traits::node_traits type; +}; + +template +struct get_explicit_node_traits +{ + typedef typename ValueTraits::node_traits type; +}; + + +template +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::value + //...get it's internal value traits using + //the provided T value type. + , get_base_node_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::value + , get_member_node_traits + , get_explicit_node_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 + 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 +struct constant_time_size +{ +/// @cond + template + 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 +struct size_type +{ +/// @cond + template + struct pack : Base + { + typedef SizeType size_type; + }; +/// @endcond +}; + +//!This option setter specifies the strict weak ordering +//!comparison functor for the value type +template +struct compare +{ +/// @cond + template + struct pack : Base + { + typedef Compare compare; + }; +/// @endcond +}; + +//!This option setter specifies the equality +//!functor for the value type +template +struct equal +{ +/// @cond + template + struct pack : Base + { + typedef Equal equal; + }; +/// @endcond +}; + +//!This option setter specifies the hash +//!functor for the value type +template +struct hash +{ +/// @cond + template + 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 +struct value_traits +{ +/// @cond + template + 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 + struct pack : Base + { + typedef member_value_traits value_traits; + }; +/// @endcond +}; + +//!This option setter specifies that the container +//!must use the specified base hook +template +struct base_hook +{ +/// @cond + template + 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 +struct void_pointer +{ +/// @cond + template + 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 +struct tag +{ +/// @cond + template + 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 +struct link_mode +{ +/// @cond + template + 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 +struct bucket_traits +{ +/// @cond + template + 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 +struct power_2_buckets +{ +/// @cond + template + struct pack : Base + { + static const bool power_2_buckets = Enabled; + }; +/// @endcond +}; + +/// @cond + +template +struct do_pack +{ + //Use "pack" member template to pack options + typedef typename Next::template pack type; +}; + +template +struct do_pack +{ + //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 + , link_mode + , tag + >::type +{}; + +/// @endcond + +} //namespace intrusive { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTRUSIVE_OPTIONS_HPP diff --git a/include/boost/intrusive/pointer_plus_bit.hpp b/include/boost/intrusive/pointer_plus_bit.hpp index 02290e6..9a69ea3 100644 --- a/include/boost/intrusive/pointer_plus_bit.hpp +++ b/include/boost/intrusive/pointer_plus_bit.hpp @@ -23,7 +23,7 @@ namespace intrusive { template struct has_pointer_plus_bit { - enum { value = false }; + static const bool value = false; }; //!This is an specialization for raw pointers. @@ -32,7 +32,7 @@ struct has_pointer_plus_bit template struct has_pointer_plus_bit { - enum { value = N % 2u == 0 }; + static const bool value = (N % 2u == 0); }; //!This is class that is supposed to have static methods diff --git a/include/boost/intrusive/rbtree.hpp b/include/boost/intrusive/rbtree.hpp index a7d3e72..fb68995 100644 --- a/include/boost/intrusive/rbtree.hpp +++ b/include/boost/intrusive/rbtree.hpp @@ -23,123 +23,228 @@ #include #include #include +#include #include -#include +#include #include #include namespace boost { namespace intrusive { +/// @cond + +template +struct internal_default_set_hook +{ + template static detail::one test(...); + template static detail::two test(typename U::default_set_hook* = 0); + static const bool value = sizeof(test(0)) == sizeof(detail::two); +}; + +template +struct get_default_set_hook +{ + typedef typename T::default_set_hook type; +}; + +template +struct setopt +{ + typedef ValueTraits value_traits; + typedef Compare compare; + typedef SizeType size_type; + static const bool constant_time_size = ConstantTimeSize; +}; + +template +struct set_defaults + : pack_options + < none + , base_hook + < typename detail::eval_if_c + < internal_default_set_hook::value + , get_default_set_hook + , detail::identity + >::type + > + , constant_time_size + , size_type + , compare > + >::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 - , bool ConstantTimeSize //= true - , class SizeType //= std::size_t - > -class rbtree - : private detail::size_holder +//! +//! 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 +#else +template +#endif +class rbtree_impl { + public: + typedef typename Config::value_traits value_traits; + /// @cond + static const bool external_value_traits = + detail::external_value_traits_is_true::value; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::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::value_type value_type; + typedef value_type key_type; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::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 iterator; + typedef rbtree_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_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 + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef rbtree_algorithms node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; + /// @cond private: - typename ValueTraits::node_traits::node root_; - typedef rbtree this_type; - typedef typename ValueTraits::node_traits node_traits; - typedef detail::size_holder size_traits; + typedef detail::size_holder size_traits; //noncopyable - rbtree (const rbtree&); - rbtree operator =(const rbtree&); - /// @endcond + rbtree_impl (const rbtree_impl&); + rbtree_impl operator =(const rbtree_impl&); - 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::reference reference; - typedef typename std::iterator_traits::reference const_reference; - typedef typename std::iterator_traits::difference_type difference_type; - typedef SizeType size_type; - typedef value_type key_type; - typedef Compare value_compare; - typedef detail::rbtree_iterator iterator; - typedef detail::rbtree_iterator const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - /// @cond - private: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef rbtree_algorithms 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))); - //Use EBO if possible - typedef detail::node_plus_pred 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 + { + node_plus_pred_t(const value_compare &comp) + : detail::ebo_functor_holder(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(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_) const + { return data_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_.get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_; } + + real_value_traits &get_real_value_traits(detail::bool_) + { 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_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + typedef typename node_algorithms::insert_commit_data insert_commit_data; //! Effects: Constructs an empty tree. //! //! Complexity: Constant. //! - //! Throws: Nothing unless the copy constructor of the Compare object throws. - rbtree(Compare cmp = Compare()) - : members_(cmp) + //! Throws: 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)); } - //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. //! cmp must be a comparison function that induces a strict weak ordering. - //! - //! Effects: Constructs an empty tree and inserts elements from + //! + //! Effects: Constructs an empty tree and inserts elements from //! [b, e). - //! - //! Complexity: Linear in N if [b, e) is already sorted using + //! + //! Complexity: Linear in N if [b, e) is already sorted using //! comp and otherwise N * log N, where N is last ­ first. //! - //! Throws: Nothing unless the copy constructor of the Compare object throws. + //! Throws: Nothing unless the copy constructor of the value_compare object throws. template - 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 @@ class rbtree //! Effects: 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. //! //! Complexity: Linear to elements contained in *this. //! //! Throws: Nothing. - ~rbtree() + ~rbtree_impl() { this->clear(); } //! Effects: Returns an iterator pointing to the beginning of the tree. @@ -162,7 +267,7 @@ class rbtree //! //! Throws: Nothing. iterator begin() - { return iterator (node_traits::get_left(node_ptr(&priv_header()))); } + { return iterator (node_traits::get_left(node_ptr(&priv_header())), this); } //! Effects: Returns a const_iterator pointing to the beginning of the tree. //! @@ -178,7 +283,7 @@ class rbtree //! //! Throws: 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); } //! Effects: Returns an iterator pointing to the end of the tree. //! @@ -186,10 +291,10 @@ class rbtree //! //! Throws: Nothing. iterator end() - { return iterator (node_ptr(&priv_header())); } + { return iterator (node_ptr(&priv_header()), this); } //! Effects: Returns a const_iterator pointing to the end of the tree. - //! + //! //! Complexity: Constant. //! //! Throws: Nothing. @@ -202,7 +307,7 @@ class rbtree //! //! Throws: Nothing. const_iterator cend() const - { return const_iterator (uncast(const_node_ptr(&priv_header()))); } + { return const_iterator (uncast(const_node_ptr(&priv_header())), this); } //! Effects: Returns a reverse_iterator pointing to the beginning of the //! reversed tree. @@ -266,12 +371,8 @@ class rbtree //! Throws: Nothing. //! //! Complexity: Constant. - static rbtree &container_from_end_iterator(iterator end_iterator) - { - return *detail::parent_from_member - ( 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); } //! Precondition: end_iterator must be a valid end const_iterator //! of rbtree. @@ -281,12 +382,8 @@ class rbtree //! Throws: Nothing. //! //! Complexity: Constant. - static const rbtree &container_from_end_iterator(const_iterator end_iterator) - { - return *detail::parent_from_member - ( 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); } //! Effects: Returns the value_compare object used by the tree. //! @@ -311,8 +408,8 @@ class rbtree //! Throws: 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 @@ class rbtree //! //! Complexity: Constant. //! - //! Throws: If the comparison functor's unspecified swap call throws. - void swap(rbtree& other) + //! Throws: 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 @@ class rbtree //! No copy-constructors are called. iterator insert_equal_upper_bound(reference value) { - detail::key_node_ptr_compare key_node_comp(priv_comp()); - node_ptr to_insert(ValueTraits::to_node_ptr(value)); + detail::key_nodeptr_comp + 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); } //! Requires: value must be an lvalue @@ -371,13 +469,14 @@ class rbtree //! No copy-constructors are called. iterator insert_equal_lower_bound(reference value) { - detail::key_node_ptr_compare key_node_comp(priv_comp()); - node_ptr to_insert(ValueTraits::to_node_ptr(value)); + detail::key_nodeptr_comp + 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); } //! Requires: value must be an lvalue, and "hint" must be @@ -396,13 +495,14 @@ class rbtree //! No copy-constructors are called. iterator insert_equal(const_iterator hint, reference value) { - detail::key_node_ptr_compare key_node_comp(priv_comp()); - node_ptr to_insert(ValueTraits::to_node_ptr(value)); + detail::key_nodeptr_comp + 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); } //! Requires: Dereferencing iterator must yield an lvalue @@ -411,8 +511,8 @@ class rbtree //! Effects: Inserts a each element of a range into the tree //! before the upper bound of the key of each element. //! - //! Complexity: 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 + //! Complexity: 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(). //! //! Throws: Nothing. @@ -512,11 +612,12 @@ class rbtree std::pair insert_unique_check (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) { - detail::key_node_ptr_compare comp(key_value_comp); + detail::key_nodeptr_comp + comp(key_value_comp, this); std::pair ret = (node_algorithms::insert_unique_check (node_ptr(&priv_header()), key, comp, commit_data)); - return std::pair(iterator(ret.first), ret.second); + return std::pair(iterator(ret.first, this), ret.second); } std::pair insert_unique_check @@ -528,22 +629,23 @@ class rbtree (const_iterator hint, const KeyType &key ,KeyValueCompare key_value_comp, insert_commit_data &commit_data) { - detail::key_node_ptr_compare comp(key_value_comp); + detail::key_nodeptr_comp + comp(key_value_comp, this); std::pair ret = (node_algorithms::insert_unique_check (node_ptr(&priv_header()), hint.pointed_node(), key, comp, commit_data)); - return std::pair(iterator(ret.first), ret.second); + return std::pair(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); } //! Effects: Erases the element pointed to by pos. @@ -562,7 +664,7 @@ class rbtree 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 @@ class rbtree { 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 @@ class rbtree 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 @@ class rbtree template 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, this)); + node_algorithms::init_header(&priv_header()); + this->priv_size_traits().set_size(0); } //! Effects: Returns the number of contained elements with the given value @@ -797,9 +883,10 @@ class rbtree template iterator lower_bound(const KeyType &key, KeyValueCompare comp) { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + 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); } //! Effects: Returns a const iterator to the first element whose @@ -811,9 +898,10 @@ class rbtree template const_iterator lower_bound(const KeyType &key, KeyValueCompare comp) const { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + 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); } //! Effects: Returns an iterator to the first element whose @@ -835,9 +923,10 @@ class rbtree template iterator upper_bound(const KeyType &key, KeyValueCompare comp) { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + 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); } //! Effects: Returns an iterator to the first element whose @@ -859,9 +948,10 @@ class rbtree template const_iterator upper_bound(const KeyType &key, KeyValueCompare comp) const { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + 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); } //! Effects: Finds an iterator to the first element whose key is @@ -882,9 +972,10 @@ class rbtree template iterator find(const KeyType &key, KeyValueCompare comp) { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + 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); } //! Effects: Finds a const_iterator to the first element whose key is @@ -905,9 +996,10 @@ class rbtree template const_iterator find(const KeyType &key, KeyValueCompare comp) const { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + 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); } //! Effects: Finds a range containing all elements whose key is k or @@ -930,10 +1022,11 @@ class rbtree template std::pair equal_range(const KeyType &key, KeyValueCompare comp) { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + key_node_comp(comp, this); std::pair ret (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); - return std::pair(iterator(ret.first), iterator(ret.second)); + return std::pair(iterator(ret.first, this), iterator(ret.second, this)); } //! Effects: Finds a range containing all elements whose key is k or @@ -958,23 +1051,24 @@ class rbtree std::pair equal_range(const KeyType &key, KeyValueCompare comp) const { - detail::key_node_ptr_compare key_node_comp(comp); + detail::key_nodeptr_comp + key_node_comp(comp, this); std::pair ret (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); - return std::pair(const_iterator(ret.first), const_iterator(ret.second)); + return std::pair(const_iterator(ret.first, this), const_iterator(ret.second, this)); } template - 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) - ,detail::value_to_node_disposer(disposer)); - size_traits::set_size(src.get_size()); + ,detail::node_cloner(cloner, this) + ,detail::node_disposer(disposer, this)); + this->priv_size_traits().set_size(src.priv_size_traits().get_size()); } } @@ -984,10 +1078,31 @@ class rbtree (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); + } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: 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)); } //! Requires: value must be an lvalue and shall be in a set of @@ -999,8 +1114,44 @@ class rbtree //! Complexity: Constant. //! //! Throws: Nothing. - static iterator iterator_to(reference value) - { return iterator (ValueTraits::to_node_ptr(value)); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + return iterator (value_traits::to_node_ptr(value), 0); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing.ç + //! + //! Note: This static function is available only if the value traits + //! 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 (value)), 0); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return iterator (value_traits::to_node_ptr(value), this); } //! Requires: value must be an lvalue and shall be in a set of //! appropriate type. Otherwise the behavior is undefined. @@ -1011,25 +1162,24 @@ class rbtree //! Complexity: Constant. //! //! Throws: Nothing. - static const_iterator iterator_to(const_reference value) - { return const_iterator (ValueTraits::to_node_ptr(const_cast (value))); } -/* - //! Requires: value shall not be in a tree of the appropriate type. + const_iterator iterator_to(const_reference value) const + { return const_iterator (value_traits::to_node_ptr(const_cast (value)), this); } + + //! Requires: value shall not be in a tree. //! - //! Effects: 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. + //! Effects: init_node puts the hook of a value in a well-known default + //! state. //! //! Throws: Nothing. //! //! Complexity: Constant time. //! - //! Note: This function is meant to be used mainly with the member value_traits, - //! where no implicit node initialization during construction occurs. + //! Note: 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)); } +/* //! Effects: 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 @@ class rbtree { //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::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 @@ -1073,20 +1224,55 @@ class rbtree 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 + ( detail::get_pointer(end_iterator.pointed_node()), &header_plus_size::header_); + node_plus_pred_t *n = detail::parent_from_member + (r, &node_plus_pred_t::header_plus_size_); + data_t *d = detail::parent_from_member(n, &data_t::node_plus_pred_); + rbtree_impl *rb = detail::parent_from_member(d, &rbtree_impl::data_); + return *rb; + } }; -template -inline bool operator==(const rbtree& x, const rbtree& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator< +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +bool operator== +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif { - if(C && x.size() != y.size()){ + typedef rbtree_impl 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::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 @@ inline bool operator==(const rbtree& x, const rbtree& y) } } -template -inline bool operator<(const rbtree& x, - const rbtree& y) -{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - -template -inline bool operator!=(const rbtree& x, const rbtree& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif { return !(x == y); } -template -inline bool operator>(const rbtree& x, const rbtree& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif { return y < x; } -template -inline bool operator<=(const rbtree& x, const rbtree& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif { return !(y < x); } -template -inline bool operator>=(const rbtree& x, const rbtree& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif { return !(x < y); } -template -inline void swap(rbtree& x, rbtree& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(rbtree_impl &x, rbtree_impl &y) +#else +(rbtree_impl &x, rbtree_impl &y) +#endif { x.swap(y); } +/// @cond +template +struct make_rbtree_opt +{ + typedef typename pack_options + < set_defaults, O1, O2, O3, O4>::type packed_options; + typedef typename detail::get_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 +#else +template +#endif +struct make_rbtree +{ + /// @cond + typedef rbtree_impl + < typename make_rbtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class rbtree + : public make_rbtree::type +{ + typedef typename make_rbtree + ::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::value)); + + rbtree( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + 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(Base::container_from_end_iterator(end_iterator)); } + + static const rbtree &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + + } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/rbtree_algorithms.hpp b/include/boost/intrusive/rbtree_algorithms.hpp index 162dde3..ebdb464 100644 --- a/include/boost/intrusive/rbtree_algorithms.hpp +++ b/include/boost/intrusive/rbtree_algorithms.hpp @@ -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 #include #include -#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING -#include -#endif +#include #include @@ -67,7 +74,7 @@ namespace intrusive { //! 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 @@ class rbtree_algorithms /// @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 @@ class rbtree_algorithms { return node_ptr(const_cast(::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 @@ class rbtree_algorithms //! //! Throws: 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 @@ class rbtree_algorithms } } + 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; + } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees. + //! + //! Effects: 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. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: 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); + } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees with header header1 and header2. + //! + //! Effects: 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. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: 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); + } + } + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: 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); + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! with header "header" and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: 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); + } + } + } + //! Requires: node is a tree node but not the header. //! //! Effects: Unlinks the node and rebalances the tree. @@ -202,6 +508,10 @@ class rbtree_algorithms } } + static void unlink(node_ptr node) + { unlink_and_rebalance(node); } + + //! Requires: header is the header of a tree. //! //! Effects: Unlinks the leftmost node from the tree, and @@ -508,25 +818,42 @@ class rbtree_algorithms //! //! Throws: If cloner functor throws. If this happens target nodes are disposed. template - 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); + } + + //! Requires: "disposer" must be an object function + //! taking a node_ptr parameter and shouldn't throw. + //! + //! Effects: Empties the target tree calling + //! void disposer::operator()(node_ptr) for every node of the tree + //! except the header. + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are disposed. + template + 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); } //! Requires: "header" must be the header node of a tree. @@ -694,6 +1021,17 @@ class rbtree_algorithms 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 @@ class rbtree_algorithms 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 @@ class rbtree_algorithms !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 @@ class rbtree_algorithms /// @cond + template + 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 + 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; + } + } + //! Requires: 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 @@ class rbtree_algorithms } NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black()); } - - template - 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 - 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 }; diff --git a/include/boost/intrusive/set.hpp b/include/boost/intrusive/set.hpp index 09735f0..9b8fcca 100644 --- a/include/boost/intrusive/set.hpp +++ b/include/boost/intrusive/set.hpp @@ -24,63 +24,59 @@ namespace intrusive { //! 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 - , 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 +#else +template +#endif +class set_impl { /// @cond - typedef rbtree tree_type; - + typedef rbtree_impl 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::reference reference; - typedef typename std::iterator_traits::reference const_reference; - typedef typename std::iterator_traits::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 - friend bool operator==(const set& x, const set& y); - - template - friend bool operator<(const set& x, const set& y); /// @endcond public: @@ -90,9 +86,10 @@ class set //! //! Throws: 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) {} //! Requires: Dereferencing iterator must yield an lvalue of type value_type. @@ -106,10 +103,12 @@ class set //! //! Throws: 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 - 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); } //! Effects: Detaches all elements from this. The objects in the set @@ -119,7 +118,7 @@ class set //! value. Otherwise constant. //! //! Throws: Nothing. - ~set() + ~set_impl() {} //! Effects: Returns an iterator pointing to the beginning of the set. @@ -232,11 +231,11 @@ class set //! Throws: Nothing. //! //! Complexity: 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 + return *detail::parent_from_member ( &tree_type::container_from_end_iterator(end_iterator) - , &set::tree_); + , &set_impl::tree_); } //! Precondition: end_iterator must be a valid end const_iterator @@ -247,11 +246,11 @@ class set //! Throws: Nothing. //! //! Complexity: 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 + return *detail::parent_from_member ( &tree_type::container_from_end_iterator(end_iterator) - , &set::tree_); + , &set_impl::tree_); } //! Effects: Returns the key_compare object used by the set. @@ -281,7 +280,7 @@ class set //! Effects: Returns the number of elements stored in the set. //! //! Complexity: Linear to elements contained in *this if, - //! ConstantTimeSize is false. Constant-time otherwise. + //! constant-time size option is enabled. Constant-time otherwise. //! //! Throws: Nothing. size_type size() const @@ -293,7 +292,7 @@ class set //! //! Throws: 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_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -310,7 +309,7 @@ class set //! //! Throws: If cloner throws. template - 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); } //! Requires: value must be an lvalue @@ -326,7 +325,7 @@ class set //! Complexity: Average complexity for insert element is at //! most logarithmic. //! - //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -344,7 +343,7 @@ class set //! Complexity: Logarithmic in general, but it's amortized //! constant time if t is inserted immediately before hint. //! - //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -449,11 +448,11 @@ class set //! //! Effects: Inserts a range into the set. //! - //! Complexity: 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 + //! Complexity: 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(). //! - //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -494,7 +493,7 @@ class set //! //! Complexity: O(log(size()) + this->count(value)). //! - //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. @@ -556,7 +555,7 @@ class set //! Effects: Erases all the elements with the given value. //! Disposer::operator()(pointer) is called for the removed elements. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. //! //! Complexity: O(log(size() + this->count(value)). Basic guarantee. //! @@ -618,7 +617,7 @@ class set //! Complexity: Logarithmic to the number of elements contained plus lineal //! to number of objects with the given key. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. size_type count(const_reference value) const { return tree_.find(value) != end(); } @@ -638,7 +637,7 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. iterator lower_bound(const_reference value) { return tree_.lower_bound(value); } @@ -666,7 +665,7 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: 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 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. iterator upper_bound(const_reference value) { return tree_.upper_bound(value); } @@ -722,7 +721,7 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: 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 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. iterator find(const_reference value) { return tree_.find(value); } @@ -778,7 +777,7 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. const_iterator find(const_reference value) const { return tree_.find(value); } @@ -807,7 +806,7 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. std::pair equal_range(const_reference value) { return tree_.equal_range(value); } @@ -837,7 +836,7 @@ class set //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. std::pair equal_range(const_reference value) const { return tree_.equal_range(value); } @@ -872,8 +871,11 @@ class set //! Complexity: Constant. //! //! Throws: Nothing. - static iterator iterator_to(reference value) - { return tree_type::iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } //! Requires: value must be an lvalue and shall be in a set of //! appropriate type. Otherwise the behavior is undefined. @@ -884,91 +886,245 @@ class set //! Complexity: Constant. //! //! Throws: Nothing. - static const_iterator iterator_to(const_reference value) - { return tree_type::iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a set/multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: 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); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: 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 -inline bool operator!=(const set& x, const set& y) -{ return !(x==y); } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return !(x == y); } -template -inline bool operator>(const set& x, const set& y) -{ return y < x; } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return y < x; } -template -inline bool operator<=(const set& x, const set& y) -{ return !(y > x); } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return !(y < x); } -template -inline bool operator>=(const set& x, const set& y) -{ return !(x < y); } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return !(x < y); } -template -inline void swap(set& x, set& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(set_impl &x, set_impl &y) +#else +(set_impl &x, set_impl &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 +#else +template +#endif +struct make_set +{ + /// @cond + typedef set_impl + < typename make_rbtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class set + : public make_set::type +{ + typedef typename make_set + ::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::value)); + + set( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + 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(Base::container_from_end_iterator(end_iterator)); } + + static const set &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(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 - , 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 +#else +template +#endif +class multiset_impl { /// @cond - typedef rbtree tree_type; - - //! This class is - //! non-copyable - multiset (const multiset&); - - //! This class is - //! non-asignable - multiset &operator =(const multiset&); + typedef rbtree_impl 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::reference reference; - typedef typename std::iterator_traits::reference const_reference; - typedef typename std::iterator_traits::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 @@ class multiset //! //! Throws: 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) {} //! Requires: Dereferencing iterator must yield an lvalue of type value_type. @@ -993,15 +1150,17 @@ class multiset //! Effects: Constructs an empty multiset and inserts elements from //! [b, e). //! - //! Complexity: Linear in N if [b, e) is already sorted using + //! Complexity: Linear in N if [b, e) is already sorted using //! comp and otherwise N * log N, where N is last ­ first. //! //! Throws: 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 - 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) {} //! Effects: Detaches all elements from this. The objects in the set @@ -1011,7 +1170,7 @@ class multiset //! auto-unlink value. Otherwise constant. //! //! Throws: Nothing. - ~multiset() + ~multiset_impl() {} //! Effects: Returns an iterator pointing to the beginning of the multiset. @@ -1124,11 +1283,11 @@ class multiset //! Throws: Nothing. //! //! Complexity: 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 + return *detail::parent_from_member ( &tree_type::container_from_end_iterator(end_iterator) - , &multiset::tree_); + , &multiset_impl::tree_); } //! Precondition: end_iterator must be a valid end const_iterator @@ -1139,11 +1298,11 @@ class multiset //! Throws: Nothing. //! //! Complexity: 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 + return *detail::parent_from_member ( &tree_type::container_from_end_iterator(end_iterator) - , &multiset::tree_); + , &multiset_impl::tree_); } //! Effects: Returns the key_compare object used by the multiset. @@ -1173,7 +1332,7 @@ class multiset //! Effects: Returns the number of elements stored in the multiset. //! //! Complexity: Linear to elements contained in *this if, - //! ConstantTimeSize is false. Constant-time otherwise. + //! constant-time size option is enabled. Constant-time otherwise. //! //! Throws: Nothing. size_type size() const @@ -1185,7 +1344,7 @@ class multiset //! //! Throws: 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_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1202,7 +1361,7 @@ class multiset //! //! Throws: If cloner throws. Basic guarantee. template - 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); } //! Requires: value must be an lvalue @@ -1215,7 +1374,7 @@ class multiset //! Complexity: Average complexity for insert element is at //! most logarithmic. //! - //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -1233,7 +1392,7 @@ class multiset //! Complexity: Logarithmic in general, but it is amortized //! constant time if t is inserted immediately before hint. //! - //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -1248,11 +1407,11 @@ class multiset //! Returns: An iterator that points to the position where the new //! element was inserted. //! - //! Complexity: 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 + //! Complexity: 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(). //! - //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! //! Note: Does not affect the validity of iterators and references. //! No copy-constructors are called. @@ -1293,7 +1452,7 @@ class multiset //! //! Complexity: O(log(size() + this->count(value)). //! - //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. @@ -1359,7 +1518,7 @@ class multiset //! //! Complexity: O(log(size() + this->count(value)). //! - //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. @@ -1417,7 +1576,7 @@ class multiset //! Complexity: Logarithmic to the number of elements contained plus lineal //! to number of objects with the given key. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. size_type count(const_reference value) const { return tree_.count(value); } @@ -1437,7 +1596,7 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. iterator lower_bound(const_reference value) { return tree_.lower_bound(value); } @@ -1465,7 +1624,7 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: 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 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. iterator upper_bound(const_reference value) { return tree_.upper_bound(value); } @@ -1521,7 +1680,7 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: 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 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. iterator find(const_reference value) { return tree_.find(value); } @@ -1577,7 +1736,7 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. const_iterator find(const_reference value) const { return tree_.find(value); } @@ -1606,7 +1765,7 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. std::pair equal_range(const_reference value) { return tree_.equal_range(value); } @@ -1636,7 +1795,7 @@ class multiset //! //! Complexity: Logarithmic. //! - //! Throws: If the internal Compare ordering function throws. + //! Throws: If the internal value_compare ordering function throws. std::pair equal_range(const_reference value) const { return tree_.equal_range(value); } @@ -1671,8 +1830,11 @@ class multiset //! Complexity: Constant. //! //! Throws: Nothing. - static iterator iterator_to(reference value) - { return tree_type::iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } //! Requires: value must be an lvalue and shall be in a set of //! appropriate type. Otherwise the behavior is undefined. @@ -1683,38 +1845,197 @@ class multiset //! Complexity: Constant. //! //! Throws: Nothing. - static const_iterator iterator_to(const_reference value) - { return tree_type::iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a set/multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: 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); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: 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 -inline bool operator!=(const multiset& x, const multiset& y) -{ return !(x==y); } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return !(x == y); } -template -inline bool operator>(const multiset& x, const multiset& y) -{ return y < x; } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return y < x; } -template -inline bool operator<=(const multiset& x, const multiset& y) -{ return !(y > x); } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return !(y < x); } -template -inline bool operator>=(const multiset& x, const multiset& y) -{ return !(x < y); } +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return !(x < y); } -template -inline void swap(multiset& x, multiset& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(multiset_impl &x, multiset_impl &y) +#else +(multiset_impl &x, multiset_impl &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 +#else +template +#endif +struct make_multiset +{ + /// @cond + typedef multiset_impl + < typename make_rbtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class multiset + : public make_multiset::type +{ + typedef typename make_multiset + ::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::value)); + + multiset( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + 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(Base::container_from_end_iterator(end_iterator)); } + + static const multiset &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/set_hook.hpp b/include/boost/intrusive/set_hook.hpp index 1218c69..df0c164 100644 --- a/include/boost/intrusive/set_hook.hpp +++ b/include/boost/intrusive/set_hook.hpp @@ -17,16 +17,45 @@ #include #include #include -#include #include #include -#include -#include -#include +#include +#include namespace boost { namespace intrusive { +/// @cond +template +struct get_set_node_algo +{ + typedef rbtree_algorithms > 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 +#else +template +#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::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 @@ namespace intrusive { //! //! 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 +#else +template +#endif class set_base_hook - : private detail::rbtree_node_traits::node + : public make_set_base_hook::type { - public: - typedef detail::rbtree_node_traits node_traits; - enum { linking_policy = Policy }; - - /// @cond - private: - typedef rbtree_algorithms node_algorithms; - /// @endcond - - public: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef set_base_hook - this_type; - - typedef typename boost::pointer_to_other - ::type this_type_ptr; - - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - /// @cond - private: - - node_ptr this_as_node() - { return node_ptr(static_cast(this)); } - - const_node_ptr this_as_node() const - { return const_node_ptr(static_cast(this)); } - /// @endcond - - public: - //! Effects: If Policy is auto_unlink or safe_mode_linnk + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! - //! Throws: Nothing. - set_base_hook() - : node() - { - if(Policy == safe_link || Policy == auto_unlink){ - node_algorithms::init(this_as_node()); - } - } + //! Throws: Nothing. + set_base_hook(); - //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); //! Effects: Empty function. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); - //! Effects: 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. + //! Effects: 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. //! //! Throws: Nothing. - ~set_base_hook() - { detail::destructor_impl(*this, detail::dispatcher()); } + ~set_base_hook(); - //! Precondition: Policy must be safe_link or auto_unlink. + //! Effects: 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. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(set_base_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. //! //! Returns: 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. //! //! Complexity: 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; //! Effects: 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. //! //! Throws: Nothing. - void unlink() - { - BOOST_STATIC_ASSERT((Policy == auto_unlink)); - node_algorithms::unlink_and_rebalance(this_as_node()); - node_algorithms::init(this_as_node()); - } + void unlink(); + #endif +}; - //! 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 - struct value_traits - : detail::derivation_hook_value_traits - {}; +//! 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 +#else +template +#endif +struct make_set_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3>::type packed_options; - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static this_type_ptr to_hook_ptr(node_ptr p) - { - return this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static const_this_type_ptr to_hook_ptr(const_node_ptr p) - { - return const_this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Returns a pointer to the node that this hook holds. - //! - //! Throws: Nothing. - node_ptr to_node_ptr() - { return this_as_node(); } - - //! Effects: Returns a const pointer to the node that this hook holds. - //! - //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return this_as_node(); } + typedef detail::generic_hook + < get_set_node_algo + , 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 @@ class set_base_hook //! //! 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 +#else +template +#endif class set_member_hook - : private detail::rbtree_node_traits::node + : public make_set_member_hook::type { - public: - typedef detail::rbtree_node_traits node_traits; - enum { linking_policy = Policy }; - - /// @cond - private: - typedef rbtree_algorithms node_algorithms; - /// @endcond - - public: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef set_member_hook - this_type; - - typedef typename boost::pointer_to_other - ::type this_type_ptr; - - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - /// @cond - private: - node_ptr this_as_node() - { return node_ptr(static_cast(this)); } - - const_node_ptr this_as_node() const - { return const_node_ptr(static_cast(this)); } - /// @endcond - - public: - //! Effects: If Policy is auto_unlink or safe_mode_linnk + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! //! Throws: Nothing. - set_member_hook() - : node() - { - if(Policy == safe_link || Policy == auto_unlink){ - node_algorithms::init(this_as_node()); - } - } + set_member_hook(); - //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); //! Effects: Empty function. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); - //! Effects: 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. + //! Effects: 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. //! //! Throws: Nothing. - ~set_member_hook() - { detail::destructor_impl(*this, detail::dispatcher()); } + ~set_member_hook(); - //! Precondition: Policy must be safe_link or auto_unlink. + //! Effects: 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. //! - //! Complexity: 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()); - } + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(set_member_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: 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. + //! + //! Complexity: Constant + bool is_linked() const; //! Effects: 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. //! //! Throws: 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 - struct value_traits - : detail::member_hook_value_traits - {}; - - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static this_type_ptr to_hook_ptr(node_ptr p) - { - return this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static const_this_type_ptr to_hook_ptr(const_node_ptr p) - { - return const_this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Returns a pointer to the node that this hook holds. - //! - //! Throws: Nothing. - node_ptr to_node_ptr() - { return this_as_node(); } - - //! Effects: Returns a const pointer to the node that this hook holds. - //! - //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return this_as_node(); } + void unlink(); + #endif }; } //namespace intrusive diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 385c8e7..8cda94e 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -16,21 +16,60 @@ #include #include -#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING -#include -#endif +#include #include #include #include #include #include -#include +#include +#include #include #include namespace boost { namespace intrusive { +/// @cond + +template +struct internal_default_slist_hook +{ + template static detail::one test(...); + template static detail::two test(typename U::default_slist_hook* = 0); + static const bool value = sizeof(test(0)) == sizeof(detail::two); +}; + +template +struct get_default_slist_hook +{ typedef typename T::default_slist_hook type; }; + +template +struct slistopt +{ + typedef ValueTraits value_traits; + typedef SizeType size_type; + static const bool constant_time_size = ConstantTimeSize; +}; + +template +struct slist_defaults + : pack_options + < none + , base_hook + < typename detail::eval_if_c + < internal_default_slist_hook::value + , get_default_slist_hook + , detail::identity + >::type + > + , constant_time_size + , size_type + >::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 @@ namespace intrusive { //! 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,82 +93,120 @@ namespace intrusive { //! 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 +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class slist_impl { - /// @cond - private: - typename ValueTraits::node_traits::node root_; - - typedef slist this_type; - typedef typename ValueTraits::node_traits node_traits; - typedef detail::size_holder size_traits; - - //! This class is - //! non-copyable - slist (const slist&); - - //! This class is - //! non-asignable - slist &operator =(const slist&); - /// @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; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::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::value_type value_type; typedef typename std::iterator_traits::reference reference; typedef typename std::iterator_traits::reference const_reference; typedef typename std::iterator_traits::difference_type difference_type; - typedef SizeType size_type; - typedef detail::slist_iterator iterator; - typedef detail::slist_iterator const_iterator; + typedef typename Config::size_type size_type; + typedef slist_iterator iterator; + typedef slist_iterator const_iterator; + typedef typename real_value_traits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef circular_slist_algorithms node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; /// @cond private: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef circular_slist_algorithms node_algorithms; + typedef detail::size_holder size_traits; + + //! This class is + //! non-copyable + slist_impl (const slist_impl&); + + //! This class is + //! non-asignable + slist_impl &operator =(const slist_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))); 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(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_) const + { return data_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_.get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_; } + + real_value_traits &get_real_value_traits(detail::bool_) + { 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_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + public: //! Effects: constructs an empty list. //! @@ -136,9 +214,10 @@ class slist //! //! Throws: 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 @@ class slist //! Throws: If value_traits::node_traits::node //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). template - 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 @@ class slist //! 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. //! //! Complexity: 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(); } //! Effects: Erases all the elements of the container. @@ -185,7 +265,7 @@ class slist } 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 @@ class slist //! Note: 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(); } //! Effects: Erases the first element of the list. @@ -234,7 +314,7 @@ class slist { 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 @@ class slist { 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)); } //! Effects: Returns a reference to the first element of the list. @@ -263,7 +343,7 @@ class slist //! //! Complexity: 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())); } //! Effects: Returns a const_reference to the first element of the list. //! @@ -271,7 +351,7 @@ class slist //! //! Complexity: 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()))); } //! Effects: Returns an iterator to the first element contained in the list. //! @@ -279,7 +359,7 @@ class slist //! //! Complexity: Constant. iterator begin() - { return iterator (node_traits::get_next(this->get_root_node())); } + { return iterator (node_traits::get_next(this->get_root_node()), this); } //! Effects: Returns a const_iterator to the first element contained in the list. //! @@ -287,7 +367,7 @@ class slist //! //! Complexity: 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); } //! Effects: Returns a const_iterator to the first element contained in the list. //! @@ -295,7 +375,7 @@ class slist //! //! Complexity: 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); } //! Effects: Returns an iterator to the end of the list. //! @@ -303,7 +383,7 @@ class slist //! //! Complexity: Constant. iterator end() - { return iterator (this->get_root_node()); } + { return iterator (this->get_root_node(), this); } //! Effects: Returns a const_iterator to the end of the list. //! @@ -311,7 +391,7 @@ class slist //! //! Complexity: Constant. const_iterator end() const - { return const_iterator (uncast(this->get_root_node())); } + { return const_iterator (uncast(this->get_root_node()), this); } //! Effects: Returns a const_iterator to the end of the list. //! @@ -319,7 +399,7 @@ class slist //! //! Complexity: Constant. const_iterator cend() const - { return const_iterator (uncast(this->get_root_node())); } + { return const_iterator (uncast(this->get_root_node()), this); } //! Effects: Returns an iterator that points to a position //! before the first element. Equivalent to "end()" @@ -356,11 +436,8 @@ class slist //! Throws: Nothing. //! //! Complexity: Constant. - static slist &container_from_end_iterator(iterator end_iterator) - { - return *detail::parent_from_member - ( 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); } //! Precondition: end_iterator must be a valid end const_iterator //! of slist. @@ -370,24 +447,21 @@ class slist //! Throws: Nothing. //! //! Complexity: Constant. - static const slist &container_from_end_iterator(const_iterator end_iterator) - { - return *detail::parent_from_member - ( 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); } //! Effects: Returns the number of the elements contained in the list. //! //! Throws: Nothing. //! //! Complexity: 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. //! //! Note: 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 @@ class slist //! Complexity: Linear to the number of elements of both lists. //! //! Note: 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 @@ class slist //! //! Throws: If cloner throws. template - 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 } //! Requires: value must be an lvalue and prev_p must point to an element @@ -569,12 +639,12 @@ class slist //! Note: 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); } //! Requires: Dereferencing iterator must yield @@ -644,7 +714,7 @@ class slist 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 @@ class slist 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 @@ class slist //! //! Note: 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 @@ class slist ( 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 @@ class slist //! //! Note: 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 @@ class slist //! Throws: Nothing. //! //! Complexity: Linear to the number of elements transferred - //! if ConstantTimeSize is true. Constant-time otherwise. + //! if constant_time_size is true. Constant-time otherwise. //! //! Note: 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 @@ class slist //! //! Note: 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 @@ class slist //! //! Note: 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); } //! Requires: it p must be a valid iterator of *this. @@ -991,7 +1061,7 @@ class slist //! //! Note: 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)); } //! Requires: pos must be a dereferenceable iterator in *this @@ -1004,11 +1074,11 @@ class slist //! Throws: Nothing. //! //! Complexity: 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. //! //! Note: 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)); } //! Requires: pos must be a dereferenceable iterator in *this @@ -1025,7 +1095,7 @@ class slist //! //! Note: 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); } //! Effects: This function sorts the list *this according to std::less. @@ -1044,8 +1114,8 @@ class slist { 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 @@ class slist } 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 @@ class slist 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 @@ class slist //! //! Note: Iterators and references are not invalidated. template - 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 @@ class slist //! size() + x.size() - 1 comparisons. //! //! Note: Iterators and references are not invalidated - void merge(slist& x) + void merge(slist_impl& x) { this->merge(x, std::less()); } //! Effects: Reverses the order of elements in the list. @@ -1328,10 +1399,13 @@ class slist //! Complexity: Constant time. //! //! Note: Iterators and references are not invalidated. - static iterator iterator_to(reference value) - { - BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(value))); - return iterator (ValueTraits::to_node_ptr(value)); + //! This static function is available only if the value traits + //! 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); } //! Requires: value must be a const reference to a value inserted in a list. @@ -1343,10 +1417,43 @@ class slist //! Complexity: Constant time. //! //! Note: Iterators and references are not invalidated. - static const_iterator iterator_to(const_reference value) + //! This static function is available only if the value traits + //! 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 (value)))); + return const_iterator (value_traits::to_node_ptr(const_cast (value)), 0); + } + + //! Requires: value must be a reference to a value inserted in a list. + //! + //! Effects: This function returns a const_iterator pointing to the element + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + iterator iterator_to(reference value) { - BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast (value)))); - return const_iterator (ValueTraits::to_node_ptr(const_cast (value))); + BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(value))); + return iterator (value_traits::to_node_ptr(value), this); + } + + //! Requires: value must be a const reference to a value inserted in a list. + //! + //! Effects: This function returns an iterator pointing to the element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + const_iterator iterator_to(const_reference value) const + { + BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(const_cast (value)))); + return const_iterator (value_traits::to_node_ptr(const_cast (value)), this); } //! Returns: The iterator to the element before i in the list. @@ -1360,7 +1467,7 @@ class slist { return iterator (node_algorithms::get_previous_node - (before_begin().pointed_node(), i.pointed_node())); + (before_begin().pointed_node(), i.pointed_node()), 0); } //! Returns: The const_iterator to the element before i in the list. @@ -1374,17 +1481,52 @@ class slist { 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 + ( detail::get_pointer(end_iterator.pointed_node()), &root_plus_size::root_); + data_t *d = detail::parent_from_member + ( r, &data_t::root_plus_size_); + slist_impl *s = detail::parent_from_member(d, &slist_impl::data_); + return *s; } }; -template -inline bool operator==(const slist& x, const slist& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator< +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +bool operator== +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif { + typedef slist_impl 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::const_iterator const_iterator; const_iterator end1 = x.end(); const_iterator i1 = x.begin(); @@ -1406,31 +1548,131 @@ inline bool operator==(const slist& x, const slist& y) } } -template -inline bool operator<(const slist& x, - const slist& y) -{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - -template -inline bool operator!=(const slist& x, const slist& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif { return !(x == y); } -template -inline bool operator>(const slist& x, const slist& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif { return y < x; } -template -inline bool operator<=(const slist& x, const slist& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif { return !(y < x); } -template -inline bool operator>=(const slist& x, const slist& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif { return !(x < y); } -template -inline void swap(slist& x, slist& y) +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(slist_impl &x, slist_impl &y) +#else +(slist_impl &x, slist_impl &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 +#else +template +#endif +struct make_slist +{ + /// @cond + typedef typename pack_options + < slist_defaults, O1, O2, O3>::type packed_options; + typedef typename detail::get_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 slist + : public make_slist::type +{ + typedef typename make_slist + ::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::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 + 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(Base::container_from_end_iterator(end_iterator)); } + + static const slist &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/slist_hook.hpp b/include/boost/intrusive/slist_hook.hpp index 97b65ca..a08f071 100644 --- a/include/boost/intrusive/slist_hook.hpp +++ b/include/boost/intrusive/slist_hook.hpp @@ -17,19 +17,48 @@ #include #include #include -#include #include #include -#include -#include -#include +#include +#include namespace boost { namespace intrusive { +/// @cond +template +struct get_slist_node_algo +{ + typedef circular_slist_algorithms > 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 +#else +template +#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::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 @@ namespace intrusive { //! 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 +#else +template +#endif class slist_base_hook - : private detail::slist_node_traits::node + : public make_slist_base_hook::type { - public: - typedef detail::slist_node_traits node_traits; - enum { linking_policy = Policy }; - - /// @cond - private: - typedef circular_slist_algorithms node_algorithms; - /// @endcond - - public: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef slist_base_hook - this_type; - - typedef typename boost::pointer_to_other - ::type this_type_ptr; - - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - /// @cond - private: - node_ptr this_as_node() - { return node_ptr(static_cast(this)); } - - const_node_ptr this_as_node() const - { return const_node_ptr(static_cast(this)); } - /// @endcond - - public: - - //! Effects: If Policy is auto_unlink or safe_mode_linnk + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! //! Throws: Nothing. - slist_base_hook() - : node() - { - if(Policy == safe_link || Policy == auto_unlink){ - node_algorithms::init(this_as_node()); - } - } + slist_base_hook(); - //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); //! Effects: Empty function. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); - //! Effects: 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. + //! Effects: 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. //! //! Throws: Nothing. - ~slist_base_hook() - { detail::destructor_impl(*this, detail::dispatcher()); } + ~slist_base_hook(); //! Effects: 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 @@ class slist_base_hook //! Complexity: Constant //! //! Throws: 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); - //! Precondition: Policy must be safe_link or auto_unlink. + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. //! //! Returns: 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. //! //! Complexity: 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; //! Effects: 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. //! //! Throws: Nothing. - void unlink() - { - BOOST_STATIC_ASSERT((Policy == auto_unlink)); - node_algorithms::unlink(this_as_node()); - node_algorithms::init(this_as_node()); - } + void unlink(); + #endif +}; - //! 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 - struct value_traits - : detail::derivation_hook_value_traits - {}; +//! 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 +#else +template +#endif +struct make_slist_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3>::type packed_options; - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static this_type_ptr to_hook_ptr(node_ptr p) - { - return this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static const_this_type_ptr to_hook_ptr(const_node_ptr p) - { - return const_this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Returns a pointer to the node that this hook holds. - //! - //! Throws: Nothing. - node_ptr to_node_ptr() - { return this_as_node(); } - - //! Effects: Returns a const pointer to the node that this hook holds. - //! - //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return this_as_node(); } + typedef detail::generic_hook + < get_slist_node_algo + , 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. +//! an list. slist_member_hook holds the data necessary for maintaining the list and +//! provides an appropriate value_traits class for list. //! -//! 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. -//! -//! 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::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 +#else +template +#endif +class slist_member_hook + : public make_slist_member_hook::type { - public: - typedef detail::slist_node_traits node_traits; - enum { linking_policy = Policy }; - - /// @cond - private: - typedef circular_slist_algorithms node_algorithms; - /// @endcond - - public: - typedef typename node_traits::node node; - typedef typename boost::pointer_to_other - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef slist_member_hook - this_type; - - typedef typename boost::pointer_to_other - ::type this_type_ptr; - - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - /// @cond - private: - node_ptr this_as_node() - { return node_ptr(static_cast(this)); } - - const_node_ptr this_as_node() const - { return const_node_ptr(static_cast(this)); } - /// @endcond - - public: - //! Effects: If Policy is auto_unlink or safe_mode_linnk + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! //! Throws: Nothing. - slist_member_hook() - : node() - { - if(Policy == safe_link || Policy == auto_unlink){ - node_algorithms::init(this_as_node()); - } - } + slist_member_hook(); - //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); //! Effects: Empty function. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); - //! Effects: 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. + //! Effects: 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. //! //! Throws: Nothing. - ~slist_member_hook() - { detail::destructor_impl(*this, detail::dispatcher()); } + ~slist_member_hook(); //! Effects: 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 @@ class slist_member_hook //! //! Complexity: Constant //! - //! Throws: Nothing. - void swap_nodes(slist_member_hook& other) - { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); } + //! Throws: Nothing. + void swap_nodes(slist_member_hook &other); - //! Precondition: Policy must be safe_link or auto_unlink. + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. //! //! Returns: 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. //! - //! Complexity: 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()); - } + //! Complexity: Constant + bool is_linked() const; //! Effects: 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. //! //! Throws: 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 - struct value_traits - : detail::member_hook_value_traits - {}; - - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static this_type_ptr to_hook_ptr(node_ptr p) - { - return this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. - //! - //! Throws: Nothing. - static const_this_type_ptr to_hook_ptr(const_node_ptr p) - { - return const_this_type_ptr(static_cast (detail::get_pointer(p))); - } - - //! Effects: Returns a pointer to the node that this hook holds. - //! - //! Throws: Nothing. - node_ptr to_node_ptr() - { return this_as_node(); } - - //! Effects: Returns a const pointer to the node that this hook holds. - //! - //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return this_as_node(); } + void unlink(); + #endif }; } //namespace intrusive } //namespace boost -#include +#include #endif //BOOST_INTRUSIVE_SLIST_HOOK_HPP diff --git a/include/boost/intrusive/tag.hpp b/include/boost/intrusive/tag.hpp deleted file mode 100644 index 649b3af..0000000 --- a/include/boost/intrusive/tag.hpp +++ /dev/null @@ -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 diff --git a/include/boost/intrusive/trivial_value_traits.hpp b/include/boost/intrusive/trivial_value_traits.hpp index 3bb4250..3d8797e 100644 --- a/include/boost/intrusive/trivial_value_traits.hpp +++ b/include/boost/intrusive/trivial_value_traits.hpp @@ -13,7 +13,7 @@ #ifndef BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP #define BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP -#include +#include namespace boost { namespace intrusive { @@ -21,7 +21,7 @@ namespace intrusive { //!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 +template struct trivial_value_traits { typedef NodeTraits node_traits; @@ -30,11 +30,11 @@ struct trivial_value_traits 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 diff --git a/include/boost/intrusive/unordered_set.hpp b/include/boost/intrusive/unordered_set.hpp index 41d0467..392e83d 100644 --- a/include/boost/intrusive/unordered_set.hpp +++ b/include/boost/intrusive/unordered_set.hpp @@ -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 #include @@ -32,27 +32,22 @@ namespace intrusive { //! 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 @@ namespace intrusive { //! //! 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 - , class Equal //= std::equal_to - , bool ConstantTimeSize //= true - , class SizeType //= std::size_t - > -class unordered_set +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class unordered_set_impl { /// @cond private: - typedef hashtable table_type; + typedef hashtable_impl 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::reference reference; - typedef typename std::iterator_traits::reference const_reference; - typedef typename std::iterator_traits::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::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 @@ class unordered_set //! Requires: buckets must not be being used by any other resource. //! - //! Effects: Constructs an empty unordered_set, storing a reference + //! Effects: Constructs an empty unordered_set_impl, storing a reference //! to the bucket array and copies of the hasher and equal functors. //! //! Complexity: Constant. @@ -123,11 +123,11 @@ class unordered_set //! //! Notes: 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) {} //! Requires: buckets must not be being used by any other resource @@ -141,18 +141,18 @@ class unordered_set //! //! Throws: 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. //! //! Notes: buckets array must be disposed only after //! *this is disposed. template - 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); } //! Effects: Detaches all elements from this. The objects in the unordered_set @@ -162,7 +162,7 @@ class unordered_set //! it's a safe-mode or auto-unlink value. Otherwise constant. //! //! Throws: Nothing. - ~unordered_set() + ~unordered_set_impl() {} //! Effects: Returns an iterator pointing to the beginning of the unordered_set. @@ -236,7 +236,7 @@ class unordered_set //! Effects: Returns true is the container is empty. //! - //! Complexity: if ConstantTimeSize is false, average constant time + //! Complexity: 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 @@ class unordered_set //! Effects: Returns the number of elements stored in the unordered_set. //! //! Complexity: Linear to elements contained in *this if - //! ConstantTimeSize is false. Constant-time otherwise. + //! constant-time size option is enabled. Constant-time otherwise. //! //! Throws: Nothing. size_type size() const @@ -263,7 +263,7 @@ class unordered_set //! //! Throws: 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_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -280,7 +280,7 @@ class unordered_set //! //! Throws: If cloner throws. Basic guarantee. template - 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); } //! Requires: value must be an lvalue @@ -433,13 +433,13 @@ class unordered_set //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If hasher or equal throw. Basic guarantee. + //! Throws: If hash_func or equal_func throw. Basic guarantee. //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - 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); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -493,7 +493,7 @@ class unordered_set //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: 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. //! //! Returns: The number of erased elements. @@ -501,13 +501,13 @@ class unordered_set //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If hasher or key_value_equal throw. Basic guarantee. + //! Throws: If hash_func or equal_func throw. Basic guarantee. //! //! Note: Invalidates the iterators //! to the erased elements. template - 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); } //! Effects: Erases all of the elements. //! @@ -544,22 +544,22 @@ class unordered_set size_type count(const_reference value) const { return table_.find(value) != end(); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns the number of contained elements with the given key //! //! Complexity: Average case O(1), worst case O(this->size()). //! - //! Throws: If hasher or equal throw. + //! Throws: If hash_func or equal_func throw. template - 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(); } //! Effects: Finds an iterator to the first element is equal to //! "value" or end() if that element does not exist. @@ -570,13 +570,13 @@ class unordered_set iterator find(const_reference value) { return table_.find(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: 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 @@ class unordered_set //! //! Complexity: Average case O(1), worst case O(this->size()). //! - //! Throws: If hasher or equal throw. + //! Throws: If hash_func or equal_func throw. //! //! Note: 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 - 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); } //! Effects: Finds a const_iterator to the first element whose key is //! "key" or end() if that element does not exist. @@ -602,13 +602,13 @@ class unordered_set const_iterator find(const_reference value) const { return table_.find(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: 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 @@ class unordered_set //! //! Complexity: Average case O(1), worst case O(this->size()). //! - //! Throws: If hasher or equal throw. + //! Throws: If hash_func or equal_func throw. //! //! Note: 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 - 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); } //! Effects: 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 @@ class unordered_set std::pair equal_range(const_reference value) { return table_.equal_range(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns a range containing all elements with equivalent //! keys. Returns std::make_pair(this->end(), this->end()) if no such //! elements exist. //! - //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! Complexity: Average case O(this->count(key, hash_func, hash_func)). + //! Worst case O(this->size()). //! - //! Throws: If hasher or the equal throw. + //! Throws: If hash_func or the equal_func throw. //! //! Note: 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 - std::pair equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) - { return table_.equal_range(key, hasher, equal); } + std::pair equal_range(const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) + { return table_.equal_range(key, hash_func, equal_func); } //! Effects: 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 @@ class unordered_set equal_range(const_reference value) const { return table_.equal_range(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns a range containing all elements with equivalent //! keys. Returns std::make_pair(this->end(), this->end()) if no such //! elements exist. //! - //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! Complexity: Average case O(this->count(key, hash_func, equal_func)). + //! Worst case O(this->size()). //! - //! Throws: If the hasher or equal throw. + //! Throws: If the hash_func or equal_func throw. //! //! Note: 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 std::pair - 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); } //! Requires: value must be an lvalue and shall be in a unordered_set of //! appropriate type. Otherwise the behavior is undefined. @@ -726,8 +728,11 @@ class unordered_set //! Complexity: Constant. //! //! Throws: Nothing. - static local_iterator local_iterator_to(reference value) - { return table_type::local_iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static local_iterator s_local_iterator_to(reference value) + { return table_type::s_local_iterator_to(value); } //! Requires: value must be an lvalue and shall be in a unordered_set of //! appropriate type. Otherwise the behavior is undefined. @@ -738,8 +743,35 @@ class unordered_set //! Complexity: Constant. //! //! Throws: Nothing. - static const_local_iterator local_iterator_to(const_reference value) - { return table_type::local_iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_local_iterator s_local_iterator_to(const_reference value) + { return table_type::s_local_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid local_iterator belonging to the unordered_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + local_iterator local_iterator_to(reference value) + { return table_.local_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_local_iterator belonging to + //! the unordered_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_local_iterator local_iterator_to(const_reference value) const + { return table_.local_iterator_to(value); } //! Effects: Returns the number of buckets passed in the constructor //! or the last rehash function. @@ -771,21 +803,21 @@ class unordered_set size_type bucket(const value_type& k) const { return table_.bucket(k); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: Returns the index of the bucket in which elements //! with keys equivalent to k would be found, if any such element existed. //! //! Complexity: Constant. //! - //! Throws: If hasher throws. + //! Throws: If hash_func throws. //! //! Note: the return value is in the range [0, this->bucket_count()). template - 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); } //! Effects: Returns the bucket array pointer passed in the constructor //! or the last rehash function. @@ -891,8 +923,8 @@ class unordered_set //! Complexity: Average case linear in this->size(), worst case quadratic. //! //! Throws: 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); } //! Effects: Returns the nearest new bucket count optimized for //! the container that is bigger than n. This suggestion can be used @@ -919,6 +951,70 @@ class unordered_set { 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 +#else +template +#endif +struct make_unordered_set +{ + /// @cond + typedef unordered_set_impl + < typename make_hashtable_opt + ::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class unordered_set + : public make_unordered_set::type +{ + typedef typename make_unordered_set + ::type Base; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::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 + 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 @@ class unordered_set //! 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 \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_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 @@ class unordered_set //! //! 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 - , class Equal //= std::equal_to - , bool ConstantTimeSize //= true - , class SizeType //= std::size_t - > -class unordered_multiset +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class unordered_multiset_impl { /// @cond private: - typedef hashtable table_type; + typedef hashtable_impl 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::reference reference; - typedef typename std::iterator_traits::reference const_reference; - typedef typename std::iterator_traits::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::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 @@ class unordered_multiset //! //! Notes: 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) {} //! Requires: buckets must not be being used by any other resource @@ -1039,18 +1135,18 @@ class unordered_multiset //! //! Throws: 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. //! //! Notes: buckets array must be disposed only after //! *this is disposed. template - 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); } //! Effects: Detaches all elements from this. The objects in the unordered_multiset @@ -1060,7 +1156,7 @@ class unordered_multiset //! it's a safe-mode or auto-unlink value. Otherwise constant. //! //! Throws: Nothing. - ~unordered_multiset() + ~unordered_multiset_impl() {} //! Effects: Returns an iterator pointing to the beginning of the unordered_multiset. @@ -1134,7 +1230,7 @@ class unordered_multiset //! Effects: Returns true is the container is empty. //! - //! Complexity: if ConstantTimeSize is false, average constant time + //! Complexity: 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 @@ class unordered_multiset //! Effects: Returns the number of elements stored in the unordered_multiset. //! //! Complexity: Linear to elements contained in *this if - //! ConstantTimeSize is false. Constant-time otherwise. + //! constant-time size option is enabled. Constant-time otherwise. //! //! Throws: Nothing. size_type size() const @@ -1162,7 +1258,7 @@ class unordered_multiset //! //! Throws: 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_); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -1179,7 +1275,7 @@ class unordered_multiset //! //! Throws: If cloner throws. template - 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); } //! Requires: value must be an lvalue @@ -1202,8 +1298,8 @@ class unordered_multiset //! //! Effects: Equivalent to this->insert(t) for each element in [b, e). //! - //! Complexity: 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 + //! Complexity: 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(). //! //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. @@ -1251,9 +1347,9 @@ class unordered_multiset size_type erase(const_reference value) { return table_.erase(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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 @@ class unordered_multiset //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If the hasher or the equal functors throws. Basic guarantee. + //! Throws: If the hash_func or the equal_func functors throws. + //! Basic guarantee. //! //! Note: Invalidates the iterators (but not the references) //! to the erased elements. No destructors are called. template - 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); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1327,7 +1424,7 @@ class unordered_multiset //! Requires: Disposer::operator()(pointer) shouldn't throw. //! //! Effects: 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. //! //! Returns: The number of erased elements. @@ -1335,13 +1432,13 @@ class unordered_multiset //! Complexity: Average case O(this->count(value)). //! Worst case O(this->size()). //! - //! Throws: If hasher or equal throw. Basic guarantee. + //! Throws: If hash_func or equal_func throw. Basic guarantee. //! //! Note: Invalidates the iterators //! to the erased elements. template - 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); } //! Effects: Erases all the elements of the container. //! @@ -1378,9 +1475,9 @@ class unordered_multiset size_type count(const_reference value) const { return table_.count(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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 @@ class unordered_multiset //! //! Throws: If the internal hasher or the equality functor throws. template - 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); } //! Effects: Finds an iterator to the first element whose value is //! "value" or end() if that element does not exist. @@ -1404,9 +1501,9 @@ class unordered_multiset iterator find(const_reference value) { return table_.find(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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 @@ class unordered_multiset //! is expensive and the value_type can be compared with a cheaper //! key type. Usually this key is part of the value_type. template - 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); } //! Effects: Finds a const_iterator to the first element whose key is //! "key" or end() if that element does not exist. @@ -1436,9 +1533,9 @@ class unordered_multiset const_iterator find(const_reference value) const { return table_.find(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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 @@ class unordered_multiset //! is expensive and the value_type can be compared with a cheaper //! key type. Usually this key is part of the value_type. template - 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); } //! Effects: 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 @@ class unordered_multiset std::pair equal_range(const_reference value) { return table_.equal_range(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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 @@ class unordered_multiset //! keys. Returns std::make_pair(this->end(), this->end()) if no such //! elements exist. //! - //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! Complexity: Average case O(this->count(key, hash_func, equal_func)). + //! Worst case O(this->size()). //! //! Throws: If the internal hasher or the equality functor throws. //! @@ -1489,8 +1587,9 @@ class unordered_multiset //! is expensive and the value_type can be compared with a cheaper //! key type. Usually this key is part of the value_type. template - std::pair equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) - { return table_.equal_range(key, hasher, equal); } + std::pair equal_range + (const KeyType& key, KeyHasher hash_func, KeyValueEqual equal_func) + { return table_.equal_range(key, hash_func, equal_func); } //! Effects: 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 @@ class unordered_multiset equal_range(const_reference value) const { return table_.equal_range(value); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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 @@ class unordered_multiset //! keys. Returns std::make_pair(this->end(), this->end()) if no such //! elements exist. //! - //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! Complexity: Average case O(this->count(key, hash_func, equal_func)). + //! Worst case O(this->size()). //! //! Throws: If the internal hasher or the equality functor throws. //! @@ -1524,8 +1624,8 @@ class unordered_multiset //! key type. Usually this key is part of the value_type. template std::pair - 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); } //! Requires: value must be an lvalue and shall be in a unordered_multiset of //! appropriate type. Otherwise the behavior is undefined. @@ -1551,29 +1651,59 @@ class unordered_multiset const_iterator iterator_to(const_reference value) const { return table_.iterator_to(value); } - //! Requires: value must be an lvalue and shall be in a unordered_multiset of + //! Requires: value must be an lvalue and shall be in a unordered_set of //! appropriate type. Otherwise the behavior is undefined. //! - //! Effects: Returns: a valid local_iterator belonging to the unordered_multiset + //! Effects: Returns: a valid local_iterator belonging to the unordered_set //! that points to the value //! //! Complexity: Constant. //! //! Throws: Nothing. - static local_iterator local_iterator_to(reference value) - { return table_type::local_iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static local_iterator s_local_iterator_to(reference value) + { return table_type::s_local_iterator_to(value); } - //! Requires: value must be an lvalue and shall be in a unordered_multiset of + //! Requires: value must be an lvalue and shall be in a unordered_set of //! appropriate type. Otherwise the behavior is undefined. //! //! Effects: Returns: a valid const_local_iterator belonging to - //! the unordered_multiset that points to the value + //! the unordered_set that points to the value //! //! Complexity: Constant. //! //! Throws: Nothing. - static const_local_iterator local_iterator_to(const_reference value) - { return table_type::local_iterator_to(value); } + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_local_iterator s_local_iterator_to(const_reference value) + { return table_type::s_local_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid local_iterator belonging to the unordered_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + local_iterator local_iterator_to(reference value) + { return table_.local_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_local_iterator belonging to + //! the unordered_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_local_iterator local_iterator_to(const_reference value) const + { return table_.local_iterator_to(value); } //! Effects: Returns the number of buckets passed in the constructor //! or the last rehash function. @@ -1605,9 +1735,9 @@ class unordered_multiset size_type bucket(const value_type& k) const { return table_.bucket(k); } - //! Requires: "hasher" must be a hash function that induces + //! Requires: "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. //! //! Effects: 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 @@ class unordered_multiset //! //! Note: the return value is in the range [0, this->bucket_count()). template - 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); } //! Effects: Returns the bucket array pointer passed in the constructor //! or the last rehash function. @@ -1725,8 +1855,8 @@ class unordered_multiset //! Complexity: Average case linear in this->size(), worst case quadratic. //! //! Throws: 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); } //! Effects: Returns the nearest new bucket count optimized for //! the container that is bigger than n. This suggestion can be used @@ -1753,9 +1883,71 @@ class unordered_multiset { 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 +#else +template +#endif +struct make_unordered_multiset +{ + /// @cond + typedef unordered_multiset_impl + < typename make_hashtable_opt + ::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class unordered_multiset + : public make_unordered_multiset::type +{ + typedef typename make_unordered_multiset + ::type Base; + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::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 + 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 -#endif //BOOST_INTRUSIVE_HASHSET_HPP +#endif //BOOST_INTRUSIVE_UNORDERED_SET_HPP diff --git a/include/boost/intrusive/unordered_set_hook.hpp b/include/boost/intrusive/unordered_set_hook.hpp index 65d4605..9096911 100644 --- a/include/boost/intrusive/unordered_set_hook.hpp +++ b/include/boost/intrusive/unordered_set_hook.hpp @@ -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 #include #include -#include #include -#include +#include +#include namespace boost { namespace intrusive { +/// @cond +template +struct get_uset_node_algo +{ + typedef circular_slist_algorithms > 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 +#else +template +#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::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 @@ namespace intrusive { //! //! 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 +#else +template +#endif class unordered_set_base_hook + : public make_unordered_set_base_hook::type { - /// @cond - typedef slist_base_hook 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 - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef unordered_set_base_hook - this_type; - typedef typename boost::pointer_to_other - ::type this_type_ptr; - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - //! Effects: If Policy is auto_unlink or safe_mode_linnk + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! - //! Throws: Nothing. - unordered_set_base_hook() - : m_slisthook() - {} + //! Throws: Nothing. + unordered_set_base_hook(); - //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. The argument is ignored. //! - //! Throws: Nothing. + //! Throws: Nothing. //! //! Rationale: 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& ); //! Effects: Empty function. The argument is ignored. //! - //! Throws: Nothing. + //! Throws: Nothing. //! //! Rationale: 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& ); - //! Effects: 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. + //! Effects: 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. //! - //! Throws: Nothing. - ~unordered_set_base_hook() - {} //m_slisthook's destructor does the job + //! Throws: Nothing. + ~unordered_set_base_hook(); - //! Precondition: Policy must be safe_link or auto_unlink. + //! Effects: 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. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(unordered_set_base_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. //! //! Returns: 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. //! - //! Complexity: Constant - bool is_linked() const - { return m_slisthook.is_linked(); } + //! Complexity: Constant + bool is_linked() const; - //! 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 - struct value_traits - : detail::derivation_hook_value_traits - {}; - - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. //! - //! Throws: 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))); - } + //! Throws: Nothing. + void unlink(); + #endif +}; - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. - //! - //! Throws: 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))); - } - //! Effects: Returns a pointer to the node that this hook holds. - //! - //! Throws: Nothing. - node_ptr to_node_ptr() - { return m_slisthook.to_node_ptr(); } +//! 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 +#else +template +#endif +struct make_unordered_set_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3>::type packed_options; - //! Effects: Returns a const pointer to the node that this hook holds. - //! - //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return m_slisthook.to_node_ptr(); } + typedef detail::generic_hook + < get_uset_node_algo + , 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 @@ class unordered_set_base_hook //! //! 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 +#else +template +#endif class unordered_set_member_hook + : public make_unordered_set_member_hook::type { - /// @cond - typedef slist_member_hook 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 - ::type node_ptr; - typedef typename boost::pointer_to_other - ::type const_node_ptr; - typedef unordered_set_member_hook - this_type; - typedef typename boost::pointer_to_other - ::type this_type_ptr; - typedef typename boost::pointer_to_other - ::type const_this_type_ptr; - - public: - //! Effects: If Policy is auto_unlink or safe_mode_linnk + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. //! //! Throws: Nothing. - unordered_set_member_hook() - : m_slisthook() - {} + unordered_set_member_hook(); - //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! Effects: If link_mode is \c auto_unlink or \c safe_link //! initializes the node to an unlinked state. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); //! Effects: Empty function. The argument is ignored. //! //! Throws: Nothing. //! //! Rationale: 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& ); - //! Effects: 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. + //! Effects: 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. //! //! Throws: Nothing. - ~unordered_set_member_hook() - {} //m_slisthook's destructor does the job + ~unordered_set_member_hook(); - //! Precondition: Policy must be safe_link or auto_unlink. + //! Effects: 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. //! //! Complexity: Constant - bool is_linked() const - { return m_slisthook.is_linked(); } + //! + //! Throws: Nothing. + void swap_nodes(unordered_set_member_hook &other); - //! 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 - struct value_traits - : detail::member_hook_value_traits - {}; + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: 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. + //! + //! Complexity: Constant + bool is_linked() const; //! Effects: 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. //! //! Throws: Nothing. - void unlink() - { m_slisthook.unlink(); } - - //! Effects: Converts a pointer to a node into - //! a pointer to the hook that holds that node. - //! - //! Throws: 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))); - } - - //! Effects: Converts a const pointer to a node stored in a container into - //! a const pointer to the hook that holds that node. - //! - //! Throws: 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))); - } - - //! Effects: Returns a pointer to the node that this hook holds. - //! - //! Throws: Nothing. - node_ptr to_node_ptr() - { return m_slisthook.to_node_ptr(); } - - //! Effects: Returns a const pointer to the node that this hook holds. - //! - //! Throws: Nothing. - const_node_ptr to_node_ptr() const - { return m_slisthook.to_node_ptr(); } + void unlink(); + #endif }; } //namespace intrusive @@ -287,4 +255,4 @@ class unordered_set_member_hook #include -#endif //BOOST_INTRUSIVE_HASHSET_HOOK_HPP +#endif //BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP