Changes introduced by the new intrusive version.

[SVN r39548]
This commit is contained in:
Ion Gaztañaga
2007-09-26 15:26:35 +00:00
parent 7338abf061
commit 2ddf5b904b
32 changed files with 5852 additions and 3217 deletions

View File

@@ -48,6 +48,7 @@ class circular_slist_algorithms
public: public:
typedef typename NodeTraits::node_ptr node_ptr; typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr; typedef typename NodeTraits::const_node_ptr const_node_ptr;
typedef NodeTraits node_traits;
//! <b>Requires</b>: this_node must be in a circular list or be an empty circular list. //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
//! //!

View File

@@ -13,7 +13,7 @@
#ifndef BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP #ifndef BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP #define BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/link_mode.hpp>
#include <iterator> #include <iterator>
namespace boost { namespace boost {
@@ -22,7 +22,7 @@ namespace intrusive {
//!This value traits template is used to create value traits //!This value traits template is used to create value traits
//!from user defined node traits where value_traits::value_type will //!from user defined node traits where value_traits::value_type will
//!derive from node_traits::node //!derive from node_traits::node
template<class T, class NodeTraits, linking_policy Policy> template<class T, class NodeTraits, link_mode_type LinkMode = safe_link>
struct derivation_value_traits struct derivation_value_traits
{ {
public: public:
@@ -35,8 +35,7 @@ struct derivation_value_traits
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer; typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef typename std::iterator_traits<pointer>::reference reference; typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference; typedef typename std::iterator_traits<const_pointer>::reference const_reference;
static const link_mode_type link_mode = LinkMode;
enum { linking_policy = Policy };
static node_ptr to_node_ptr(reference value) static node_ptr to_node_ptr(reference value)
{ return node_ptr(&value); } { return node_ptr(&value); }

View File

@@ -10,12 +10,10 @@
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_SELECT_COMPILER_INCLUDED #ifndef BOOST_INTRUSIVE_CONFIG_INCLUDED
#ifndef BOOST_COMPILER_CONFIG #define BOOST_INTRUSIVE_CONFIG_INCLUDED
#include <boost/config.hpp> #include <boost/config.hpp>
#endif #endif
#define BOOST_INTRUSIVE_SELECT_COMPILER_INCLUDED
#endif
#ifdef BOOST_MSVC #ifdef BOOST_MSVC

View File

@@ -35,7 +35,7 @@ class ebo_functor_holder_impl
template<typename T> template<typename T>
class ebo_functor_holder_impl<T, false> class ebo_functor_holder_impl<T, false>
: private T : public T
{ {
public: public:
ebo_functor_holder_impl(){} ebo_functor_holder_impl(){}

View File

@@ -0,0 +1,185 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_GENERIC_HOOK_HPP
#define BOOST_INTRUSIVE_GENERIC_HOOK_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/static_assert.hpp>
namespace boost {
namespace intrusive {
namespace detail {
/// @cond
enum
{ NoBaseHook
, ListBaseHook
, SlistBaseHook
, SetBaseHook
, UsetBaseHook
};
struct no_default_definer{};
template <class Hook, unsigned int>
struct default_definer;
template <class Hook>
struct default_definer<Hook, ListBaseHook>
{ typedef Hook default_list_hook; };
template <class Hook>
struct default_definer<Hook, SlistBaseHook>
{ typedef Hook default_slist_hook; };
template <class Hook>
struct default_definer<Hook, SetBaseHook>
{ typedef Hook default_set_hook; };
template <class Hook>
struct default_definer<Hook, UsetBaseHook>
{ typedef Hook default_uset_hook; };
template <class Hook, unsigned int BaseHookType>
struct make_default_definer
{
typedef typename detail::if_c
< BaseHookType != 0
, default_definer<Hook, BaseHookType>
, no_default_definer>::type type;
};
template
< class GetNodeAlgorithms
, class Tag
, link_mode_type LinkMode
, int HookType
>
struct make_node_holder
{
typedef typename detail::if_c
<!detail::is_same<Tag, member_tag>::value
, detail::node_holder
< typename GetNodeAlgorithms::type::node_traits::node
, Tag
, LinkMode
, HookType>
, typename GetNodeAlgorithms::type::node_traits::node
>::type type;
};
/// @endcond
template
< class GetNodeAlgorithms
, class Tag
, link_mode_type LinkMode
, int HookType
>
class generic_hook
/// @cond
//If the hook is a base hook, derive generic hook from detail::node_holder
//so that a unique base class is created to convert from the node
//to the type. This mechanism will be used by base_hook_traits.
//
//If the hook is a member hook, generic hook will directly derive
//from the hook.
: public make_default_definer
< generic_hook<GetNodeAlgorithms, Tag, LinkMode, HookType>
, detail::is_same<Tag, default_tag>::value*HookType
>::type
, public make_node_holder<GetNodeAlgorithms, Tag, LinkMode, HookType>::type
/// @endcond
{
public:
/// @cond
struct boost_intrusive_tags
{
static const int hook_type = HookType;
static const link_mode_type link_mode = LinkMode;
typedef Tag tag;
typedef typename GetNodeAlgorithms::type node_algorithms;
typedef typename node_algorithms::node_traits node_traits;
typedef typename node_traits::node node;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
static const bool is_base_hook = !detail::is_same<Tag, member_tag>::value;
enum { safemode_or_autounlink =
(int)link_mode == (int)auto_unlink ||
(int)link_mode == (int)safe_link };
};
/// @endcond
generic_hook()
{
if(boost_intrusive_tags::safemode_or_autounlink){
boost_intrusive_tags::node_algorithms::init
(static_cast<typename boost_intrusive_tags::node*>(this));
}
}
generic_hook(const generic_hook& )
{
if(boost_intrusive_tags::safemode_or_autounlink){
boost_intrusive_tags::node_algorithms::init
(static_cast<typename boost_intrusive_tags::node*>(this));
}
}
generic_hook& operator=(const generic_hook& )
{ return *this; }
~generic_hook()
{
destructor_impl
(*this, detail::link_dispatch<boost_intrusive_tags::link_mode>());
}
void swap_nodes(generic_hook &other)
{
boost_intrusive_tags::node_algorithms::swap_nodes
( static_cast<typename boost_intrusive_tags::node*>(this)
, static_cast<typename boost_intrusive_tags::node*>(&other));
}
bool is_linked() const
{
//is_linked() can be only used in safe-mode or auto-unlink
BOOST_STATIC_ASSERT(( boost_intrusive_tags::safemode_or_autounlink ));
return !boost_intrusive_tags::node_algorithms::unique
(static_cast<const typename boost_intrusive_tags::node*>(this));
}
void unlink()
{
BOOST_STATIC_ASSERT(( (int)boost_intrusive_tags::link_mode == (int)auto_unlink ));
boost_intrusive_tags::node_algorithms::unlink
(static_cast<typename boost_intrusive_tags::node*>(this));
boost_intrusive_tags::node_algorithms::init
(static_cast<typename boost_intrusive_tags::node*>(this));
}
};
} //namespace detail
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_GENERIC_HOOK_HPP

View File

@@ -18,14 +18,9 @@
#include <boost/intrusive/detail/assert.hpp> #include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp> #include <boost/intrusive/circular_list_algorithms.hpp>
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
#include <boost/iterator/iterator_facade.hpp>
#endif
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#endif
#include <boost/intrusive/detail/mpl.hpp> #include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/slist_node.hpp> //remove-me
#include <cstddef> #include <cstddef>
namespace boost { namespace boost {
@@ -52,27 +47,34 @@ template<int Dummy>
const std::size_t prime_list_holder<Dummy>::prime_list_size const std::size_t prime_list_holder<Dummy>::prime_list_size
= sizeof(prime_list)/sizeof(std::size_t); = sizeof(prime_list)/sizeof(std::size_t);
template <class SlistImpl> template <class Slist>
struct bucket_type_impl struct bucket_impl : public Slist
: public SlistImpl
{ {
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&) ~bucket_impl()
{ SlistImpl::clear(); }
static typename std::iterator_traits
<typename SlistImpl::const_iterator>::difference_type
get_bucket_num
( typename SlistImpl::const_iterator it
, const bucket_type_impl<SlistImpl> &first_bucket
, const bucket_type_impl<SlistImpl> &last_bucket)
{ {
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<Slist> &first_bucket
, const bucket_impl<Slist> &last_bucket)
{
typename Slist::const_iterator
first(first_bucket.cend()), last(last_bucket.cend()); first(first_bucket.cend()), last(last_bucket.cend());
//The end node is embedded in the singly linked list: //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.pointed_node() <= last.pointed_node())){
++it; ++it;
} }
//Now get the bucket_type_impl from the iterator //Now get the bucket_impl from the iterator
const bucket_type_impl &b = static_cast<const bucket_type_impl&> const bucket_impl &b = static_cast<const bucket_impl&>
(SlistImpl::container_from_end_iterator(it)); (Slist::container_from_end_iterator(it));
//Now just calculate the index b has in the bucket array //Now just calculate the index b has in the bucket array
return &b - &first_bucket; return &b - &first_bucket;
} }
static SlistImpl &bucket_to_slist(bucket_type_impl<SlistImpl> &b)
{ return static_cast<SlistImpl &>(b); }
static const SlistImpl &bucket_to_slist(const bucket_type_impl<SlistImpl> &b)
{ return static_cast<const SlistImpl &>(b); }
}; };
template<class SlistImpl> template<class Slist>
struct bucket_info_impl struct bucket_traits_impl
{ {
/// @cond
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
< typename SlistImpl::pointer < typename Slist::pointer, bucket_impl<Slist> >::type bucket_ptr;
, bucket_type_impl<SlistImpl> >::type bucket_ptr; typedef typename Slist::size_type size_type;
typedef typename SlistImpl::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_; bucket_ptr buckets_;
size_type buckets_len_; size_type buckets_len_;
}; };
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE template<class Container, bool IsConst>
template<class Value, class SlistImpl>
class hashtable_iterator class hashtable_iterator
: public boost::iterator_facade : public std::iterator
< hashtable_iterator<Value, SlistImpl> < std::forward_iterator_tag
, Value , typename detail::add_const_if_c
, boost::forward_traversal_tag <typename Container::value_type, IsConst>::type
, Value&
, typename std::iterator_traits<typename SlistImpl::iterator>::difference_type
> >
{ {
typedef typename SlistImpl::iterator local_iterator; typedef typename Container::real_value_traits real_value_traits;
typedef typename SlistImpl::const_iterator const_local_iterator; typedef typename Container::siterator siterator;
typedef typename SlistImpl::value_traits::node_ptr node_ptr; typedef typename Container::const_siterator const_siterator;
typedef typename SlistImpl::value_traits::const_node_ptr const_node_ptr; typedef typename Container::bucket_type bucket_type;
typedef bucket_type_impl<SlistImpl> bucket_type;
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
< typename SlistImpl::pointer, bucket_type>::type bucket_ptr; < typename Container::pointer, const Container>::type const_cont_ptr;
typedef typename boost::pointer_to_other typedef typename Container::size_type size_type;
< typename SlistImpl::pointer, const bucket_type>::type const_bucket_ptr;
typedef detail::bucket_info_impl<SlistImpl> bucket_info_t;
typedef typename boost::pointer_to_other
<bucket_ptr, bucket_info_t>::type bucket_info_ptr;
typedef typename boost::pointer_to_other
<bucket_ptr, const bucket_info_t>::type const_bucket_info_ptr;
typedef typename SlistImpl::size_type size_type;
struct enabler {};
public: public:
hashtable_iterator () typedef typename detail::add_const_if_c
{} <typename Container::value_type, IsConst>::type value_type;
explicit hashtable_iterator(local_iterator ptr, const_bucket_info_ptr bucket_info)
: local_it_ (ptr), bucket_info_ (bucket_info)
{}
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
template <class OtherValue>
hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other
,typename boost::enable_if<
boost::is_convertible<OtherValue*,Value*>
, enabler
>::type = enabler()
)
: local_it_(other.local_it_), bucket_info_(other.bucket_info_)
{}
#else
template <class OtherValue>
hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other,
typename enable_if<
is_convertible<OtherValue*,T*>
>::type* = 0)
: local_it_(other.local_it_), bucket_info_(other.bucket_info_)
{}
#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 <class, class> friend class hashtable_iterator;
template <class OtherValue>
bool equal(hashtable_iterator<OtherValue, SlistImpl> const& other) const
{ return other.local() == local_it_; }
void increment()
{
size_type buckets_len = bucket_info_->buckets_len_;
const_bucket_ptr buckets = bucket_info_->buckets_;
const_local_iterator first = bucket_type::bucket_to_slist(buckets[0]).cend();
const_local_iterator last = bucket_type::bucket_to_slist(buckets[buckets_len]).cend();
++local_it_;
if(first.pointed_node() <= local_it_.pointed_node() &&
local_it_.pointed_node() <= last.pointed_node()){
size_type n_bucket = (size_type)
bucket_type::get_bucket_num(local_it_, buckets[0], buckets[buckets_len]);
do{
if (++n_bucket == buckets_len){
local_it_ = bucket_info_->buckets_->end();
break;
}
local_it_ = bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).begin();
}
while (local_it_ == bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).end());
}
}
Value& dereference() const
{ return *local_it_; }
local_iterator local_it_;
const_bucket_info_ptr bucket_info_;
};
#else
template<class T, class SlistImpl>
class hashtable_iterator
: public std::iterator<std::forward_iterator_tag, T>
{
typedef typename SlistImpl::iterator local_iterator;
typedef typename SlistImpl::const_iterator const_local_iterator;
typedef typename SlistImpl::value_traits::node_ptr node_ptr;
typedef typename SlistImpl::value_traits::const_node_ptr const_node_ptr;
typedef bucket_type_impl<SlistImpl> bucket_type;
typedef typename boost::pointer_to_other
< typename SlistImpl::pointer, bucket_type>::type bucket_ptr;
typedef typename boost::pointer_to_other
< typename SlistImpl::pointer, const bucket_type>::type const_bucket_ptr;
typedef detail::bucket_info_impl<SlistImpl> bucket_info_t;
typedef typename boost::pointer_to_other
<bucket_ptr, bucket_info_t>::type bucket_info_ptr;
typedef typename boost::pointer_to_other
<bucket_ptr, const bucket_info_t>::type const_bucket_info_ptr;
typedef typename SlistImpl::size_type size_type;
struct enabler {};
public:
typedef T & reference;
typedef T * pointer;
hashtable_iterator () hashtable_iterator ()
{} {}
explicit hashtable_iterator(local_iterator ptr, const_bucket_info_ptr bucket_info) explicit hashtable_iterator(siterator ptr, const Container *cont)
: local_it_ (ptr), bucket_info_ (bucket_info) : slist_it_ (ptr), cont_ (cont)
{} {}
hashtable_iterator(const hashtable_iterator<Container, false> &other)
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE : slist_it_(other.slist_it()), cont_(other.get_container())
template <class OtherValue>
hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other
,typename boost::enable_if<
boost::is_convertible<OtherValue*,T*>
, enabler
>::type = enabler()
)
: local_it_(other.local_it_), bucket_info_(other.bucket_info_)
{} {}
#else
template <class OtherValue>
hashtable_iterator(hashtable_iterator<OtherValue, SlistImpl> const& other,
typename enable_if<is_convertible<OtherValue*, T*> >::type* = 0)
: local_it_(other.local_it_), bucket_info_(other.bucket_info_)
{}
#endif
const local_iterator &local() const const siterator &slist_it() const
{ return local_it_; } { return slist_it_; }
const_node_ptr pointed_node() const
{ return local_it_.pointed_node(); }
const const_bucket_info_ptr &bucket_info() const
{ return bucket_info_; }
public: public:
hashtable_iterator& operator++() hashtable_iterator& operator++()
{ increment(); return *this; } { this->increment(); return *this; }
hashtable_iterator operator++(int) hashtable_iterator operator++(int)
{ {
hashtable_iterator result (*this); hashtable_iterator result (*this);
increment(); this->increment();
return result; return result;
} }
friend bool operator== (const hashtable_iterator& i, const hashtable_iterator& i2) 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) friend bool operator!= (const hashtable_iterator& i, const hashtable_iterator& i2)
{ return !(i == i2); } { return !(i == i2); }
T& operator*() const value_type& operator*() const
{ return *local_it_; } { return *this->operator ->(); }
pointer operator->() const value_type* operator->() const
{ return &(*local_it_); } { 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: private:
void increment() void increment()
{ {
size_type buckets_len = bucket_info_->buckets_len_; const Container *cont = detail::get_pointer(cont_);
const_bucket_ptr buckets = bucket_info_->buckets_; bucket_type* buckets = detail::get_pointer(cont->bucket_pointer());
const_local_iterator first = bucket_type::bucket_to_slist(buckets[0]).cend(); size_type buckets_len = cont->bucket_count();
const_local_iterator last = bucket_type::bucket_to_slist(buckets[buckets_len]).cend(); const_siterator first(buckets[0].cend());
const_siterator last (buckets[buckets_len].cend());
++local_it_; ++slist_it_;
if(first.pointed_node() <= local_it_.pointed_node() && if(first.pointed_node() <= slist_it_.pointed_node() &&
local_it_.pointed_node() <= last.pointed_node()){ slist_it_.pointed_node()<= last.pointed_node() ){
size_type n_bucket = (size_type) 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{ do{
if (++n_bucket == buckets_len){ if (++n_bucket == buckets_len){
local_it_ = bucket_info_->buckets_->end(); slist_it_ = buckets->end();
break; 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_; siterator slist_it_;
const_bucket_info_ptr bucket_info_; const_cont_ptr cont_;
}; };
#endif
} //namespace detail { } //namespace detail {
} //namespace intrusive { } //namespace intrusive {

View File

@@ -19,35 +19,31 @@
#include <boost/intrusive/detail/assert.hpp> #include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp> #include <boost/intrusive/circular_list_algorithms.hpp>
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
#include <boost/iterator/iterator_facade.hpp>
#endif
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#endif
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
namespace detail {
// list_node_traits can be used with circular_list_algorithms and supplies // list_node_traits can be used with circular_list_algorithms and supplies
// a list_node holding the pointers needed for a double-linked list // a list_node holding the pointers needed for a double-linked list
// it is used by list_derived_node and list_member_node // it is used by list_derived_node and list_member_node
template<class VoidPointer>
struct list_node
{
typedef typename boost::pointer_to_other
<VoidPointer, list_node>::type node_ptr;
node_ptr prev_, next_;
};
template<class VoidPointer> template<class VoidPointer>
struct list_node_traits struct list_node_traits
{ {
struct node; typedef list_node<VoidPointer> node;
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr; <VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr; <VoidPointer, const node>::type const_node_ptr;
struct node
{
node_ptr prev_, next_;
};
static node_ptr get_previous(const_node_ptr n) static node_ptr get_previous(const_node_ptr n)
{ return n->prev_; } { return n->prev_; }
@@ -61,178 +57,126 @@ struct list_node_traits
{ n->next_ = next; } { n->next_ = next; }
}; };
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
// list_iterator provides some basic functions for a
// node oriented forward iterator:
template<class T, class ValueTraits>
class list_iterator
: public boost::iterator_facade
< list_iterator<T, ValueTraits>
, T
, boost::bidirectional_traversal_tag
, T&
, typename std::iterator_traits<typename ValueTraits::node_ptr>::difference_type
>
{
typedef typename ValueTraits::node_traits node_traits;
typedef typename node_traits::node node;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
struct enabler{};
public:
typedef typename pointer_to_other<typename ValueTraits::node_ptr, T>::type pointer;
typedef typename std::iterator_traits<node_ptr>::difference_type difference_type;
list_iterator ()
: node_ (0)
{}
explicit list_iterator(node_ptr node)
: node_ (node)
{}
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
template <class OtherValue>
list_iterator(list_iterator<OtherValue, ValueTraits> const& other
,typename boost::enable_if<
boost::is_convertible<OtherValue*,T*>
, enabler
>::type = enabler()
)
: node_(other.pointed_node())
{}
#else
template <class OtherValue>
list_iterator(list_iterator<OtherValue, ValueTraits> const& other,
typename enable_if<
is_convertible<OtherValue*,T*>
>::type* = 0)
: node_(other.pointed_node())
{}
#endif
const node_ptr &pointed_node() const
{ return node_; }
private:
friend class boost::iterator_core_access;
template <class, class> friend class list_iterator;
template <class OtherValue>
bool equal(list_iterator<OtherValue, ValueTraits> const& other) const
{ return other.pointed_node() == node_; }
void increment()
{ node_ = node_traits::get_next(node_); }
void decrement()
{ node_ = node_traits::get_previous(node_); }
T& dereference() const
{ return *ValueTraits::to_value_ptr(node_); }
node_ptr node_;
};
#else //BOOST_INTRUSIVE_USE_ITERATOR_FACADE
// list_iterator provides some basic functions for a // list_iterator provides some basic functions for a
// node oriented bidirectional iterator: // node oriented bidirectional iterator:
template<class T, class ValueTraits> template<class Container, bool IsConst>
class list_iterator class list_iterator
: public std::iterator<std::bidirectional_iterator_tag, T> : public std::iterator
< std::bidirectional_iterator_tag
, typename detail::add_const_if_c
<typename Container::value_type, IsConst>::type
>
{ {
struct enabler{};
protected: protected:
typedef typename ValueTraits::node_traits node_traits; 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 node;
typedef typename node_traits::node_ptr node_ptr; typedef typename node_traits::node_ptr node_ptr;
typedef typename boost::pointer_to_other
<node_ptr, void>::type void_pointer;
static const bool store_container_ptr =
detail::store_cont_ptr_on_it<Container>::value;
public: public:
typedef T & reference; typedef typename detail::add_const_if_c
typedef T * pointer; <typename Container::value_type, IsConst>
::type value_type;
typedef value_type & reference;
typedef value_type * pointer;
list_iterator() list_iterator()
: node_ (0) : members_ (0, 0)
{} {}
explicit list_iterator(node_ptr node) explicit list_iterator(node_ptr node, const Container *cont_ptr)
: node_ (node) : members_ (node, cont_ptr)
{} {}
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
template <class OtherValue> list_iterator(list_iterator<Container, false> const& other)
list_iterator(list_iterator<OtherValue, ValueTraits> const& other : members_(other.pointed_node(), other.get_container())
,typename boost::enable_if<
boost::is_convertible<OtherValue*,T*>
, enabler
>::type = enabler()
)
: node_(other.pointed_node())
{} {}
#else
template <class OtherValue>
list_iterator(list_iterator<OtherValue, ValueTraits> const& other,
typename enable_if<
is_convertible<OtherValue*,T*>
>::type* = 0)
: node_(other.pointed_node())
{}
#endif
const node_ptr &pointed_node() const const node_ptr &pointed_node() const
{ return node_; } { return members_.nodeptr_; }
list_iterator &operator=(const node_ptr &node) list_iterator &operator=(const node_ptr &node)
{ node_ = node; return static_cast<list_iterator&>(*this); } { members_.nodeptr_ = node; return static_cast<list_iterator&>(*this); }
public: public:
list_iterator& operator++() list_iterator& operator++()
{ {
node_ = node_traits::get_next(node_); members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return static_cast<list_iterator&> (*this); return static_cast<list_iterator&> (*this);
} }
list_iterator operator++(int) list_iterator operator++(int)
{ {
list_iterator result (node_); list_iterator result (*this);
node_ = node_traits::get_next(node_); members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return result; return result;
} }
list_iterator& operator--() list_iterator& operator--()
{ {
node_ = node_traits::get_previous(node_); members_.nodeptr_ = node_traits::get_previous(members_.nodeptr_);
return static_cast<list_iterator&> (*this); return static_cast<list_iterator&> (*this);
} }
list_iterator operator--(int) list_iterator operator--(int)
{ {
list_iterator result (node_); list_iterator result (*this);
node_ = node_traits::get_previous(node_); members_.nodeptr_ = node_traits::get_previous(members_.nodeptr_);
return result; return result;
} }
bool operator== (const list_iterator& i) const 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 bool operator!= (const list_iterator& i) const
{ return !operator== (i); } { return !operator== (i); }
T& operator*() const value_type& operator*() const
{ return *ValueTraits::to_value_ptr(node_); } { return *operator->(); }
pointer operator->() const pointer operator->() const
{ return detail::get_pointer(ValueTraits::to_value_ptr(node_)); } { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(members_.nodeptr_)); }
const Container *get_container() const
{
if(store_container_ptr){
const Container* c = static_cast<const Container*>(members_.get_ptr());
BOOST_INTRUSIVE_INVARIANT_ASSERT(c != 0);
return c;
}
else{
return 0;
}
}
const real_value_traits *get_real_value_traits() const
{
if(store_container_ptr)
return &this->get_container()->get_real_value_traits();
else
return 0;
}
private: private:
node_ptr node_; struct members
: public detail::select_constptr
<void_pointer, store_container_ptr>::type
{
typedef typename detail::select_constptr
<void_pointer, store_container_ptr>::type Base;
members(const node_ptr &n_ptr, const void *cont)
: Base(cont), nodeptr_(n_ptr)
{}
node_ptr nodeptr_;
} members_;
}; };
#endif
} //namespace detail
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost

View File

@@ -17,6 +17,9 @@ namespace boost {
namespace intrusive { namespace intrusive {
namespace detail { namespace detail {
typedef char one;
struct two {one _[2];};
template< bool C_ > template< bool C_ >
struct bool_ struct bool_
{ {
@@ -55,7 +58,61 @@ class is_convertible
static false_t dispatch(...); static false_t dispatch(...);
static T trigger(); static T trigger();
public: public:
enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t);
};
template<
bool C
, typename T1
, typename T2
>
struct if_c
{
typedef T1 type;
};
template<
typename T1
, typename T2
>
struct if_c<false,T1,T2>
{
typedef T2 type;
};
template<
typename C
, typename T1
, typename T2
>
struct if_
{
typedef typename if_c<0 != C::value, T1, T2>::type type;
};
template<
bool C
, typename F1
, typename F2
>
struct eval_if_c
: if_c<C,F1,F2>::type
{};
template<
typename C
, typename T1
, typename T2
>
struct eval_if
: if_<C,T1,T2>::type
{};
// identity is an extension: it is not part of the standard.
template <class T>
struct identity
{
typedef T type;
}; };
#if defined(BOOST_MSVC) || defined(__BORLANDC_) #if defined(BOOST_MSVC) || defined(__BORLANDC_)
@@ -131,17 +188,19 @@ template <typename T>
struct is_unary_or_binary_function_impl struct is_unary_or_binary_function_impl
{ {
static T* t; static T* t;
enum{ value = sizeof(is_function_ptr_tester(t)) == sizeof(yes_type) }; static const bool value = sizeof(is_function_ptr_tester(t)) == sizeof(yes_type);
}; };
template <typename T> template <typename T>
struct is_unary_or_binary_function_impl<T&> struct is_unary_or_binary_function_impl<T&>
{ enum {value = false }; }; {
static const bool value = false;
};
template<typename T> template<typename T>
struct is_unary_or_binary_function struct is_unary_or_binary_function
{ {
enum{ value = is_unary_or_binary_function_impl<T>::value }; static const bool value = is_unary_or_binary_function_impl<T>::value;
}; };
//boost::alignment_of yields to 10K lines of preprocessed code, so we //boost::alignment_of yields to 10K lines of preprocessed code, so we
@@ -159,15 +218,68 @@ struct alignment_of_hack
template <unsigned A, unsigned S> template <unsigned A, unsigned S>
struct alignment_logic struct alignment_logic
{ {
enum{ value = A < S ? A : S }; static const std::size_t value = A < S ? A : S;
}; };
template< typename T > template< typename T >
struct alignment_of struct alignment_of
{ {
enum{ value = alignment_logic static const std::size_t value = alignment_logic
< sizeof(alignment_of_hack<T>) - sizeof(T) < sizeof(alignment_of_hack<T>) - sizeof(T)
, sizeof(T)>::value }; , sizeof(T)
>::value;
};
template <typename T, typename U>
struct is_same
{
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <typename V>
static yes_type is_same_tester(V*, V*);
static no_type is_same_tester(...);
static T *t;
static U *u;
static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
};
template<typename T>
struct add_const
{ typedef const T type; };
template<class T>
struct remove_reference
{
typedef T type;
};
template<class T>
struct remove_reference<T&>
{
typedef T type;
};
template<class Class>
class is_empty_class
{
template <typename T>
struct empty_helper_t1 : public T
{
empty_helper_t1();
int i[256];
};
struct empty_helper_t2
{ int i[256]; };
public:
static const bool value = sizeof(empty_helper_t1<Class>) == sizeof(empty_helper_t2);
}; };
} //namespace detail } //namespace detail

View File

@@ -0,0 +1,28 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_NO_EXCEPTION_SUPPORT_HPP
#if !(defined BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING)
# include <boost/detail/no_exceptions_support.hpp>
# define BOOST_INTRUSIVE_TRY BOOST_TRY
# define BOOST_INTRUSIVE_CATCH(x) BOOST_CATCH(x)
# define BOOST_INTRUSIVE_RETHROW BOOST_RETHROW
# define BOOST_INTRUSIVE_CATCH_END BOOST_CATCH_END
#else
# define BOOST_INTRUSIVE_TRY { if (true)
# define BOOST_INTRUSIVE_CATCH(x) else if (false)
# define BOOST_INTRUSIVE_RETHROW
# define BOOST_INTRUSIVE_CATCH_END }
#endif
#endif //#ifndef BOOST_INTRUSIVE_NO_EXCEPTION_SUPPORT_HPP

View File

@@ -13,6 +13,7 @@
#define BOOST_INTRUSIVE_PARENT_FROM_MEMBER_HPP #define BOOST_INTRUSIVE_PARENT_FROM_MEMBER_HPP
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/static_assert.hpp>
#include <cstddef> #include <cstddef>
namespace boost { namespace boost {
@@ -22,14 +23,18 @@ namespace detail {
template<class Parent, class Member> template<class Parent, class Member>
inline std::size_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member) inline std::size_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member)
{ {
//BOOST_STATIC_ASSERT(( sizeof(std::ptrdiff_t) == sizeof(ptr_to_member) ));
//The implementation of a pointer to member is compiler dependent. //The implementation of a pointer to member is compiler dependent.
#if (defined(_MSC_VER) || defined(__GNUC__) || \ #if defined(BOOST_MSVC) || (defined (BOOST_WINDOWS) && defined(BOOST_INTEL))
defined(BOOST_INTEL) || defined(__HP_aCC)) //This works with gcc, msvc, ac++, ibmcpp
//This works with gcc, msvc, ac++
return *(const std::ptrdiff_t*)(void*)&ptr_to_member; return *(const std::ptrdiff_t*)(void*)&ptr_to_member;
#elif defined(__GNUC__) || defined(__HP_aCC) || defined(BOOST_INTEL) || defined (__IBMCPP__)
const Parent * const parent = 0;
const char *const member = reinterpret_cast<const char*>(&(parent->*ptr_to_member));
return std::size_t(member - reinterpret_cast<const char*>(parent));
#else #else
//This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC //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 #endif
} }

View File

@@ -18,19 +18,11 @@
#include <iterator> #include <iterator>
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/rbtree_algorithms.hpp> #include <boost/intrusive/rbtree_algorithms.hpp>
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
#include <boost/iterator/iterator_facade.hpp>
#endif
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#endif
#include <boost/intrusive/pointer_plus_bit.hpp> #include <boost/intrusive/pointer_plus_bit.hpp>
#include <boost/intrusive/detail/mpl.hpp> #include <boost/intrusive/detail/mpl.hpp>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
namespace detail {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// // // //
@@ -164,14 +156,14 @@ struct rbtree_node_traits_dispatch<VoidPointer, true>
: public compact_rbtree_node_traits_impl<VoidPointer> : public compact_rbtree_node_traits_impl<VoidPointer>
{}; {};
//Inherit from the dispatcher depending on the embedding capabilities //Inherit from the detail::link_dispatch depending on the embedding capabilities
template<class VoidPointer> template<class VoidPointer>
struct rbtree_node_traits struct rbtree_node_traits
: public rbtree_node_traits_dispatch : public rbtree_node_traits_dispatch
<VoidPointer < VoidPointer
,has_pointer_plus_bit , has_pointer_plus_bit
<VoidPointer, detail::alignment_of<compact_rbtree_node<VoidPointer> < VoidPointer
>::value , detail::alignment_of<compact_rbtree_node<VoidPointer> >::value
>::value >::value
> >
{}; {};
@@ -182,179 +174,124 @@ struct rbtree_node_traits
// // // //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
template<class T, class ValueTraits>
class rbtree_iterator
: public boost::iterator_facade
< rbtree_iterator<T, ValueTraits>
, T
, boost::bidirectional_traversal_tag
, T&
, typename std::iterator_traits<typename ValueTraits::node_ptr>::difference_type
>
{
typedef typename ValueTraits::node_traits node_traits;
typedef typename node_traits::node node;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef rbtree_algorithms<node_traits> node_algorithms;
struct enabler{};
public:
typedef typename pointer_to_other<typename ValueTraits::node_ptr, T>::type pointer;
typedef typename std::iterator_traits<node_ptr>::difference_type difference_type;
rbtree_iterator ()
: node_ (0)
{}
explicit rbtree_iterator(node_ptr node)
: node_ (node)
{}
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
template <class OtherValue>
rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other
,typename boost::enable_if<
boost::is_convertible<OtherValue*,T*>
, enabler
>::type = enabler()
)
: node_(other.pointed_node())
{}
#else
template <class OtherValue>
rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other,
typename enable_if<
is_convertible<OtherValue*,T*>
>::type* = 0)
: node_(other.pointed_node())
{}
#endif
const node_ptr &pointed_node() const
{ return node_; }
private:
friend class boost::iterator_core_access;
template <class, class> friend class rbtree_iterator;
template <class OtherValue>
bool equal(rbtree_iterator<OtherValue, ValueTraits> const& other) const
{ return other.pointed_node() == node_; }
void increment()
{ node_ = node_algorithms::next_node(node_); }
void decrement()
{ node_ = node_algorithms::prev_node(node_); }
T& dereference() const
{ return *ValueTraits::to_value_ptr(node_); }
node_ptr node_;
};
#else
// rbtree_iterator provides some basic functions for a // rbtree_iterator provides some basic functions for a
// node oriented bidirectional iterator: // node oriented bidirectional iterator:
template<class T, class ValueTraits> template<class Container, bool IsConst>
class rbtree_iterator class rbtree_iterator
: public std::iterator<std::bidirectional_iterator_tag, T> : public std::iterator
< std::bidirectional_iterator_tag
, typename detail::add_const_if_c
<typename Container::value_type, IsConst>::type
>
{ {
struct enabler{};
protected: protected:
typedef typename ValueTraits::node_traits node_traits; 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 node;
typedef typename node_traits::node_ptr node_ptr; typedef typename node_traits::node_ptr node_ptr;
typedef rbtree_algorithms<node_traits> node_algorithms; typedef rbtree_algorithms<node_traits> node_algorithms;
typedef typename boost::pointer_to_other
<node_ptr, void>::type void_pointer;
static const bool store_container_ptr =
detail::store_cont_ptr_on_it<Container>::value;
public: public:
typedef T & reference; public:
typedef T * pointer; typedef typename detail::add_const_if_c
<typename Container::value_type, IsConst>
::type value_type;
typedef value_type & reference;
typedef value_type * pointer;
rbtree_iterator() rbtree_iterator()
: node_ (0) : members_ (0, 0)
{} {}
explicit rbtree_iterator(node_ptr node) explicit rbtree_iterator(node_ptr node, const Container *cont_ptr)
: node_ (node) : members_ (node, cont_ptr)
{} {}
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE rbtree_iterator(rbtree_iterator<Container, false> const& other)
template <class OtherValue> : members_(other.pointed_node(), other.get_container())
rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other
,typename boost::enable_if<
boost::is_convertible<OtherValue*,T*>
, enabler
>::type = enabler()
)
: node_(other.pointed_node())
{} {}
#else
template <class OtherValue>
rbtree_iterator(rbtree_iterator<OtherValue, ValueTraits> const& other,
typename enable_if<
is_convertible<OtherValue*,T*>
>::type* = 0)
: node_(other.pointed_node())
{}
#endif
const node_ptr &pointed_node() const const node_ptr &pointed_node() const
{ return node_; } { return members_.nodeptr_; }
rbtree_iterator &operator=(const node_ptr &node) rbtree_iterator &operator=(const node_ptr &node)
{ node_ = node; return static_cast<rbtree_iterator&>(*this); } { members_.nodeptr_ = node; return static_cast<rbtree_iterator&>(*this); }
public: public:
rbtree_iterator& operator++() rbtree_iterator& operator++()
{ {
node_ = node_algorithms::next_node(node_); members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_);
return static_cast<rbtree_iterator&> (*this); return static_cast<rbtree_iterator&> (*this);
} }
rbtree_iterator operator++(int) rbtree_iterator operator++(int)
{ {
rbtree_iterator result (node_); rbtree_iterator result (*this);
node_ = node_algorithms::next_node(node_); members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_);
return result; return result;
} }
rbtree_iterator& operator--() rbtree_iterator& operator--()
{ {
node_ = node_algorithms::prev_node(node_); members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_);
return static_cast<rbtree_iterator&> (*this); return static_cast<rbtree_iterator&> (*this);
} }
rbtree_iterator operator--(int) rbtree_iterator operator--(int)
{ {
rbtree_iterator result (node_); rbtree_iterator result (*this);
node_ = node_algorithms::prev_node(node_); members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_);
return result; return result;
} }
bool operator== (const rbtree_iterator& i) const 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 bool operator!= (const rbtree_iterator& i) const
{ return !operator== (i); } { return !operator== (i); }
T& operator*() const value_type& operator*() const
{ return *ValueTraits::to_value_ptr(node_); } { return *operator->(); }
pointer operator->() const pointer operator->() const
{ return detail::get_pointer(ValueTraits::to_value_ptr(node_)); } { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(members_.nodeptr_)); }
const Container *get_container() const
{
if(store_container_ptr)
return static_cast<const Container*>(members_.get_ptr());
else
return 0;
}
const real_value_traits *get_real_value_traits() const
{
if(store_container_ptr)
return &this->get_container()->get_real_value_traits();
else
return 0;
}
private: private:
node_ptr node_; struct members
: public detail::select_constptr
<void_pointer, store_container_ptr>::type
{
typedef typename detail::select_constptr
<void_pointer, store_container_ptr>::type Base;
members(const node_ptr &n_ptr, const void *cont)
: Base(cont), nodeptr_(n_ptr)
{}
node_ptr nodeptr_;
} members_;
}; };
#endif
} //namespace detail
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost

View File

@@ -19,17 +19,17 @@
#include <boost/intrusive/detail/assert.hpp> #include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/circular_slist_algorithms.hpp> #include <boost/intrusive/circular_slist_algorithms.hpp>
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
#include <boost/iterator/iterator_facade.hpp>
#endif
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#endif
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
namespace detail {
template<class VoidPointer>
struct slist_node
{
typedef typename boost::pointer_to_other
<VoidPointer, slist_node>::type node_ptr;
node_ptr next_;
};
// slist_node_traits can be used with circular_slist_algorithms and supplies // slist_node_traits can be used with circular_slist_algorithms and supplies
// a slist_node holding the pointers needed for a singly-linked list // a slist_node holding the pointers needed for a singly-linked list
@@ -37,18 +37,12 @@ namespace detail {
template<class VoidPointer> template<class VoidPointer>
struct slist_node_traits struct slist_node_traits
{ {
struct node; typedef slist_node<VoidPointer> node;
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr; <VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr; <VoidPointer, const node>::type const_node_ptr;
struct node
{
node_ptr next_;
};
static node_ptr get_next(const_node_ptr n) static node_ptr get_next(const_node_ptr n)
{ return n->next_; } { return n->next_; }
@@ -56,163 +50,109 @@ struct slist_node_traits
{ n->next_ = next; } { n->next_ = next; }
}; };
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_FACADE
// slist_iterator provides some basic functions for a
// node oriented forward iterator:
template<class T, class ValueTraits>
class slist_iterator
: public boost::iterator_facade
< slist_iterator<T, ValueTraits>
, T
, boost::forward_traversal_tag
, T&
, typename std::iterator_traits<typename ValueTraits::node_ptr>::difference_type
>
{
typedef typename ValueTraits::node_traits node_traits;
typedef typename node_traits::node node;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
struct enabler{};
public:
typedef typename pointer_to_other<typename ValueTraits::node_ptr, T>::type pointer;
typedef typename std::iterator_traits<node_ptr>::difference_type difference_type;
slist_iterator ()
: node_ (0)
{}
explicit slist_iterator(node_ptr node)
: node_ (node)
{}
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE
template <class OtherValue>
slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other
,typename boost::enable_if<
boost::is_convertible<OtherValue*,T*>
, enabler
>::type = enabler()
)
: node_(other.pointed_node())
{}
#else
template <class OtherValue>
slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other,
typename enable_if<
is_convertible<OtherValue*,T*>
>::type* = 0)
: node_(other.pointed_node())
{}
#endif
const node_ptr &pointed_node() const
{ return node_; }
private:
friend class boost::iterator_core_access;
template <class, class> friend class slist_iterator;
template <class OtherValue>
bool equal(slist_iterator<OtherValue, ValueTraits> const& other) const
{ return other.pointed_node() == node_; }
void increment()
{ node_ = node_traits::get_next(node_); }
T& dereference() const
{ return *ValueTraits::to_value_ptr(node_); }
node_ptr node_;
};
#else
// slist_iterator provides some basic functions for a // slist_iterator provides some basic functions for a
// node oriented bidirectional iterator: // node oriented bidirectional iterator:
template<class T, class ValueTraits> template<class Container, bool IsConst>
class slist_iterator class slist_iterator
: public std::iterator<std::forward_iterator_tag, T> : public std::iterator
< std::forward_iterator_tag
, typename detail::add_const_if_c
<typename Container::value_type, IsConst>::type
>
{ {
struct enabler{};
protected: protected:
typedef typename ValueTraits::node_traits node_traits; 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 node;
typedef typename node_traits::node_ptr node_ptr; typedef typename node_traits::node_ptr node_ptr;
typedef typename boost::pointer_to_other
<node_ptr, void>::type void_pointer;
static const bool store_container_ptr =
detail::store_cont_ptr_on_it<Container>::value;
public: public:
typedef T & reference; typedef typename detail::add_const_if_c
typedef T * pointer; <typename Container::value_type, IsConst>
::type value_type;
typedef value_type & reference;
typedef value_type * pointer;
slist_iterator() slist_iterator()
: node_ (0) : members_ (0, 0)
{} {}
explicit slist_iterator(node_ptr node) explicit slist_iterator(node_ptr node, const Container *cont_ptr)
: node_ (node) : members_ (node, cont_ptr)
{} {}
#ifdef BOOST_INTRUSIVE_USE_ITERATOR_ENABLE_IF_CONVERTIBLE slist_iterator(slist_iterator<Container, false> const& other)
template <class OtherValue> : members_(other.pointed_node(), other.get_container())
slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other
,typename boost::enable_if<
boost::is_convertible<OtherValue*,T*>
, enabler
>::type = enabler()
)
: node_(other.pointed_node())
{} {}
#else
template <class OtherValue>
slist_iterator(slist_iterator<OtherValue, ValueTraits> const& other,
typename enable_if<
is_convertible<OtherValue*,T*>
>::type* = 0)
: node_(other.pointed_node())
{}
#endif
const node_ptr &pointed_node() const const node_ptr &pointed_node() const
{ return node_; } { return members_.nodeptr_; }
slist_iterator &operator=(const node_ptr &node) slist_iterator &operator=(const node_ptr &node)
{ node_ = node; return static_cast<slist_iterator&>(*this); } { members_.nodeptr_ = node; return static_cast<slist_iterator&>(*this); }
public: public:
slist_iterator& operator++() slist_iterator& operator++()
{ {
node_ = node_traits::get_next(node_); members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return static_cast<slist_iterator&> (*this); return static_cast<slist_iterator&> (*this);
} }
slist_iterator operator++(int) slist_iterator operator++(int)
{ {
slist_iterator result (node_); slist_iterator result (*this);
node_ = node_traits::get_next(node_); members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return result; return result;
} }
bool operator== (const slist_iterator& i) const 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 bool operator!= (const slist_iterator& i) const
{ return !operator== (i); } { return !operator== (i); }
T& operator*() const value_type& operator*() const
{ return *ValueTraits::to_value_ptr(node_); } { return *operator->(); }
pointer operator->() const pointer operator->() const
{ return detail::get_pointer(ValueTraits::to_value_ptr(node_)); } { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(members_.nodeptr_)); }
const Container *get_container() const
{
if(store_container_ptr)
return static_cast<const Container*>(members_.get_ptr());
else
return 0;
}
const real_value_traits *get_real_value_traits() const
{
if(store_container_ptr)
return &this->get_container()->get_real_value_traits();
else
return 0;
}
private: private:
node_ptr node_; struct members
: public detail::select_constptr
<void_pointer, store_container_ptr>::type
{
typedef typename detail::select_constptr
<void_pointer, store_container_ptr>::type Base;
members(const node_ptr &n_ptr, const void *cont)
: Base(cont), nodeptr_(n_ptr)
{}
node_ptr nodeptr_;
} members_;
}; };
#endif
} //namespace detail
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost

View File

@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP
#define BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <iterator>
#include <boost/intrusive/detail/mpl.hpp>
namespace boost {
namespace intrusive {
namespace detail {
template <class PseudoReference>
struct operator_arrow_proxy
{
operator_arrow_proxy(const PseudoReference &px)
: m_value(px)
{}
PseudoReference* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable PseudoReference m_value;
};
template <class T>
struct operator_arrow_proxy<T&>
{
operator_arrow_proxy(T &px)
: m_value(px)
{}
T* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable T &m_value;
};
template <class Iterator, class UnaryFunction>
class transform_iterator
: public std::iterator
< typename Iterator::iterator_category
, typename detail::remove_reference<typename UnaryFunction::result_type>::type
, typename Iterator::difference_type
, operator_arrow_proxy<typename UnaryFunction::result_type>
, typename UnaryFunction::result_type>
{
public:
explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction())
: members_(it, f)
{}
explicit transform_iterator()
: members_()
{}
Iterator get_it() const
{ return members_.m_it; }
//Constructors
transform_iterator& operator++()
{ increment(); return *this; }
transform_iterator operator++(int)
{
transform_iterator result (*this);
increment();
return result;
}
friend bool operator== (const transform_iterator& i, const transform_iterator& i2)
{ return i.equal(i2); }
friend bool operator!= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i == i2); }
/*
friend bool operator> (const transform_iterator& i, const transform_iterator& i2)
{ return i2 < i; }
friend bool operator<= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i > i2); }
friend bool operator>= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i < i2); }
*/
friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
transform_iterator& operator+=(typename Iterator::difference_type off)
{ this->advance(off); return *this; }
transform_iterator operator+(typename Iterator::difference_type off) const
{
transform_iterator other(*this);
other.advance(off);
return other;
}
friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right)
{ return right + off; }
transform_iterator& operator-=(typename Iterator::difference_type off)
{ this->advance(-off); return *this; }
transform_iterator operator-(typename Iterator::difference_type off) const
{ return *this + (-off); }
typename UnaryFunction::result_type operator*() const
{ return dereference(); }
operator_arrow_proxy<typename UnaryFunction::result_type>
operator->() const
{ return operator_arrow_proxy<typename UnaryFunction::result_type>(dereference()); }
private:
struct members
: UnaryFunction
{
members(const Iterator &it, const UnaryFunction &f)
: UnaryFunction(f), m_it(it)
{}
members()
{}
Iterator m_it;
} members_;
void increment()
{ ++members_.m_it; }
void decrement()
{ --members_.m_it; }
bool equal(const transform_iterator &other) const
{ return members_.m_it == other.members_.m_it; }
bool less(const transform_iterator &other) const
{ return other.members_.m_it < members_.m_it; }
typename UnaryFunction::result_type dereference() const
{ return members_(*members_.m_it); }
void advance(typename Iterator::difference_type n)
{ std::advance(members_.m_it, n); }
typename Iterator::difference_type distance_to(const transform_iterator &other)const
{ return std::distance(other.members_.m_it, members_.m_it); }
};
} //namespace detail
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP

View File

@@ -17,7 +17,7 @@
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/detail/parent_from_member.hpp> #include <boost/intrusive/detail/parent_from_member.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp> #include <boost/intrusive/detail/ebo_functor_holder.hpp>
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/mpl.hpp> #include <boost/intrusive/detail/mpl.hpp>
#include <cstddef> #include <cstddef>
#include <iterator> #include <iterator>
@@ -26,6 +26,64 @@ namespace boost {
namespace intrusive { namespace intrusive {
namespace detail { namespace detail {
template <class T>
struct internal_member_value_traits
{
template <class U> static detail::one test(...);
template <class U> static detail::two test(typename U::member_value_traits* = 0);
static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
};
template <class T>
struct internal_base_hook_bool
{
template<bool Add>
struct two_or_three {one _[2 + Add];};
template <class U> static one test(...);
template <class U> static two_or_three<U::boost_intrusive_tags::is_base_hook>
test (detail::bool_<U::boost_intrusive_tags::is_base_hook>* = 0);
static const int value = sizeof(test<T>(0));
};
template <class T>
struct internal_base_hook_bool_is_true
{
static const bool value = internal_base_hook_bool<T>::value == 3;
};
template <class T>
struct external_value_traits_bool
{
template<bool Add>
struct two_or_three {one _[2 + Add];};
template <class U> static one test(...);
template <class U> static two_or_three<U::external_value_traits>
test (detail::bool_<U::external_value_traits>* = 0);
static const int value = sizeof(test<T>(0));
};
template <class T>
struct external_bucket_traits_bool
{
template<bool Add>
struct two_or_three {one _[2 + Add];};
template <class U> static one test(...);
template <class U> static two_or_three<U::external_bucket_traits>
test (detail::bool_<U::external_bucket_traits>* = 0);
static const int value = sizeof(test<T>(0));
};
template <class T>
struct external_value_traits_is_true
{
static const bool value = external_value_traits_bool<T>::value == 3;
};
template<class Node, class Tag, link_mode_type LinkMode, int>
struct node_holder
: public Node
{};
template<class SmartPtr> template<class SmartPtr>
struct smart_ptr_type struct smart_ptr_type
{ {
@@ -49,7 +107,6 @@ template<class Ptr>
inline typename smart_ptr_type<Ptr>::pointer inline typename smart_ptr_type<Ptr>::pointer
get_pointer(const Ptr &ptr) get_pointer(const Ptr &ptr)
{ return smart_ptr_type<Ptr>::get(ptr); } { return smart_ptr_type<Ptr>::get(ptr); }
//{ using boost::get_pointer; return get_pointer(ptr); }
//This functor compares a stored value //This functor compares a stored value
//and the one passed as an argument //and the one passed as an argument
@@ -75,10 +132,20 @@ class null_disposer
{} {}
}; };
template<class NodeAlgorithms>
class init_disposer
{
typedef typename NodeAlgorithms::node_ptr node_ptr;
public:
void operator()(node_ptr p)
{ NodeAlgorithms::init(p); }
};
template<bool ConstantSize, class SizeType> template<bool ConstantSize, class SizeType>
struct size_holder struct size_holder
{ {
enum { constant_time_size = ConstantSize }; static const bool constant_time_size = ConstantSize;
typedef SizeType size_type; typedef SizeType size_type;
SizeType get_size() const SizeType get_size() const
@@ -99,7 +166,7 @@ struct size_holder
template<class SizeType> template<class SizeType>
struct size_holder<false, SizeType> struct size_holder<false, SizeType>
{ {
enum { constant_time_size = false }; static const bool constant_time_size = false;
typedef SizeType size_type; typedef SizeType size_type;
size_type get_size() const size_type get_size() const
@@ -115,11 +182,235 @@ struct size_holder<false, SizeType>
{} {}
}; };
template<class T, class DerivationHookType, typename Tag> template<class KeyValueCompare, class Container>
struct derivation_hook_value_traits struct key_nodeptr_comp
: private detail::ebo_functor_holder<KeyValueCompare>
{
typedef typename Container::real_value_traits real_value_traits;
typedef typename real_value_traits::node_ptr node_ptr;
typedef detail::ebo_functor_holder<KeyValueCompare> base_t;
key_nodeptr_comp(KeyValueCompare kcomp, const Container *cont)
: base_t(kcomp), cont_(cont)
{}
template<class KeyType>
bool operator()(node_ptr node, const KeyType &key) const
{ return base_t::get()(*cont_->get_real_value_traits().to_value_ptr(node), key); }
template<class KeyType>
bool operator()(const KeyType &key, node_ptr node) const
{ return base_t::get()(key, *cont_->get_real_value_traits().to_value_ptr(node)); }
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<class F, class Container>
struct node_cloner
: private detail::ebo_functor_holder<F>
{
typedef typename Container::real_value_traits real_value_traits;
typedef typename Container::node_algorithms node_algorithms;
typedef typename real_value_traits::value_type value_type;
typedef typename real_value_traits::pointer pointer;
typedef typename real_value_traits::node_traits::node node;
typedef typename real_value_traits::node_ptr node_ptr;
typedef typename real_value_traits::const_node_ptr const_node_ptr;
typedef detail::ebo_functor_holder<F> base_t;
enum { safemode_or_autounlink =
(int)real_value_traits::link_mode == (int)auto_unlink ||
(int)real_value_traits::link_mode == (int)safe_link };
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<class F, class Container>
struct node_disposer
: private detail::ebo_functor_holder<F>
{
typedef typename Container::real_value_traits real_value_traits;
typedef typename real_value_traits::node_ptr node_ptr;
typedef detail::ebo_functor_holder<F> base_t;
typedef typename Container::node_algorithms node_algorithms;
enum { safemode_or_autounlink =
(int)real_value_traits::link_mode == (int)auto_unlink ||
(int)real_value_traits::link_mode == (int)safe_link };
node_disposer(F f, const Container *cont)
: base_t(f), cont_(cont)
{}
void operator()(node_ptr p)
{
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<class VoidPointer>
struct constptr
{
typedef typename boost::pointer_to_other
<VoidPointer, const void>::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 <class VoidPointer, bool store_ptr>
struct select_constptr
{
typedef typename detail::if_c
< store_ptr
, constptr<VoidPointer>
, dummy_constptr
>::type type;
};
template <class Container>
struct store_cont_ptr_on_it
{
typedef typename Container::value_traits value_traits;
static const bool value =
!detail::is_empty_class<value_traits>::value
|| detail::external_value_traits_is_true<value_traits>::value
;
};
template<class T, bool Add>
struct add_const_if_c
{
typedef typename detail::if_c
< Add
, typename detail::add_const<T>::type
, T
>::type type;
};
template<class Container, bool IsConst>
struct node_to_value
: public detail::select_constptr
< typename boost::pointer_to_other
<typename Container::pointer, void>::type
, detail::store_cont_ptr_on_it<Container>::value
>::type
{
static const bool store_container_ptr =
detail::store_cont_ptr_on_it<Container>::value;
typedef typename Container::real_value_traits real_value_traits;
typedef typename real_value_traits::value_type value_type;
typedef typename detail::select_constptr
< typename boost::pointer_to_other
<typename Container::pointer, void>::type
, store_container_ptr >::type Base;
typedef typename real_value_traits::node_traits::node node;
typedef typename detail::add_const_if_c
<value_type, IsConst>::type vtype;
typedef typename detail::add_const_if_c
<node, IsConst>::type ntype;
typedef typename boost::pointer_to_other
<typename Container::pointer, ntype>::type npointer;
node_to_value(const Container *cont)
: Base(cont)
{}
typedef vtype & result_type;
typedef ntype & first_argument_type;
const Container *get_container() const
{
if(store_container_ptr)
return static_cast<const Container*>(Base::get_ptr());
else
return 0;
}
const real_value_traits *get_real_value_traits() const
{
if(store_container_ptr)
return &this->get_container()->get_real_value_traits();
else
return 0;
}
result_type operator()(first_argument_type arg) const
{ return *(this->get_real_value_traits()->to_value_ptr(npointer(&arg))); }
};
template <link_mode_type LinkMode>
struct link_dispatch
{};
template<class Container>
void destructor_impl(Container &cont, detail::link_dispatch<safe_link>)
{ (void)cont; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!cont.is_linked()); }
template<class Container>
void destructor_impl(Container &cont, detail::link_dispatch<auto_unlink>)
{ cont.unlink(); }
template<class Container>
void destructor_impl(Container &, detail::link_dispatch<normal_link>)
{}
template<class T, class NodeTraits, link_mode_type LinkMode, class Tag, int HookType>
struct base_hook_traits
{ {
public: public:
typedef typename DerivationHookType::node_traits node_traits; typedef detail::node_holder
<typename NodeTraits::node, Tag, LinkMode, HookType> node_holder;
typedef NodeTraits node_traits;
typedef T value_type; typedef T value_type;
typedef typename node_traits::node_ptr node_ptr; typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr; typedef typename node_traits::const_node_ptr const_node_ptr;
@@ -127,172 +418,60 @@ struct derivation_hook_value_traits
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer; typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef typename std::iterator_traits<pointer>::reference reference; typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference; typedef typename std::iterator_traits<const_pointer>::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) static node_ptr to_node_ptr(reference value)
{ return static_cast<DerivationHookType &>(value).to_node_ptr(); } { return static_cast<node_holder*>(&value); }
static const_node_ptr to_node_ptr(const_reference value) static const_node_ptr to_node_ptr(const_reference value)
{ return static_cast<const DerivationHookType &>(value).to_node_ptr(); } { return static_cast<const node_holder*>(&value); }
static pointer to_value_ptr(node_ptr n) static pointer to_value_ptr(node_ptr n)
{ { return static_cast<T*>(static_cast<node_holder*>(&*n)); }
return static_cast<T*>(detail::get_pointer(DerivationHookType::to_hook_ptr(n)));
}
static const_pointer to_value_ptr(const_node_ptr n) static const_pointer to_value_ptr(const_node_ptr n)
{ { return static_cast<const T*>(static_cast<const node_holder*>(&*n)); }
return static_cast<const T*>(detail::get_pointer(DerivationHookType::to_hook_ptr(n)));
}
}; };
template<class T, class Hook, Hook T::* P>
template<class T, class MemberHookType, MemberHookType T::* P> struct member_hook_traits
struct member_hook_value_traits
{ {
public: 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 T value_type;
typedef typename node_traits::node_ptr node_ptr; typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr; typedef typename node_traits::const_node_ptr const_node_ptr;
typedef typename boost::pointer_to_other<node_ptr, T>::type pointer; typedef typename boost::pointer_to_other<node_ptr, T>::type pointer;
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer; typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef value_type & reference; typedef typename std::iterator_traits<pointer>::reference reference;
typedef const value_type & const_reference; typedef typename std::iterator_traits<const_pointer>::reference const_reference;
enum { linking_policy = MemberHookType::linking_policy }; static const link_mode_type link_mode = Hook::boost_intrusive_tags::link_mode;
public:
static node_ptr to_node_ptr(reference value) static node_ptr to_node_ptr(reference value)
{ {
MemberHookType* result = &(value.*P); return reinterpret_cast<node*>(&(value.*P));
return result->to_node_ptr();
} }
static const_node_ptr to_node_ptr(const_reference value) static const_node_ptr to_node_ptr(const_reference value)
{ {
const MemberHookType* result = &(value.*P); return static_cast<const node*>(&(value.*P));
return result->to_node_ptr();
} }
static pointer to_value_ptr(node_ptr n) static pointer to_value_ptr(node_ptr n)
{ {
return pointer return detail::parent_from_member<T, Hook>
( (static_cast<Hook*>(detail::get_pointer(n)), P);
parent_from_member<value_type, MemberHookType>
(detail::get_pointer(MemberHookType::to_hook_ptr(n)), P)
);
} }
static const_pointer to_value_ptr(const_node_ptr n) static const_pointer to_value_ptr(const_node_ptr n)
{ {
return const_pointer return detail::parent_from_member<T, Hook>
( (static_cast<const Hook*>(detail::get_pointer(n)), P);
parent_from_member<value_type, MemberHookType>
(detail::get_pointer(MemberHookType::to_hook_ptr(n)), P)
);
} }
}; };
template<class KeyValueCompare, class ValueTraits>
struct key_node_ptr_compare
: private detail::ebo_functor_holder<KeyValueCompare>
{
typedef typename ValueTraits::node_ptr node_ptr;
typedef detail::ebo_functor_holder<KeyValueCompare> base_t;
key_node_ptr_compare(KeyValueCompare kcomp)
: base_t(kcomp)
{}
template<class KeyType>
bool operator()(node_ptr node, const KeyType &key) const
{ return base_t::get()(*ValueTraits::to_value_ptr(node), key); }
template<class KeyType>
bool operator()(const KeyType &key, node_ptr node) const
{ return base_t::get()(key, *ValueTraits::to_value_ptr(node)); }
bool operator()(node_ptr node1, node_ptr node2) const
{
return base_t::get()
(*ValueTraits::to_value_ptr(node1), *ValueTraits::to_value_ptr(node2));
}
};
template<class F, class ValueTraits>
struct value_to_node_cloner
: private detail::ebo_functor_holder<F>
{
typedef typename ValueTraits::node_ptr node_ptr;
typedef detail::ebo_functor_holder<F> 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<class F, class ValueTraits>
struct value_to_node_disposer
: private detail::ebo_functor_holder<F>
{
typedef typename ValueTraits::node_ptr node_ptr;
typedef detail::ebo_functor_holder<F> 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 <linking_policy Policy>
struct dispatcher
{};
template<class Container>
void destructor_impl(Container &cont, dispatcher<safe_link>)
{ (void)cont; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!cont.is_linked()); }
template<class Container>
void destructor_impl(Container &cont, dispatcher<auto_unlink>)
{ cont.unlink(); }
template<class Container>
void destructor_impl(Container &, dispatcher<normal_link>)
{}
template<class Node, class MaybeClass>
struct node_plus_pred
: public ebo_functor_holder<MaybeClass>
, public Node
{
node_plus_pred()
{}
node_plus_pred(const Node &x, const MaybeClass &y)
: Node(x), ebo_functor_holder<MaybeClass>(y) {}
node_plus_pred(const MaybeClass &y)
: ebo_functor_holder<MaybeClass>(y) {}
Node &first()
{ return *this; }
const Node &first() const
{ return *this; }
MaybeClass &second()
{ return ebo_functor_holder<MaybeClass>::get(); }
const MaybeClass &second() const
{ return ebo_functor_holder<MaybeClass>::get(); }
static node_plus_pred *this_from_node(Node *n)
{ return static_cast<node_plus_pred*>(n); }
static node_plus_pred *this_from_node(const Node *n)
{ return static_cast<const node_plus_pred*>(n); }
};
} //namespace detail } //namespace detail
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost

File diff suppressed because it is too large Load Diff

View File

@@ -14,8 +14,9 @@
#define BOOST_INTRUSIVE_FWD_HPP #define BOOST_INTRUSIVE_FWD_HPP
#include <cstddef> #include <cstddef>
#include <boost/intrusive/tag.hpp> #include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/linking_policy.hpp>
/// @cond
//std predeclarations //std predeclarations
namespace std{ namespace std{
@@ -36,6 +37,14 @@ struct hash;
namespace intrusive { namespace intrusive {
struct none;
} //namespace intrusive{
} //namespace boost{
namespace boost {
namespace intrusive {
//////////////////////////// ////////////////////////////
// Node algorithms // Node algorithms
//////////////////////////// ////////////////////////////
@@ -55,104 +64,148 @@ class rbtree_algorithms;
//////////////////////////// ////////////////////////////
//slist //slist
template < class ValueTraits template
, bool ConstantTimeSize = true < class T
, class SizeType = std::size_t> , class O1 = none
, class O2 = none
, class O3 = none
>
class slist; class slist;
template< class Tag = tag template
, linking_policy Policy = safe_link < class O1 = none
, class VoidPointer = void * , class O2 = none
, class O3 = none
> >
class slist_base_hook; class slist_base_hook;
template< linking_policy Policy = safe_link template
, class VoidPointer = void *> < class O1 = none
, class O2 = none
, class O3 = none
>
class slist_member_hook; class slist_member_hook;
//list //list
template< class ValueTraits template
, bool ConstantTimeSize = true < class T
, class SizeType = std::size_t> , class O1 = none
, class O2 = none
, class O3 = none
>
class list; class list;
template< class Tag = tag template
, linking_policy Policy = safe_link < class O1 = none
, class VoidPointer = void * , class O2 = none
, class O3 = none
> >
class list_base_hook; class list_base_hook;
template< linking_policy Policy = safe_link template
, class VoidPointer = void *> < class O1 = none
, class O2 = none
, class O3 = none
>
class list_member_hook; class list_member_hook;
//hash/unordered //rbtree/set/multiset
template< class ValueTraits template
, class Hash = boost::hash<typename ValueTraits::value_type> < class T
, class Equal = std::equal_to<typename ValueTraits::value_type> , class O1 = none
, bool ConstantTimeSize = true , class O2 = none
, class SizeType = std::size_t , class O3 = none
> , class O4 = none
class hashtable;
template< class ValueTraits
, class Hash = boost::hash<typename ValueTraits::value_type>
, class Equal = std::equal_to<typename ValueTraits::value_type>
, bool ConstantTimeSize = true
, class SizeType = std::size_t
>
class unordered_set;
template< class ValueTraits
, class Hash = boost::hash<typename ValueTraits::value_type>
, class Equal = std::equal_to<typename ValueTraits::value_type>
, bool ConstantTimeSize = true
, class SizeType = std::size_t
>
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<typename ValueTraits::value_type>
, bool ConstantTimeSize = true
, class SizeType = std::size_t
> >
class rbtree; class rbtree;
template < class ValueTraits template
, class Compare = std::less<typename ValueTraits::value_type> < class T
, bool ConstantTimeSize = true , class O1 = none
, class SizeType = std::size_t> , class O2 = none
, class O3 = none
, class O4 = none
>
class set; class set;
template < class ValueTraits template
, class Compare = std::less<typename ValueTraits::value_type> < class T
, bool ConstantTimeSize = true , class O1 = none
, class SizeType = std::size_t> , class O2 = none
, class O3 = none
, class O4 = none
>
class multiset; class multiset;
template< class Tag = tag template
, linking_policy Policy = safe_link < class O1 = none
, class VoidPointer = void * , class O2 = none
, class O3 = none
> >
class set_base_hook; class set_base_hook;
template< linking_policy Policy = safe_link template
, class VoidPointer = void *> < class O1 = none
, class O2 = none
, class O3 = none
>
class set_member_hook; 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 intrusive {
} //namespace boost { } //namespace boost {
/// @endcond
#endif //#ifndef BOOST_INTRUSIVE_FWD_HPP #endif //#ifndef BOOST_INTRUSIVE_FWD_HPP

View File

@@ -10,24 +10,24 @@
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP #ifndef BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP
#define BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP #define BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
//!This enumeration defines the type of value_traits that can be defined //!This enumeration defines the type of value_traits that can be defined
//!for Boost.Intrusive containers //!for Boost.Intrusive containers
enum linking_policy{ enum link_mode_type{
//!If this linking policy is specified in a value_traits class //!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 //!configured with such value_traits won't set the hooks
//!of the erased values to a default state. Containers also won't //!of the erased values to a default state. Containers also won't
//!check that the hooks of the new values are default initialized. //!check that the hooks of the new values are default initialized.
normal_link, normal_link,
//!If this linking policy is specified in a value_traits class //!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 //!configured with such value_traits will set the hooks
//!of the erased values to a default state. Containers also will //!of the erased values to a default state. Containers also will
//!check that the hooks of the new values are default initialized. //!check that the hooks of the new values are default initialized.
@@ -43,4 +43,4 @@ enum linking_policy{
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost
#endif //BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP #endif //BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP

View File

@@ -20,79 +20,127 @@
#include <boost/intrusive/list_hook.hpp> #include <boost/intrusive/list_hook.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp> #include <boost/intrusive/circular_list_algorithms.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING #include <boost/intrusive/options.hpp>
#include <boost/detail/no_exceptions_support.hpp> #include <boost/intrusive/detail/no_exceptions_support.hpp>
#endif
#include <iterator> #include <iterator>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <cstddef> #include <cstddef>
#include <iterator>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
/// @cond
template <class T>
struct internal_default_list_hook
{
template <class U> static detail::one test(...);
template <class U> static detail::two test(typename U::default_list_hook* = 0);
static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
};
template <class T>
struct get_default_list_hook
{
typedef typename T::default_list_hook type;
};
template <class ValueTraits, class SizeType, bool ConstantTimeSize>
struct listopt
{
typedef ValueTraits value_traits;
typedef SizeType size_type;
static const bool constant_time_size = ConstantTimeSize;
};
template <class T>
struct list_defaults
: pack_options
< none
, base_hook
< typename detail::eval_if_c
< internal_default_list_hook<T>::value
, get_default_list_hook<T>
, detail::identity<none>
>::type
>
, constant_time_size<true>
, size_type<std::size_t>
>::type
{};
/// @endcond
//! The class template list is an intrusive container that mimics most of the //! The class template list is an intrusive container that mimics most of the
//! interface of std::list as described in the C++ standard. //! interface of std::list as described in the C++ standard.
//! //!
//! The template parameter ValueTraits is called "value traits". It stores //! The template parameter \c T is the type to be managed by the container.
//! information and operations about the type to be stored in 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 //! The container supports the following options:
//! will be embedded in the class, that will keep track of the number of stored objects. //! \c base_hook<>/member_hook<>/value_traits<>,
//! This will allow constant-time O(1) size() member, instead of default O(N) size. //! \c constant_time_size<> and \c size_type<>.
template< class ValueTraits #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
, bool ConstantTimeSize //= true template<class T, class ...Options>
, class SizeType //= std::size_t #else
> template<class Config>
class list #endif
: private detail::size_holder<ConstantTimeSize, SizeType> class list_impl
{ {
/// @cond
private:
typename ValueTraits::node_traits::node root_;
typedef list<ValueTraits, ConstantTimeSize, SizeType> this_type;
typedef typename ValueTraits::node_traits node_traits;
typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;
//! This class is
//! non-copyable
list (const list&);
//! This class is
//! non-assignable
list &operator =(const list&);
/// @endcond
//Public typedefs //Public typedefs
public: public:
typedef ValueTraits value_traits; typedef typename Config::value_traits value_traits;
typedef typename ValueTraits::value_type value_type; /// @cond
typedef typename ValueTraits::pointer pointer; static const bool external_value_traits =
typedef typename ValueTraits::const_pointer const_pointer; detail::external_value_traits_is_true<value_traits>::value;
typedef typename detail::eval_if_c
< external_value_traits
, detail::eval_value_traits<value_traits>
, detail::identity<value_traits>
>::type real_value_traits;
/// @endcond
typedef typename real_value_traits::pointer pointer;
typedef typename real_value_traits::const_pointer const_pointer;
typedef typename std::iterator_traits<pointer>::value_type value_type;
typedef typename std::iterator_traits<pointer>::reference reference; typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference; typedef typename std::iterator_traits<const_pointer>::reference const_reference;
typedef typename std::iterator_traits<pointer>::difference_type difference_type; typedef typename std::iterator_traits<pointer>::difference_type difference_type;
typedef SizeType size_type; typedef typename Config::size_type size_type;
typedef detail::list_iterator<value_type, ValueTraits> iterator; typedef list_iterator<list_impl, false> iterator;
typedef detail::list_iterator<const value_type, ValueTraits> const_iterator; typedef list_iterator<list_impl, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename real_value_traits::node_traits node_traits;
/// @cond
private:
typedef typename node_traits::node node; typedef typename node_traits::node node;
typedef typename node_traits::node_ptr node_ptr; typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr; typedef typename node_traits::const_node_ptr const_node_ptr;
typedef circular_list_algorithms<node_traits> node_algorithms; typedef circular_list_algorithms<node_traits> node_algorithms;
static const bool constant_time_size = Config::constant_time_size;
static const bool stateful_value_traits = detail::store_cont_ptr_on_it<list_impl>::value;
/// @cond
private:
typedef detail::size_holder<constant_time_size, size_type> size_traits;
//Non-copyable and non-moveable
list_impl (const list_impl&);
list_impl &operator =(const list_impl&);
enum { safemode_or_autounlink = enum { safemode_or_autounlink =
(int)ValueTraits::linking_policy == (int)auto_unlink || (int)real_value_traits::link_mode == (int)auto_unlink ||
(int)ValueTraits::linking_policy == (int)safe_link }; (int)real_value_traits::link_mode == (int)safe_link };
//Constant-time size is incompatible with auto-unlink hooks! //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 //Const cast emulation for smart pointers
static node_ptr uncast(const_node_ptr ptr) static node_ptr uncast(const_node_ptr ptr)
@@ -102,22 +150,64 @@ class list
} }
node_ptr get_root_node() node_ptr get_root_node()
{ return node_ptr(&root_); } { return node_ptr(&data_.root_plus_size_.root_); }
const_node_ptr get_root_node() const const_node_ptr get_root_node() const
{ return const_node_ptr(&root_); } { return const_node_ptr(&data_.root_plus_size_.root_); }
struct root_plus_size : public size_traits
{
node root_;
};
struct data_t : public value_traits
{
typedef typename list_impl::value_traits value_traits;
data_t(const value_traits &val_traits)
: value_traits(val_traits)
{}
root_plus_size root_plus_size_;
} data_;
size_traits &priv_size_traits()
{ return data_.root_plus_size_; }
const size_traits &priv_size_traits() const
{ return data_.root_plus_size_; }
const real_value_traits &get_real_value_traits(detail::bool_<false>) const
{ return data_; }
const real_value_traits &get_real_value_traits(detail::bool_<true>) const
{ return data_.get_value_traits(*this); }
real_value_traits &get_real_value_traits(detail::bool_<false>)
{ return data_; }
real_value_traits &get_real_value_traits(detail::bool_<true>)
{ return data_.get_value_traits(*this); }
/// @endcond /// @endcond
public: public:
const real_value_traits &get_real_value_traits() const
{ return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
real_value_traits &get_real_value_traits()
{ return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
//! <b>Effects</b>: constructs an empty list. //! <b>Effects</b>: constructs an empty list.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
//! //!
//! <b>Throws</b>: If value_traits::node_traits::node //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks). //! 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()); node_algorithms::init(this->get_root_node());
} }
@@ -127,12 +217,13 @@ class list
//! //!
//! <b>Complexity</b>: Linear in std::distance(b, e). No copy constructors are called. //! <b>Complexity</b>: Linear in std::distance(b, e). No copy constructors are called.
//! //!
//! <b>Throws</b>: If value_traits::node_traits::node //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks). //! constructor throws (this does not happen with predefined Boost.Intrusive hooks).
template<class Iterator> template<class Iterator>
list(Iterator b, Iterator e) list_impl(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
: data_(v_traits)
{ {
size_traits::set_size(size_type(0)); this->priv_size_traits().set_size(size_type(0));
node_algorithms::init(this->get_root_node()); node_algorithms::init(this->get_root_node());
this->insert(this->end(), b, e); this->insert(this->end(), b, e);
} }
@@ -146,7 +237,7 @@ class list
//! //!
//! <b>Complexity</b>: Linear to the number of elements in the list, if //! <b>Complexity</b>: Linear to the number of elements in the list, if
//! it's a safe-mode or auto-unlink value . Otherwise constant. //! it's a safe-mode or auto-unlink value . Otherwise constant.
~list() ~list_impl()
{ {
if(safemode_or_autounlink){ if(safemode_or_autounlink){
this->clear(); this->clear();
@@ -165,11 +256,11 @@ class list
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
void push_back(reference value) 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) if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
node_algorithms::link_before(this->get_root_node(), to_insert); node_algorithms::link_before(this->get_root_node(), to_insert);
size_traits::increment(); this->priv_size_traits().increment();
} }
//! <b>Requires</b>: value must be an lvalue. //! <b>Requires</b>: value must be an lvalue.
@@ -184,11 +275,11 @@ class list
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
void push_front(reference value) 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) if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); 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); node_algorithms::link_before(node_traits::get_next(this->get_root_node()), to_insert);
size_traits::increment(); this->priv_size_traits().increment();
} }
//! <b>Effects</b>: Erases the last element of the list. //! <b>Effects</b>: 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_ptr to_erase = node_traits::get_previous(this->get_root_node());
node_algorithms::unlink(to_erase); node_algorithms::unlink(to_erase);
size_traits::decrement(); this->priv_size_traits().decrement();
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
} }
@@ -224,10 +315,10 @@ class list
{ {
node_ptr to_erase = node_traits::get_previous(this->get_root_node()); node_ptr to_erase = node_traits::get_previous(this->get_root_node());
node_algorithms::unlink(to_erase); node_algorithms::unlink(to_erase);
size_traits::decrement(); this->priv_size_traits().decrement();
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
disposer(ValueTraits::to_value_ptr(to_erase)); disposer(get_real_value_traits().to_value_ptr(to_erase));
} }
//! <b>Effects</b>: Erases the first element of the list. //! <b>Effects</b>: 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_ptr to_erase = node_traits::get_next(this->get_root_node());
node_algorithms::unlink(to_erase); node_algorithms::unlink(to_erase);
size_traits::decrement(); this->priv_size_traits().decrement();
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
} }
@@ -263,10 +354,10 @@ class list
{ {
node_ptr to_erase = node_traits::get_next(this->get_root_node()); node_ptr to_erase = node_traits::get_next(this->get_root_node());
node_algorithms::unlink(to_erase); node_algorithms::unlink(to_erase);
size_traits::decrement(); this->priv_size_traits().decrement();
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
disposer(ValueTraits::to_value_ptr(to_erase)); disposer(get_real_value_traits().to_value_ptr(to_erase));
} }
//! <b>Effects</b>: Returns a reference to the first element of the list. //! <b>Effects</b>: Returns a reference to the first element of the list.
@@ -275,7 +366,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
reference front() reference front()
{ return *ValueTraits::to_value_ptr(node_traits::get_next(this->get_root_node())); } { return *get_real_value_traits().to_value_ptr(node_traits::get_next(this->get_root_node())); }
//! <b>Effects</b>: Returns a const_reference to the first element of the list. //! <b>Effects</b>: Returns a const_reference to the first element of the list.
//! //!
@@ -283,7 +374,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_reference front() const const_reference front() const
{ return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); } { return *get_real_value_traits().to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); }
//! <b>Effects</b>: Returns a reference to the last element of the list. //! <b>Effects</b>: Returns a reference to the last element of the list.
//! //!
@@ -291,7 +382,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
reference back() reference back()
{ return *ValueTraits::to_value_ptr(node_traits::get_previous(this->get_root_node())); } { return *get_real_value_traits().to_value_ptr(node_traits::get_previous(this->get_root_node())); }
//! <b>Effects</b>: Returns a const_reference to the last element of the list. //! <b>Effects</b>: Returns a const_reference to the last element of the list.
//! //!
@@ -299,7 +390,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_reference back() const const_reference back() const
{ return *ValueTraits::to_value_ptr(uncast(node_traits::get_previous(this->get_root_node()))); } { return *get_real_value_traits().to_value_ptr(uncast(node_traits::get_previous(this->get_root_node()))); }
//! <b>Effects</b>: Returns an iterator to the first element contained in the list. //! <b>Effects</b>: Returns an iterator to the first element contained in the list.
//! //!
@@ -307,7 +398,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
iterator begin() iterator begin()
{ return iterator(node_traits::get_next(this->get_root_node())); } { return iterator(node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the list. //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
//! //!
@@ -323,7 +414,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_iterator cbegin() const const_iterator cbegin() const
{ return const_iterator(node_traits::get_next(this->get_root_node())); } { return const_iterator(node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns an iterator to the end of the list. //! <b>Effects</b>: Returns an iterator to the end of the list.
//! //!
@@ -331,7 +422,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
iterator end() iterator end()
{ return iterator(this->get_root_node()); } { return iterator(this->get_root_node(), this); }
//! <b>Effects</b>: Returns a const_iterator to the end of the list. //! <b>Effects</b>: Returns a const_iterator to the end of the list.
//! //!
@@ -347,7 +438,7 @@ class list
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_iterator cend() const const_iterator cend() const
{ return const_iterator(uncast(this->get_root_node())); } { return const_iterator(uncast(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
//! of the reversed list. //! of the reversed list.
@@ -411,11 +502,8 @@ class list
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
static list &container_from_end_iterator(iterator end_iterator) static list_impl &container_from_end_iterator(iterator end_iterator)
{ { return priv_container_from_end_iterator(end_iterator); }
return *detail::parent_from_member<list, node>
( detail::get_pointer(end_iterator.pointed_node()), &list::root_);
}
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator //! <b>Precondition</b>: end_iterator must be a valid end const_iterator
//! of list. //! of list.
@@ -425,24 +513,21 @@ class list
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
static const list &container_from_end_iterator(const_iterator end_iterator) static const list_impl &container_from_end_iterator(const_iterator end_iterator)
{ { return priv_container_from_end_iterator(end_iterator); }
return *detail::parent_from_member<list, node>
( detail::get_pointer(end_iterator.pointed_node()), &list::root_);
}
//! <b>Effects</b>: Returns the number of the elements contained in the list. //! <b>Effects</b>: Returns the number of the elements contained in the list.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Linear to the number of elements contained in the list. //! <b>Complexity</b>: Linear to the number of elements contained in the list.
//! if ConstantTimeSize is false. Constant time otherwise. //! if constant-time size option is disabled. Constant time otherwise.
//! //!
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
size_type size() const size_type size() const
{ {
if(ConstantTimeSize) if(constant_time_size)
return size_traits::get_size(); return this->priv_size_traits().get_size();
else else
return node_algorithms::count(this->get_root_node()) - 1; return node_algorithms::count(this->get_root_node()) - 1;
} }
@@ -464,13 +549,13 @@ class list
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
//! //!
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
void swap(list& other) void swap(list_impl& other)
{ {
node_algorithms::swap_nodes(this->get_root_node(), other.get_root_node()); node_algorithms::swap_nodes(this->get_root_node(), other.get_root_node());
if(ConstantTimeSize){ if(constant_time_size){
size_type backup = size_traits::get_size(); size_type backup = this->priv_size_traits().get_size();
size_traits::set_size(other.get_size()); this->priv_size_traits().set_size(other.priv_size_traits().get_size());
other.set_size(backup); other.priv_size_traits().set_size(backup);
} }
} }
@@ -543,7 +628,7 @@ class list
++i; ++i;
node_ptr to_erase = erase.pointed_node(); node_ptr to_erase = erase.pointed_node();
node_algorithms::unlink(to_erase); node_algorithms::unlink(to_erase);
size_traits::decrement(); this->priv_size_traits().decrement();
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
return i; return i;
@@ -566,7 +651,7 @@ class list
//! erased elements. //! erased elements.
iterator erase(iterator b, iterator e) iterator erase(iterator b, iterator e)
{ {
if(safemode_or_autounlink || ConstantTimeSize){ if(safemode_or_autounlink || constant_time_size){
while(b != e){ while(b != e){
b = this->erase(b); b = this->erase(b);
} }
@@ -599,10 +684,10 @@ class list
++i; ++i;
node_ptr to_erase = erase.pointed_node(); node_ptr to_erase = erase.pointed_node();
node_algorithms::unlink(to_erase); node_algorithms::unlink(to_erase);
size_traits::decrement(); this->priv_size_traits().decrement();
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
disposer(ValueTraits::to_value_ptr(to_erase)); disposer(get_real_value_traits().to_value_ptr(to_erase));
return i; return i;
} }
@@ -645,7 +730,7 @@ class list
} }
else{ else{
node_algorithms::init(this->get_root_node()); 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
//! //!
//! <b>Throws</b>: If cloner throws. Basic guarantee. //! <b>Throws</b>: If cloner throws. Basic guarantee.
template <class Cloner, class Disposer> template <class Cloner, class Disposer>
void clone_from(const list &src, Cloner cloner, Disposer disposer) void clone_from(const list_impl &src, Cloner cloner, Disposer disposer)
{ {
this->clear_and_dispose(disposer); this->clear_and_dispose(disposer);
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING BOOST_INTRUSIVE_TRY{
BOOST_TRY{
#endif
const_iterator b(src.begin()), e(src.end()); const_iterator b(src.begin()), e(src.end());
for(; b != e; ++b){ for(; b != e; ++b){
this->push_back(*cloner(*b)); this->push_back(*cloner(*b));
} }
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
} }
BOOST_CATCH(...){ BOOST_INTRUSIVE_CATCH(...){
clear_and_dispose(disposer); this->clear_and_dispose(disposer);
BOOST_RETHROW; BOOST_INTRUSIVE_RETHROW;
} }
BOOST_CATCH_END BOOST_INTRUSIVE_CATCH_END
#endif
} }
//! <b>Requires</b>: value must be an lvalue and p must be a valid iterator of *this. //! <b>Requires</b>: value must be an lvalue and p must be a valid iterator of *this.
@@ -711,12 +792,12 @@ class list
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
iterator insert(iterator p, reference value) 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) if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
node_algorithms::link_before(p.pointed_node(), to_insert); node_algorithms::link_before(p.pointed_node(), to_insert);
size_traits::increment(); this->priv_size_traits().increment();
return iterator(to_insert); return iterator(to_insert, this);
} }
//! <b>Requires</b>: Dereferencing iterator must yield //! <b>Requires</b>: Dereferencing iterator must yield
@@ -793,13 +874,15 @@ class list
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of //! <b>Note</b>: Iterators of values obtained from list x now point to elements of
//! this list. Iterators of this list and all the references are not invalidated. //! 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()){ if(!x.empty()){
size_traits &thist = this->priv_size_traits();
size_traits &xt = x.priv_size_traits();
node_algorithms::transfer node_algorithms::transfer
(p.pointed_node(), x.begin().pointed_node(), x.end().pointed_node()); (p.pointed_node(), x.begin().pointed_node(), x.end().pointed_node());
size_traits::set_size(size_traits::get_size() + x.get_size()); thist.set_size(thist.get_size() + xt.get_size());
x.set_size(size_type(0)); xt.set_size(size_type(0));
} }
} }
@@ -816,11 +899,11 @@ class list
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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()); node_algorithms::transfer(p.pointed_node(), new_ele.pointed_node());
x.decrement(); x.priv_size_traits().decrement();
size_traits::increment(); this->priv_size_traits().increment();
} }
//! <b>Requires</b>: p must be a valid iterator of *this. //! <b>Requires</b>: p must be a valid iterator of *this.
@@ -832,18 +915,20 @@ class list
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Linear to the number of elements transferred //! <b>Complexity</b>: Linear to the number of elements transferred
//! if ConstantTimeSize is true. Constant-time otherwise. //! if constant-time size option is enabled. Constant-time otherwise.
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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(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); size_type increment = std::distance(start, end);
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
size_traits::set_size(size_traits::get_size() + increment); thist.set_size(thist.get_size() + increment);
x.set_size(x.get_size() - increment); xt.set_size(xt.get_size() - increment);
} }
else{ else{
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
@@ -864,14 +949,16 @@ class list
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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(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)); BOOST_INTRUSIVE_INVARIANT_ASSERT(n == std::distance(start, end));
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
size_traits::set_size(size_traits::get_size() + n); thist.set_size(thist.get_size() + n);
x.set_size(x.get_size() - n); xt.set_size(xt.get_size() - n);
} }
else{ else{
node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node());
@@ -882,7 +969,7 @@ class list
//! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>. //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
//! The sort is stable, that is, the relative order of equivalent elements is preserved. //! The sort is stable, that is, the relative order of equivalent elements is preserved.
//! //!
//! <b>Throws</b>: If value_traits::node_traits::node //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks) //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
//! or std::less<value_type> throws. Basic guarantee. //! or std::less<value_type> throws. Basic guarantee.
//! //!
@@ -898,12 +985,12 @@ class list
//! <b>Effects</b>: This function sorts the list *this according to p. The sort is //! <b>Effects</b>: This function sorts the list *this according to p. The sort is
//! stable, that is, the relative order of equivalent elements is preserved. //! stable, that is, the relative order of equivalent elements is preserved.
//! //!
//! <b>Throws</b>: If value_traits::node_traits::node //! <b>Throws</b>: If real_value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks) //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
//! or the predicate throws. Basic guarantee. //! or the predicate throws. Basic guarantee.
//! //!
//! <b>Notes</b>: This won't throw if list_base_hook<>::value_traits or //! <b>Notes</b>: This won't throw if list_base_hook<> or
//! list_member_hook::::value_traits are used as value traits. //! list_member_hook are used.
//! Iterators and references are not invalidated. //! Iterators and references are not invalidated.
//! //!
//! <b>Complexity</b>: The number of comparisons is approximately N log N, where N //! <b>Complexity</b>: 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()) if(node_traits::get_next(this->get_root_node())
!= node_traits::get_previous(this->get_root_node())){ != node_traits::get_previous(this->get_root_node())){
list carry; list_impl carry;
list counter[64]; list_impl counter[64];
int fill = 0; int fill = 0;
while(!this->empty()){ while(!this->empty()){
carry.splice(carry.begin(), *this, this->begin()); carry.splice(carry.begin(), *this, this->begin());
@@ -943,7 +1030,7 @@ class list
//! size() + x.size() - 1 comparisons. //! size() + x.size() - 1 comparisons.
//! //!
//! <b>Note</b>: Iterators and references are not invalidated //! <b>Note</b>: Iterators and references are not invalidated
void merge(list& x) void merge(list_impl& x)
{ merge(x, std::less<value_type>()); } { merge(x, std::less<value_type>()); }
//! <b>Requires</b>: p must be a comparison function that induces a strict weak //! <b>Requires</b>: p must be a comparison function that induces a strict weak
@@ -961,7 +1048,7 @@ class list
//! //!
//! <b>Note</b>: Iterators and references are not invalidated. //! <b>Note</b>: Iterators and references are not invalidated.
template<class Predicate> template<class Predicate>
void merge(list& x, Predicate p) void merge(list_impl& x, Predicate p)
{ {
iterator e = this->end(); iterator e = this->end();
iterator bx = x.begin(); iterator bx = x.begin();
@@ -1142,10 +1229,13 @@ class list
//! <b>Complexity</b>: Constant time. //! <b>Complexity</b>: Constant time.
//! //!
//! <b>Note</b>: Iterators and references are not invalidated. //! <b>Note</b>: Iterators and references are not invalidated.
static iterator iterator_to(reference value) //! This static function is available only if the <i>value traits</i>
//! is stateless.
static iterator s_iterator_to(reference value)
{ {
BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(value))); BOOST_STATIC_ASSERT((!stateful_value_traits));
return iterator(ValueTraits::to_node_ptr(value)); BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(value)));
return iterator(real_value_traits::to_node_ptr(value), 0);
} }
//! <b>Requires</b>: value must be a const reference to a value inserted in a list. //! <b>Requires</b>: value must be a const reference to a value inserted in a list.
@@ -1157,20 +1247,91 @@ class list
//! <b>Complexity</b>: Constant time. //! <b>Complexity</b>: Constant time.
//! //!
//! <b>Note</b>: Iterators and references are not invalidated. //! <b>Note</b>: Iterators and references are not invalidated.
static const_iterator iterator_to(const_reference value) //! This static function is available only if the <i>value traits</i>
//! is stateless.
static const_iterator s_iterator_to(const_reference value)
{ {
BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast<reference> (value)))); BOOST_STATIC_ASSERT((!stateful_value_traits));
return const_iterator(ValueTraits::to_node_ptr(const_cast<reference> (value))); BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(const_cast<reference> (value))));
return const_iterator(real_value_traits::to_node_ptr(const_cast<reference> (value)), 0);
} }
//! <b>Requires</b>: value must be a reference to a value inserted in a list.
//!
//! <b>Effects</b>: This function returns a const_iterator pointing to the element
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
iterator iterator_to(reference value)
{
BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(value)));
return iterator(real_value_traits::to_node_ptr(value), this);
}
//! <b>Requires</b>: value must be a const reference to a value inserted in a list.
//!
//! <b>Effects</b>: This function returns an iterator pointing to the element.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
const_iterator iterator_to(const_reference value) const
{
BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(const_cast<reference> (value))));
return const_iterator(real_value_traits::to_node_ptr(const_cast<reference> (value)), this);
}
/// @cond
private:
static list_impl &priv_container_from_end_iterator(const const_iterator &end_iterator)
{
root_plus_size *r = detail::parent_from_member<root_plus_size, node>
( detail::get_pointer(end_iterator.pointed_node()), &root_plus_size::root_);
data_t *d = detail::parent_from_member<data_t, root_plus_size>
( r, &data_t::root_plus_size_);
list_impl *s = detail::parent_from_member<list_impl, data_t>(d, &list_impl::data_);
return *s;
}
/// @endcond
}; };
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator==(const list<V, C, S>& x, const list<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator<
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
#else
(const list_impl<Config> &x, const list_impl<Config> &y)
#endif
{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class ...Options>
#else
template<class Config>
#endif
bool operator==
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
#else
(const list_impl<Config> &x, const list_impl<Config> &y)
#endif
{ {
typedef list_impl<Config> list_type;
typedef typename list_type::const_iterator const_iterator;
const bool C = list_type::constant_time_size;
if(C && x.size() != y.size()){ if(C && x.size() != y.size()){
return false; return false;
} }
typedef typename list<V, C, S>::const_iterator const_iterator;
const_iterator end1 = x.end(); const_iterator end1 = x.end();
const_iterator i1 = x.begin(); const_iterator i1 = x.begin();
@@ -1192,31 +1353,132 @@ inline bool operator==(const list<V, C, S>& x, const list<V, C, S>& y)
} }
} }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator<(const list<V, C, S>& x, template<class T, class ...Options>
const list<V, C, S>& y) #else
{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } template<class Config>
#endif
template <class V, bool C, class S> inline bool operator!=
inline bool operator!=(const list<V, C, S>& x, const list<V, C, S>& y) #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
#else
(const list_impl<Config> &x, const list_impl<Config> &y)
#endif
{ return !(x == y); } { return !(x == y); }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator>(const list<V, C, S>& x, const list<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator>
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
#else
(const list_impl<Config> &x, const list_impl<Config> &y)
#endif
{ return y < x; } { return y < x; }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator<=(const list<V, C, S>& x, const list<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator<=
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
#else
(const list_impl<Config> &x, const list_impl<Config> &y)
#endif
{ return !(y < x); } { return !(y < x); }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator>=(const list<V, C, S>& x, const list<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator>=
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const list_impl<T, Options...> &x, const list_impl<T, Options...> &y)
#else
(const list_impl<Config> &x, const list_impl<Config> &y)
#endif
{ return !(x < y); } { return !(x < y); }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline void swap(list<V, C, S>& x, list<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline void swap
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(list_impl<T, Options...> &x, list_impl<T, Options...> &y)
#else
(list_impl<Config> &x, list_impl<Config> &y)
#endif
{ x.swap(y); } { x.swap(y); }
//! Helper metafunction to define a \c list that yields to the same type when the
//! same options (either explicitly or implicitly) are used.
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class ...Options>
#else
template<class T, class O1 = none, class O2 = none, class O3 = none>
#endif
struct make_list
{
/// @cond
typedef typename pack_options
< list_defaults<T>, O1, O2, O3>::type packed_options;
typedef typename detail::get_value_traits
<T, typename packed_options::value_traits>::type value_traits;
typedef list_impl
<
listopt
< value_traits
, typename packed_options::size_type
, packed_options::constant_time_size
>
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class O1, class O2, class O3>
class list
: public make_list<T, O1, O2, O3>::type
{
typedef typename make_list
<T, O1, O2, O3>::type Base;
typedef typename Base::real_value_traits real_value_traits;
//Assert if passed value traits are compatible with the type
BOOST_STATIC_ASSERT((detail::is_same<typename real_value_traits::value_type, T>::value));
public:
typedef typename Base::value_traits value_traits;
typedef typename Base::iterator iterator;
typedef typename Base::const_iterator const_iterator;
list(const value_traits &v_traits = value_traits())
: Base(v_traits)
{}
template<class Iterator>
list(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
: Base(b, e, v_traits)
{}
static list &container_from_end_iterator(iterator end_iterator)
{ return static_cast<list &>(Base::container_from_end_iterator(end_iterator)); }
static const list &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const list &>(Base::container_from_end_iterator(end_iterator)); }
};
#endif
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost

View File

@@ -17,293 +17,104 @@
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp> #include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/utilities.hpp> #include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/detail/list_node.hpp> #include <boost/intrusive/detail/list_node.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp> #include <boost/intrusive/circular_list_algorithms.hpp>
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/options.hpp>
#include <boost/intrusive/tag.hpp> #include <boost/intrusive/detail/generic_hook.hpp>
#include <boost/static_assert.hpp>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
//! Derive a class from list_base_hook in order to store objects in /// @cond
//! in an list. list_base_hook holds the data necessary to maintain the template<class VoidPointer>
//! list and provides an appropriate value_traits class for list. struct get_list_node_algo
//!
//! 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<VoidPointer>::node
{ {
public: typedef circular_list_algorithms<list_node_traits<VoidPointer> > type;
typedef detail::list_node_traits<VoidPointer> node_traits; };
enum { linking_policy = Policy }; /// @endcond
//! Helper metafunction to define a \c \c list_base_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class ...Options>
#else
template<class O1 = none, class O2 = none, class O3 = none>
#endif
struct make_list_base_hook
{
/// @cond /// @cond
private: typedef typename pack_options
typedef circular_list_algorithms<node_traits> node_algorithms; < hook_defaults, O1, O2, O3>::type packed_options;
public: typedef detail::generic_hook
typedef typename node_traits::node node; < get_list_node_algo<typename packed_options::void_pointer>
typedef typename boost::pointer_to_other , typename packed_options::tag
<VoidPointer, node>::type node_ptr; , packed_options::link_mode
typedef typename boost::pointer_to_other , detail::ListBaseHook
<VoidPointer, const node>::type const_node_ptr; > implementation_defined;
typedef list_base_hook
<Tag, Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type>::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type>::type const_this_type_ptr;
private:
node_ptr this_as_node()
{ return node_ptr(static_cast<node *const>(this)); }
const_node_ptr this_as_node() const
{ return const_node_ptr(static_cast<const node *const>(this)); }
/// @endcond /// @endcond
typedef implementation_defined type;
public:
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
list_base_hook()
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using list_base_hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate
//! move-semantics.
list_base_hook(const list_base_hook& )
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
//! makes classes using list_base_hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate
//! move-semantics.
list_base_hook& operator=(const list_base_hook& )
{ return *this; }
//! <b>Effects</b>: If Policy is normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the
//! object is stored in an list an assertion is raised. If Policy is
//! auto_unlink and "is_linked()" is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
~list_base_hook()
{ detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(list_base_hook &other)
{ node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether list::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const
{
//is_linked() can be only used in safe-mode or auto-unlink
BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
return !node_algorithms::unique(this_as_node());
}
//! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if Policy is auto_unlink.
//!
//! <b>Throws</b>: Nothing.
void unlink()
{
BOOST_STATIC_ASSERT((Policy == auto_unlink));
node_algorithms::unlink(this_as_node());
node_algorithms::init(this_as_node());
}
//! The value_traits class is used as the first template argument for list.
//! The template argument T defines the class type stored in list. Objects
//! of type T and of types derived from T can be stored. T doesn't need to be
//! copy-constructible or assignable.
template<class T>
struct value_traits
: detail::derivation_hook_value_traits<T, this_type, Tag>
{};
//! <b>Effects</b>: Converts a pointer to a node into
//! a pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static this_type_ptr to_hook_ptr(node_ptr p)
{
return this_type_ptr(static_cast<list_base_hook*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into
//! a const pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p)
{
return const_this_type_ptr(static_cast<const list_base_hook*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Returns a pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
node_ptr to_node_ptr()
{ return this_as_node(); }
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
const_node_ptr to_node_ptr() const
{ return this_as_node(); }
}; };
//! Put a public data member list_member_hook in order to store objects of this class in //! Derive a class from this hook in order to store objects of that class
//! an list. list_member_hook holds the data necessary for maintaining the list and //! in an list.
//! provides an appropriate value_traits class for 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 //! \c tag<> defines a tag to identify the node.
//! and the list configured from this hook. //! The same tag value can be used in different classes, but if a class is
template< linking_policy Policy //= safe_link //! derived from more than one \c list_base_hook, then each \c list_base_hook needs its
, class VoidPointer //= void * //! unique tag.
> //!
class list_member_hook //! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
: private detail::list_node_traits<VoidPointer>::node //! \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<class ...Options>
#else
template<class O1, class O2, class O3>
#endif
class list_base_hook
: public make_list_base_hook<O1, O2, O3>::type
{ {
public: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
typedef detail::list_node_traits<VoidPointer> node_traits; //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
enum { linking_policy = Policy };
/// @cond
private:
typedef circular_list_algorithms<node_traits> node_algorithms;
/// @endcond
public:
typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef list_member_hook
<Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type >::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type >::type const_this_type_ptr;
/// @cond
private:
node_ptr this_as_node()
{ return node_ptr(static_cast<node *const>(this)); }
const_node_ptr this_as_node() const
{ return const_node_ptr(static_cast<const node *const>(this)); }
/// @endcond
public:
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. //! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
list_member_hook() list_base_hook();
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing a copy-constructor //! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using list_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
list_member_hook(const list_member_hook& ) list_base_hook(const list_base_hook& );
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: Empty function. The argument is ignored. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing an assignment operator //! <b>Rationale</b>: Providing an assignment operator
//! makes classes using list_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
list_member_hook& operator=(const list_member_hook& ) list_base_hook& operator=(const list_base_hook& );
{ return *this; }
//! <b>Effects</b>: If Policy is normal_link, the destructor does //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the //! 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 Policy is //! object is stored in an list an assertion is raised. If link_mode is
//! auto_unlink and "is_linked()" is true, the node is unlinked. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
~list_member_hook() ~list_base_hook();
{ detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node //! related to those nodes in one or two containers. That is, if the node
@@ -317,72 +128,132 @@ class list_member_hook
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void swap_nodes(list_member_hook& other) void swap_nodes(list_base_hook &other);
{ node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink. //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//! //!
//! <b>Returns</b>: true, if the node belongs to a container, false //! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether list::iterator_to //! otherwise. This function can be used to test whether \c list::iterator_to
//! will return a valid iterator. //! will return a valid iterator.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
bool is_linked() const bool is_linked() const;
{
//is_linked() can be only used in safe-mode or auto-unlink
BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
return !node_algorithms::unique(this_as_node());
}
//! <b>Effects</b>: Removes the node if it's inserted in a container. //! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if Policy is auto_unlink. //! This function is only allowed if link_mode is \c auto_unlink.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void unlink() void unlink();
{ #endif
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. //! Helper metafunction to define a \c \c list_member_hook that yields to the same
//! The template argument is a pointer to member pointing to the node in //! type when the same options (either explicitly or implicitly) are used.
//! the class. Objects of type T and of types derived from T can be stored. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! T doesn't need to be copy-constructible or assignable. template<class ...Options>
template<class T, this_type T::* M> #else
struct value_traits template<class O1 = none, class O2 = none, class O3 = none>
: detail::member_hook_value_traits<T, this_type, M> #endif
{}; struct make_list_member_hook
{
/// @cond
typedef typename pack_options
< hook_defaults, O1, O2, O3>::type packed_options;
//! <b>Effects</b>: Converts a pointer to a node into typedef detail::generic_hook
//! a pointer to the hook that holds that node. < get_list_node_algo<typename packed_options::void_pointer>
, 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<class ...Options>
#else
template<class O1, class O2, class O3>
#endif
class list_member_hook
: public make_list_member_hook<O1, O2, O3>::type
{
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
static this_type_ptr to_hook_ptr(node_ptr p) list_member_hook();
{
return this_type_ptr(static_cast<this_type*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! a const pointer to the hook that holds that node. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p) //!
{ //! <b>Rationale</b>: Providing a copy-constructor
return const_this_type_ptr(static_cast<const this_type*> (detail::get_pointer(p))); //! 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& );
//! <b>Effects</b>: Returns a pointer to the node that this hook holds. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
node_ptr to_node_ptr() //!
{ return this_as_node(); } //! <b>Rationale</b>: 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& );
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds. //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If link_mode is \c safe_link and the
//! object is stored in an list an assertion is raised. If link_mode is
//! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
const_node_ptr to_node_ptr() const ~list_member_hook();
{ return this_as_node(); }
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(list_member_hook &other);
//! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c list::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
void unlink();
#endif
}; };
} //namespace intrusive } //namespace intrusive

View File

@@ -13,7 +13,7 @@
#ifndef BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP #ifndef BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP #define BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/link_mode.hpp>
#include <iterator> #include <iterator>
#include <boost/intrusive/detail/parent_from_member.hpp> #include <boost/intrusive/detail/parent_from_member.hpp>
@@ -25,7 +25,7 @@ namespace intrusive {
//!store a node_traits::node //!store a node_traits::node
template< class T, class NodeTraits template< class T, class NodeTraits
, typename NodeTraits::node T::* PtrToMember , typename NodeTraits::node T::* PtrToMember
, linking_policy Policy> , link_mode_type LinkMode = safe_link>
struct member_value_traits struct member_value_traits
{ {
public: public:
@@ -38,8 +38,7 @@ struct member_value_traits
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer; typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef typename std::iterator_traits<pointer>::reference reference; typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference; typedef typename std::iterator_traits<const_pointer>::reference const_reference;
static const link_mode_type link_mode = LinkMode;
enum { linking_policy = Policy };
static node_ptr to_node_ptr(reference value) static node_ptr to_node_ptr(reference value)
{ return node_ptr(&(value.*PtrToMember)); } { return node_ptr(&(value.*PtrToMember)); }

View File

@@ -0,0 +1,429 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_OPTIONS_HPP
#define BOOST_INTRUSIVE_OPTIONS_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/detail/utilities.hpp>
#include <boost/static_assert.hpp>
namespace boost {
namespace intrusive {
/// @cond
struct default_tag;
struct member_tag;
namespace detail{
template <class ValueTraits>
struct eval_value_traits
{
typedef typename ValueTraits::value_traits type;
};
template <class T>
struct external_bucket_traits_is_true
{
static const bool value = external_bucket_traits_bool<T>::value == 3;
};
template <class BucketTraits>
struct eval_bucket_traits
{
typedef typename BucketTraits::bucket_traits type;
};
template<class T, class BaseHook>
struct get_base_value_traits
{
typedef detail::base_hook_traits
< T
, typename BaseHook::boost_intrusive_tags::node_traits
, BaseHook::boost_intrusive_tags::link_mode
, typename BaseHook::boost_intrusive_tags::tag
, BaseHook::boost_intrusive_tags::hook_type> type;
};
template<class T, class MemberHook>
struct get_member_value_traits
{
typedef typename MemberHook::member_value_traits type;
};
template<class T, class SupposedValueTraits>
struct get_value_traits
{
typedef SupposedValueTraits supposed_value_traits;
//...if it's a base hook
typedef typename detail::eval_if_c
< internal_base_hook_bool_is_true<supposed_value_traits>::value
//...get it's internal value traits using
//the provided T value type.
, get_base_value_traits<T, supposed_value_traits>
//...else use it's internal value traits tag
//(member hooks and custom value traits are in this group)
, detail::eval_if_c
< internal_member_value_traits<supposed_value_traits>::value
, get_member_value_traits<T, supposed_value_traits>
, detail::identity<supposed_value_traits>
>
>::type type;
};
template<class BaseHook>
struct get_base_node_traits
{
typedef typename BaseHook::boost_intrusive_tags::node_traits type;
};
template<class MemberHook>
struct get_member_node_traits
{
typedef typename MemberHook::member_value_traits::node_traits type;
};
template<class ValueTraits>
struct get_explicit_node_traits
{
typedef typename ValueTraits::node_traits type;
};
template<class SupposedValueTraits>
struct get_node_traits
{
typedef SupposedValueTraits supposed_value_traits;
//...if it's a base hook
typedef typename detail::eval_if_c
< internal_base_hook_bool_is_true<supposed_value_traits>::value
//...get it's internal value traits using
//the provided T value type.
, get_base_node_traits<supposed_value_traits>
//...else use it's internal value traits tag
//(member hooks and custom value traits are in this group)
, detail::eval_if_c
< internal_member_value_traits<supposed_value_traits>::value
, get_member_node_traits<supposed_value_traits>
, get_explicit_node_traits<supposed_value_traits>
>
>::type type;
};
} //namespace detail{
//!This type indicates that no option is being used
//!and that the default options should be used
struct none
{
template<class Base>
struct pack : Base
{ };
};
/// @endcond
//!This option setter specifies if the intrusive
//!container stores its size as a member to
//!obtain constant-time size() member.
template<bool Enabled>
struct constant_time_size
{
/// @cond
template<class Base>
struct pack : Base
{
static const bool constant_time_size = Enabled;
};
/// @endcond
};
//!This option setter specifies the type that
//!the container will use to store its size.
template<class SizeType>
struct size_type
{
/// @cond
template<class Base>
struct pack : Base
{
typedef SizeType size_type;
};
/// @endcond
};
//!This option setter specifies the strict weak ordering
//!comparison functor for the value type
template<class Compare>
struct compare
{
/// @cond
template<class Base>
struct pack : Base
{
typedef Compare compare;
};
/// @endcond
};
//!This option setter specifies the equality
//!functor for the value type
template<class Equal>
struct equal
{
/// @cond
template<class Base>
struct pack : Base
{
typedef Equal equal;
};
/// @endcond
};
//!This option setter specifies the hash
//!functor for the value type
template<class Hash>
struct hash
{
/// @cond
template<class Base>
struct pack : Base
{
typedef Hash hash;
};
/// @endcond
};
//!This option setter specifies the relationship between the type
//!to be managed by the container (the value type) and the node to be
//!used in the node algorithms. It also specifies the linking policy.
template<typename ValueTraits>
struct value_traits
{
/// @cond
template<class Base>
struct pack : Base
{
typedef ValueTraits value_traits;
};
/// @endcond
};
//!This option setter specifies the member hook the
//!container must use.
template< typename Parent
, typename MemberHook
, MemberHook Parent::* PtrToMember>
struct member_hook
{
/// @cond
typedef char Parent::* GenericPtrToMember;
typedef detail::member_hook_traits
< Parent
, MemberHook
, PtrToMember
> member_value_traits;
template<class Base>
struct pack : Base
{
typedef member_value_traits value_traits;
};
/// @endcond
};
//!This option setter specifies that the container
//!must use the specified base hook
template<typename BaseHook>
struct base_hook
{
/// @cond
template<class Base>
struct pack : Base
{
typedef BaseHook value_traits;
};
/// @endcond
};
//!This option setter specifies the type of
//!a void pointer. This will instruct the hook
//!to use this type of pointer instead of the
//!default one
template<class VoidPointer>
struct void_pointer
{
/// @cond
template<class Base>
struct pack : Base
{
typedef VoidPointer void_pointer;
};
/// @endcond
};
//!This option setter specifies the type of
//!the tag of a base hook. A type can not have two
//!base hooks of the same type, so a tag can be used
//!to differentiate two base hooks with otherwise same type
template<class BaseTag>
struct tag
{
/// @cond
template<class Base>
struct pack : Base
{
typedef BaseTag tag;
};
/// @endcond
};
//!This option setter specifies the type of
//!a void pointer. This will instruct the hook
//!to use this type of pointer instead of the
//!default one
template<link_mode_type LinkType>
struct link_mode
{
/// @cond
template<class Base>
struct pack : Base
{
static const link_mode_type link_mode = LinkType;
};
/// @endcond
};
//!This option setter specifies the bucket traits
//!class for unordered associative containers. When this option is specified,
//!instead of using the default bucket traits, a user defined holder will be defined
template<class BucketTraits>
struct bucket_traits
{
/// @cond
template<class Base>
struct pack : Base
{
typedef BucketTraits bucket_traits;
};
/// @endcond
};
//!This option setter specifies if the bucket array will be always power of two.
//!This allows using masks instead of the default modulo operation to determine
//!the bucket number from the hash value, leading to better performance.
//!In debug mode, if power of two buckets mode is activated, the bucket length
//!will be checked to through assertions to assure the bucket length is power of two.
template<bool Enabled>
struct power_2_buckets
{
/// @cond
template<class Base>
struct pack : Base
{
static const bool power_2_buckets = Enabled;
};
/// @endcond
};
/// @cond
template<class Prev, class Next>
struct do_pack
{
//Use "pack" member template to pack options
typedef typename Next::template pack<Prev> type;
};
template<class Prev>
struct do_pack<Prev, none>
{
//Avoid packing "none" to shorten template names
typedef Prev type;
};
template
< class DefaultOptions
, class O1 = none
, class O2 = none
, class O3 = none
, class O4 = none
, class O5 = none
, class O6 = none
, class O7 = none
, class O8 = none
, class O9 = none
, class Option10 = none
>
struct pack_options
{
// join options
typedef
typename do_pack
< typename do_pack
< typename do_pack
< typename do_pack
< typename do_pack
< typename do_pack
< typename do_pack
< typename do_pack
< typename do_pack
< typename do_pack
< DefaultOptions
, O1
>::type
, O2
>::type
, O3
>::type
, O4
>::type
, O5
>::type
, O6
>::type
, O7
>::type
, O8
>::type
, O9
>::type
, Option10
>::type
type;
};
struct hook_defaults
: public pack_options
< none
, void_pointer<void*>
, link_mode<safe_link>
, tag<default_tag>
>::type
{};
/// @endcond
} //namespace intrusive {
} //namespace boost {
#include <boost/intrusive/detail/config_end.hpp>
#endif //#ifndef BOOST_INTRUSIVE_OPTIONS_HPP

View File

@@ -23,7 +23,7 @@ namespace intrusive {
template<class VoidPointer, std::size_t Alignment> template<class VoidPointer, std::size_t Alignment>
struct has_pointer_plus_bit struct has_pointer_plus_bit
{ {
enum { value = false }; static const bool value = false;
}; };
//!This is an specialization for raw pointers. //!This is an specialization for raw pointers.
@@ -32,7 +32,7 @@ struct has_pointer_plus_bit
template<std::size_t N> template<std::size_t N>
struct has_pointer_plus_bit<void*, N> struct has_pointer_plus_bit<void*, N>
{ {
enum { value = N % 2u == 0 }; static const bool value = (N % 2u == 0);
}; };
//!This is class that is supposed to have static methods //!This is class that is supposed to have static methods

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,15 @@
// in supporting documentation. Hewlett-Packard Company makes no // in supporting documentation. Hewlett-Packard Company makes no
// representations about the suitability of this software for any // representations about the suitability of this software for any
// purpose. It is provided "as is" without express or implied warranty. // 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 #ifndef BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
#define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP #define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
@@ -43,9 +52,7 @@
#include <boost/intrusive/detail/assert.hpp> #include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/intrusive_fwd.hpp> #include <boost/intrusive/intrusive_fwd.hpp>
#include <cstddef> #include <cstddef>
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING #include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#endif
#include <boost/intrusive/detail/utilities.hpp> #include <boost/intrusive/detail/utilities.hpp>
@@ -67,7 +74,7 @@ namespace intrusive {
//! relinked into its place, rather than copied, so that the only //! relinked into its place, rather than copied, so that the only
//! pointers invalidated are those referring to the deleted node. //! 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 //! information about the node to be manipulated. NodeTraits must support the
//! following interface: //! following interface:
//! //!
@@ -111,6 +118,7 @@ class rbtree_algorithms
/// @endcond /// @endcond
public: public:
typedef NodeTraits node_traits;
typedef typename NodeTraits::node_ptr node_ptr; typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr; typedef typename NodeTraits::const_node_ptr const_node_ptr;
typedef typename NodeTraits::color color; typedef typename NodeTraits::color color;
@@ -121,6 +129,27 @@ class rbtree_algorithms
{ {
return node_ptr(const_cast<node*>(::boost::intrusive::detail::get_pointer(ptr))); return node_ptr(const_cast<node*>(::boost::intrusive::detail::get_pointer(ptr)));
} }
static void swap_left(node_ptr this_node, node_ptr other_node)
{
node_ptr temp(NodeTraits::get_left(this_node));
NodeTraits::set_left(this_node, NodeTraits::get_left(other_node));
NodeTraits::set_left(other_node, temp);
}
static void swap_right(node_ptr this_node, node_ptr other_node)
{
node_ptr temp(NodeTraits::get_right(this_node));
NodeTraits::set_right(this_node, NodeTraits::get_right(other_node));
NodeTraits::set_right(other_node, temp);
}
static void swap_parent(node_ptr this_node, node_ptr other_node)
{
node_ptr temp(NodeTraits::get_parent(this_node));
NodeTraits::set_parent(this_node, NodeTraits::get_parent(other_node));
NodeTraits::set_parent(other_node, temp);
}
/// @endcond /// @endcond
public: public:
@@ -146,7 +175,14 @@ class rbtree_algorithms
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
static void swap_tree(node_ptr header1, node_ptr header2) 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) if(header1 == header2)
return; 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;
}
//! <b>Requires</b>: node1 and node2 can't be header nodes
//! of two trees.
//!
//! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted
//! in the position node2 before the function. node2 will be inserted in the
//! position node1 had before the function.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Note</b>: This function will break container ordering invariants if
//! node1 and node2 are not equivalent according to the ordering rules.
//!
//!Experimental function
static void swap_nodes(node_ptr node1, node_ptr node2)
{
if(node1 == node2)
return;
node_ptr header1(get_header(node1)), header2(get_header(node2));
swap_nodes(node1, header1, node2, header2);
}
//! <b>Requires</b>: node1 and node2 can't be header nodes
//! of two trees with header header1 and header2.
//!
//! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted
//! in the position node2 before the function. node2 will be inserted in the
//! position node1 had before the function.
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Note</b>: This function will break container ordering invariants if
//! node1 and node2 are not equivalent according to the ordering rules.
//!
//!Experimental function
static void swap_nodes(node_ptr node1, node_ptr header1, node_ptr node2, node_ptr header2)
{
if(node1 == node2)
return;
//node1 and node2 must not be header nodes
//BOOST_INTRUSIVE_INVARIANT_ASSERT((header1 != node1 && header2 != node2));
if(header1 != header2){
//Update header1 if necessary
if(node1 == NodeTraits::get_left(header1)){
NodeTraits::set_left(header1, node2);
}
if(node1 == NodeTraits::get_right(header1)){
NodeTraits::set_right(header1, node2);
}
if(node1 == NodeTraits::get_parent(header1)){
NodeTraits::set_parent(header1, node2);
}
//Update header2 if necessary
if(node2 == NodeTraits::get_left(header2)){
NodeTraits::set_left(header2, node1);
}
if(node2 == NodeTraits::get_right(header2)){
NodeTraits::set_right(header2, node1);
}
if(node2 == NodeTraits::get_parent(header2)){
NodeTraits::set_parent(header2, node1);
}
}
else{
//If both nodes are from the same tree
//Update header if necessary
if(node1 == NodeTraits::get_left(header1)){
NodeTraits::set_left(header1, node2);
}
else if(node2 == NodeTraits::get_left(header2)){
NodeTraits::set_left(header2, node1);
}
if(node1 == NodeTraits::get_right(header1)){
NodeTraits::set_right(header1, node2);
}
else if(node2 == NodeTraits::get_right(header2)){
NodeTraits::set_right(header2, node1);
}
if(node1 == NodeTraits::get_parent(header1)){
NodeTraits::set_parent(header1, node2);
}
else if(node2 == NodeTraits::get_parent(header2)){
NodeTraits::set_parent(header2, node1);
}
//Adjust data in nodes to be swapped
//so that final link swap works as expected
if(node1 == NodeTraits::get_parent(node2)){
NodeTraits::set_parent(node2, node2);
if(node2 == NodeTraits::get_right(node1)){
NodeTraits::set_right(node1, node1);
}
else{
NodeTraits::set_left(node1, node1);
}
}
else if(node2 == NodeTraits::get_parent(node1)){
NodeTraits::set_parent(node1, node1);
if(node1 == NodeTraits::get_right(node2)){
NodeTraits::set_right(node2, node2);
}
else{
NodeTraits::set_left(node2, node2);
}
}
}
//Now swap all the links
node_ptr temp;
//swap left link
temp = NodeTraits::get_left(node1);
NodeTraits::set_left(node1, NodeTraits::get_left(node2));
NodeTraits::set_left(node2, temp);
//swap right link
temp = NodeTraits::get_right(node1);
NodeTraits::set_right(node1, NodeTraits::get_right(node2));
NodeTraits::set_right(node2, temp);
//swap parent link
temp = NodeTraits::get_parent(node1);
NodeTraits::set_parent(node1, NodeTraits::get_parent(node2));
NodeTraits::set_parent(node2, temp);
//Swap color
color c = NodeTraits::get_color(node1);
NodeTraits::set_color(node1, NodeTraits::get_color(node2));
NodeTraits::set_color(node2, c);
//Now adjust adjacent nodes for newly inserted node 1
if((temp = NodeTraits::get_left(node1))){
NodeTraits::set_parent(temp, node1);
}
if((temp = NodeTraits::get_right(node1))){
NodeTraits::set_parent(temp, node1);
}
if((temp = NodeTraits::get_parent(node1)) &&
//The header has been already updated so avoid it
temp != header2){
if(NodeTraits::get_left(temp) == node2){
NodeTraits::set_left(temp, node1);
}
if(NodeTraits::get_right(temp) == node2){
NodeTraits::set_right(temp, node1);
}
}
//Now adjust adjacent nodes for newly inserted node 2
if((temp = NodeTraits::get_left(node2))){
NodeTraits::set_parent(temp, node2);
}
if((temp = NodeTraits::get_right(node2))){
NodeTraits::set_parent(temp, node2);
}
if((temp = NodeTraits::get_parent(node2)) &&
//The header has been already updated so avoid it
temp != header1){
if(NodeTraits::get_left(temp) == node1){
NodeTraits::set_left(temp, node2);
}
if(NodeTraits::get_right(temp) == node1){
NodeTraits::set_right(temp, node2);
}
}
}
//! <b>Requires</b>: node_to_be_replaced must be inserted in a tree
//! and new_node must not be inserted in a tree.
//!
//! <b>Effects</b>: Replaces node_to_be_replaced in its position in the
//! tree with new_node. The tree does not need to be rebalanced
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Note</b>: This function will break container ordering invariants if
//! new_node is not equivalent to node_to_be_replaced according to the
//! ordering rules. This function is faster than erasing and inserting
//! the node, since no rebalancing and comparison is needed.
//!
//!Experimental function
static void replace_node(node_ptr node_to_be_replaced, node_ptr new_node)
{
if(node_to_be_replaced == new_node)
return;
replace_node(node_to_be_replaced, get_header(node_to_be_replaced), new_node);
}
//! <b>Requires</b>: node_to_be_replaced must be inserted in a tree
//! with header "header" and new_node must not be inserted in a tree.
//!
//! <b>Effects</b>: Replaces node_to_be_replaced in its position in the
//! tree with new_node. The tree does not need to be rebalanced
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Note</b>: This function will break container ordering invariants if
//! new_node is not equivalent to node_to_be_replaced according to the
//! ordering rules. This function is faster than erasing and inserting
//! the node, since no rebalancing or comparison is needed.
//!
//!Experimental function
static void replace_node(node_ptr node_to_be_replaced, node_ptr header, node_ptr new_node)
{
if(node_to_be_replaced == new_node)
return;
//Update header if necessary
if(node_to_be_replaced == NodeTraits::get_left(header)){
NodeTraits::set_left(header, new_node);
}
if(node_to_be_replaced == NodeTraits::get_right(header)){
NodeTraits::set_right(header, new_node);
}
if(node_to_be_replaced == NodeTraits::get_parent(header)){
NodeTraits::set_parent(header, new_node);
}
//Now set data from the original node
node_ptr temp;
NodeTraits::set_left(new_node, NodeTraits::get_left(node_to_be_replaced));
NodeTraits::set_right(new_node, NodeTraits::get_right(node_to_be_replaced));
NodeTraits::set_parent(new_node, NodeTraits::get_parent(node_to_be_replaced));
NodeTraits::set_color(new_node, NodeTraits::get_color(node_to_be_replaced));
//Now adjust adjacent nodes for newly inserted node
if((temp = NodeTraits::get_left(new_node))){
NodeTraits::set_parent(temp, new_node);
}
if((temp = NodeTraits::get_right(new_node))){
NodeTraits::set_parent(temp, new_node);
}
if((temp = NodeTraits::get_parent(new_node)) &&
//The header has been already updated so avoid it
temp != header){
if(NodeTraits::get_left(temp) == node_to_be_replaced){
NodeTraits::set_left(temp, new_node);
}
if(NodeTraits::get_right(temp) == node_to_be_replaced){
NodeTraits::set_right(temp, new_node);
}
}
}
//! <b>Requires</b>: node is a tree node but not the header. //! <b>Requires</b>: node is a tree node but not the header.
//! //!
//! <b>Effects</b>: Unlinks the node and rebalances the tree. //! <b>Effects</b>: Unlinks the node and rebalances the tree.
@@ -202,6 +508,10 @@ class rbtree_algorithms
} }
} }
static void unlink(node_ptr node)
{ unlink_and_rebalance(node); }
//! <b>Requires</b>: header is the header of a tree. //! <b>Requires</b>: header is the header of a tree.
//! //!
//! <b>Effects</b>: Unlinks the leftmost node from the tree, and //! <b>Effects</b>: Unlinks the leftmost node from the tree, and
@@ -508,25 +818,42 @@ class rbtree_algorithms
//! //!
//! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed. //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.
template <class Cloner, class Disposer> template <class Cloner, class Disposer>
static void clone_tree static void clone
(const_node_ptr source_header, node_ptr target_header, Cloner cloner, Disposer disposer) (const_node_ptr source_header, node_ptr target_header, Cloner cloner, Disposer disposer)
{ {
if(!unique(target_header)){ if(!unique(target_header)){
node_ptr p; clear_and_dispose(target_header, disposer);
while((p = unlink_leftmost_without_rebalance(target_header))){
disposer(p);
}
} }
node_ptr source_root = NodeTraits::get_parent(source_header); node_ptr leftmost, rightmost;
node_ptr new_root = clone_subtree
(source_header, target_header, cloner, disposer, leftmost, rightmost);
//Now update header node
NodeTraits::set_parent(target_header, new_root);
NodeTraits::set_left (target_header, leftmost);
NodeTraits::set_right (target_header, rightmost);
}
//! <b>Requires</b>: "disposer" must be an object function
//! taking a node_ptr parameter and shouldn't throw.
//!
//! <b>Effects</b>: Empties the target tree calling
//! <tt>void disposer::operator()(node_ptr)</tt> for every node of the tree
//! except the header.
//!
//! <b>Complexity</b>: Linear to the number of element of the source tree plus the.
//! number of elements of tree target tree when calling this function.
//!
//! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.
template<class Disposer>
static void clear_and_dispose(node_ptr header, Disposer disposer)
{
node_ptr source_root = NodeTraits::get_parent(header);
if(!source_root) if(!source_root)
return; return;
dispose_subtree(source_root, disposer);
NodeTraits::set_parent init_header(header);
( 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)));
} }
//! <b>Requires</b>: "header" must be the header node of a tree. //! <b>Requires</b>: "header" must be the header node of a tree.
@@ -694,6 +1021,17 @@ class rbtree_algorithms
bool link_left = (y == h) || bool link_left = (y == h) ||
comp(new_node, y); comp(new_node, y);
link_and_balance(new_node, y, link_left, h); 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; return new_node;
} }
@@ -725,6 +1063,17 @@ class rbtree_algorithms
bool link_left = (y == h) || bool link_left = (y == h) ||
!comp(y, new_node); !comp(y, new_node);
link_and_balance(new_node, y, link_left, h); 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; return new_node;
} }
@@ -752,6 +1101,14 @@ class rbtree_algorithms
!comp(new_node, (prev = prev_node(hint)))){ !comp(new_node, (prev = prev_node(hint)))){
bool link_left = unique(header) || !NodeTraits::get_left(hint); bool link_left = unique(header) || !NodeTraits::get_left(hint);
link_and_balance(new_node, link_left ? hint : prev, link_left, header); 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; return new_node;
} }
else{ else{
@@ -922,6 +1279,109 @@ class rbtree_algorithms
/// @cond /// @cond
template <class Cloner, class Disposer>
static node_ptr clone_subtree
( const_node_ptr source_parent, node_ptr target_parent
, Cloner cloner, Disposer disposer
, node_ptr &leftmost_out, node_ptr &rightmost_out
)
{
node_ptr target_sub_root = target_parent;
node_ptr source_root = NodeTraits::get_parent(source_parent);
if(!source_root){
leftmost_out = rightmost_out = source_root;
}
else{
//We'll calculate leftmost and rightmost nodes while iterating
node_ptr current = source_root;
node_ptr insertion_point = target_sub_root = cloner(current);
//We'll calculate leftmost and rightmost nodes while iterating
node_ptr leftmost = target_sub_root;
node_ptr rightmost = target_sub_root;
//First set the subroot
NodeTraits::set_left(target_sub_root, 0);
NodeTraits::set_right(target_sub_root, 0);
NodeTraits::set_parent(target_sub_root, target_parent);
NodeTraits::set_color(target_sub_root, NodeTraits::get_color(current));
try {
while(true) {
//First clone left nodes
if( NodeTraits::get_left(current) &&
!NodeTraits::get_left(insertion_point)) {
current = NodeTraits::get_left(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, 0);
NodeTraits::set_right (insertion_point, 0);
NodeTraits::set_color (insertion_point, NodeTraits::get_color(current));
//Insert left
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_left (temp, insertion_point);
//Update leftmost
if(rightmost == target_sub_root)
leftmost = insertion_point;
}
//Then clone right nodes
else if( NodeTraits::get_right(current) &&
!NodeTraits::get_right(insertion_point)){
current = NodeTraits::get_right(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, 0);
NodeTraits::set_right (insertion_point, 0);
NodeTraits::set_color (insertion_point, NodeTraits::get_color(current));
//Insert right
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_right (temp, insertion_point);
//Update rightmost
rightmost = insertion_point;
}
//If not, go up
else if(current == source_root){
break;
}
else{
//Branch completed, go up searching more nodes to clone
current = NodeTraits::get_parent(current);
insertion_point = NodeTraits::get_parent(insertion_point);
}
}
}
catch(...) {
dispose_subtree(target_sub_root, disposer);
throw;
}
leftmost_out = leftmost;
rightmost_out = rightmost;
}
return target_sub_root;
}
template<class Disposer>
static void dispose_subtree(node_ptr x, Disposer disposer)
{
node_ptr save;
while (x){
save = NodeTraits::get_left(x);
if (save) {
// Right rotation
NodeTraits::set_left(x, NodeTraits::get_right(save));
NodeTraits::set_right(save, x);
}
else {
save = NodeTraits::get_right(x);
init(x);
disposer(x);
}
x = save;
}
}
//! <b>Requires</b>: z is the node to be inserted, par is its parent, //! <b>Requires</b>: z is the node to be inserted, par is its parent,
//! left, indicates if z should be a left node of par and header is the header //! left, indicates if z should be a left node of par and header is the header
//! of the tree. //! of the tree.
@@ -1106,59 +1566,6 @@ class rbtree_algorithms
} }
NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black()); NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black());
} }
template <class Cloner, class Disposer>
static node_ptr deep_clone_node
(node_ptr source_root, node_ptr new_parent, Cloner cloner, Disposer disposer)
{
// structural copy. source_root and new_parent must be non-null.
node_ptr top = cloner(source_root);
NodeTraits::set_parent(top, new_parent);
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
BOOST_TRY {
#endif
if(NodeTraits::get_right(source_root)){
NodeTraits::set_right
(top, deep_clone_node(NodeTraits::get_right(source_root), top
,cloner, disposer));
}
new_parent = top;
source_root = NodeTraits::get_left(source_root);
while(source_root){
node_ptr y = cloner(source_root);
NodeTraits::set_left(new_parent, y);
NodeTraits::set_parent(y, new_parent);
if(NodeTraits::get_right(source_root)){
NodeTraits::set_right(y, deep_clone_node(NodeTraits::get_right(source_root), y
,cloner, disposer));
}
new_parent = y;
source_root = NodeTraits::get_left(source_root);
}
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
}
BOOST_CATCH(...){
deep_dispose_node(top, disposer);
BOOST_RETHROW;
}
BOOST_CATCH_END
#endif
return top;
}
template<class Disposer>
static void deep_dispose_node(node_ptr x, Disposer disposer)
{
// erase without rebalancing
while(x){
deep_dispose_node(NodeTraits::get_right(x), disposer);
node_ptr y = NodeTraits::get_left(x);
disposer(x);
x = y;
}
}
/// @endcond /// @endcond
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -17,16 +17,45 @@
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp> #include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/utilities.hpp> #include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/detail/rbtree_node.hpp> #include <boost/intrusive/detail/rbtree_node.hpp>
#include <boost/intrusive/rbtree_algorithms.hpp> #include <boost/intrusive/rbtree_algorithms.hpp>
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/options.hpp>
#include <boost/intrusive/tag.hpp> #include <boost/intrusive/detail/generic_hook.hpp>
#include <boost/static_assert.hpp>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
/// @cond
template<class VoidPointer>
struct get_set_node_algo
{
typedef rbtree_algorithms<rbtree_node_traits<VoidPointer> > type;
};
/// @endcond
//! Helper metafunction to define a \c set_base_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class ...Options>
#else
template<class O1 = none, class O2 = none, class O3 = none>
#endif
struct make_set_base_hook
{
/// @cond
typedef typename pack_options
< hook_defaults, O1, O2, O3>::type packed_options;
typedef detail::generic_hook
< get_set_node_algo<typename packed_options::void_pointer>
, typename packed_options::tag
, packed_options::link_mode
, detail::SetBaseHook
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Derive a class from set_base_hook in order to store objects in //! 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 //! 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. //! 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 //! The third argument is the pointer type that will be used internally in the hook
//! and the set/multiset configured from this hook. //! and the set/multiset configured from this hook.
template< class Tag //= tag #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
, linking_policy Policy //= safe_link template<class ...Options>
, class VoidPointer //= void * #else
> template<class O1, class O2, class O3>
#endif
class set_base_hook class set_base_hook
: private detail::rbtree_node_traits<VoidPointer>::node : public make_set_base_hook<O1, O2, O3>::type
{ {
public: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
typedef detail::rbtree_node_traits<VoidPointer> node_traits; //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
enum { linking_policy = Policy };
/// @cond
private:
typedef rbtree_algorithms<node_traits> node_algorithms;
/// @endcond
public:
typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef set_base_hook
<Tag, Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type>::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type>::type const_this_type_ptr;
/// @cond
private:
node_ptr this_as_node()
{ return node_ptr(static_cast<node *const>(this)); }
const_node_ptr this_as_node() const
{ return const_node_ptr(static_cast<const node *const>(this)); }
/// @endcond
public:
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. //! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
set_base_hook() set_base_hook();
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing a copy-constructor //! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using set_base_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
set_base_hook(const set_base_hook& ) set_base_hook(const set_base_hook& );
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: Empty function. The argument is ignored. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing an assignment operator //! <b>Rationale</b>: Providing an assignment operator
//! makes classes using set_base_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
set_base_hook& operator=(const set_base_hook& ) set_base_hook& operator=(const set_base_hook& );
{ return *this; }
//! <b>Effects</b>: If Policy is normal_link, the destructor does //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the //! 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 Policy is //! object is stored in an set an assertion is raised. If link_mode is
//! auto_unlink and "is_linked()" is true, the node is unlinked. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
~set_base_hook() ~set_base_hook();
{ detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink. //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(set_base_hook &other);
//! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//! //!
//! <b>Returns</b>: true, if the node belongs to a container, false //! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether set::iterator_to //! otherwise. This function can be used to test whether \c set::iterator_to
//! will return a valid iterator. //! will return a valid iterator.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
bool is_linked() const bool is_linked() const;
{
//is_linked() can be only used in safe-mode or auto-unlink
BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
return !node_algorithms::unique(this_as_node());
}
//! <b>Effects</b>: Removes the node if it's inserted in a container. //! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if Policy is auto_unlink. //! This function is only allowed if link_mode is \c auto_unlink.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void unlink() void unlink();
{ #endif
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. //! Helper metafunction to define a \c set_member_hook that yields to the same
//! The template argument T defines the class type stored in multiset. Objects //! type when the same options (either explicitly or implicitly) are used.
//! of type T and of types derived from T can be stored. T don't need to be #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! copy-constructible or assignable. template<class ...Options>
template<class T> #else
struct value_traits template<class O1 = none, class O2 = none, class O3 = none>
: detail::derivation_hook_value_traits<T, this_type, Tag> #endif
{}; struct make_set_member_hook
{
/// @cond
typedef typename pack_options
< hook_defaults, O1, O2, O3>::type packed_options;
//! <b>Effects</b>: Converts a pointer to a node into typedef detail::generic_hook
//! a pointer to the hook that holds that node. < get_set_node_algo<typename packed_options::void_pointer>
//! , member_tag
//! <b>Throws</b>: Nothing. , packed_options::link_mode
static this_type_ptr to_hook_ptr(node_ptr p) , detail::NoBaseHook
{ > implementation_defined;
return this_type_ptr(static_cast<set_base_hook*> (detail::get_pointer(p))); /// @endcond
} typedef implementation_defined type;
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into
//! a const pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p)
{
return const_this_type_ptr(static_cast<const set_base_hook*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Returns a pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
node_ptr to_node_ptr()
{ return this_as_node(); }
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
const_node_ptr to_node_ptr() const
{ return this_as_node(); }
}; };
//! Put a public data member set_member_hook in order to store objects of this class in //! 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 //! The second argument is the pointer type that will be used internally in the hook
//! and the set/multiset configured from this hook. //! and the set/multiset configured from this hook.
template< linking_policy Policy //= safe_link #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
, class VoidPointer //= void * template<class ...Options>
> #else
template<class O1, class O2, class O3>
#endif
class set_member_hook class set_member_hook
: private detail::rbtree_node_traits<VoidPointer>::node : public make_set_member_hook<O1, O2, O3>::type
{ {
public: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
typedef detail::rbtree_node_traits<VoidPointer> node_traits; //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
enum { linking_policy = Policy };
/// @cond
private:
typedef rbtree_algorithms<node_traits> node_algorithms;
/// @endcond
public:
typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef set_member_hook
<Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type >::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type >::type const_this_type_ptr;
/// @cond
private:
node_ptr this_as_node()
{ return node_ptr(static_cast<node *const>(this)); }
const_node_ptr this_as_node() const
{ return const_node_ptr(static_cast<const node *const>(this)); }
/// @endcond
public:
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. //! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
set_member_hook() set_member_hook();
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing a copy-constructor //! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using set_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. //! user to do some additional work. \c swap can be used to emulate
set_member_hook(const set_member_hook& ) //! move-semantics.
: node() set_member_hook(const set_member_hook& );
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: Empty function. The argument is ignored. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing an assignment operator //! <b>Rationale</b>: Providing an assignment operator
//! makes classes using set_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. //! user to do some additional work. \c swap can be used to emulate
set_member_hook& operator=(const set_member_hook& ) //! move-semantics.
{ return *this; } set_member_hook& operator=(const set_member_hook& );
//! <b>Effects</b>: If Policy is normal_link, the destructor does //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the //! 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 Policy is //! object is stored in an set an assertion is raised. If link_mode is
//! auto_unlink and "is_linked()" is true, the node is unlinked. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
~set_member_hook() ~set_member_hook();
{ detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink. //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
bool is_linked() const //!
{ //! <b>Throws</b>: Nothing.
//is_linked() can be only used in safe-mode or auto-unlink void swap_nodes(set_member_hook &other);
BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
return !node_algorithms::unique(this_as_node()); //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
} //!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c set::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container. //! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if Policy is auto_unlink. //! This function is only allowed if link_mode is \c auto_unlink.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void unlink() void unlink();
{ #endif
BOOST_STATIC_ASSERT((Policy == auto_unlink));
node_algorithms::unlink_and_rebalance(this_as_node());
node_algorithms::init(this_as_node());
}
//! The value_traits class is used as the first template argument for multiset.
//! The template argument is a pointer to member pointing to the node in
//! the class. Objects of type T and of types derived from T can be stored.
//! T don't need to be copy-constructible or assignable.
template<class T, this_type T::* P>
struct value_traits
: detail::member_hook_value_traits<T, this_type, P>
{};
//! <b>Effects</b>: Converts a pointer to a node into
//! a pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static this_type_ptr to_hook_ptr(node_ptr p)
{
return this_type_ptr(static_cast<this_type*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into
//! a const pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p)
{
return const_this_type_ptr(static_cast<const this_type*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Returns a pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
node_ptr to_node_ptr()
{ return this_as_node(); }
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
const_node_ptr to_node_ptr() const
{ return this_as_node(); }
}; };
} //namespace intrusive } //namespace intrusive

View File

@@ -16,21 +16,60 @@
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING #include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#endif
#include <boost/intrusive/detail/assert.hpp> #include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/intrusive_fwd.hpp> #include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/slist_hook.hpp> #include <boost/intrusive/slist_hook.hpp>
#include <boost/intrusive/circular_slist_algorithms.hpp> #include <boost/intrusive/circular_slist_algorithms.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp> #include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/options.hpp>
#include <functional> #include <functional>
#include <cstddef> #include <cstddef>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
/// @cond
template <class T>
struct internal_default_slist_hook
{
template <class U> static detail::one test(...);
template <class U> static detail::two test(typename U::default_slist_hook* = 0);
static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
};
template <class T>
struct get_default_slist_hook
{ typedef typename T::default_slist_hook type; };
template <class ValueTraits, class SizeType, bool ConstantTimeSize>
struct slistopt
{
typedef ValueTraits value_traits;
typedef SizeType size_type;
static const bool constant_time_size = ConstantTimeSize;
};
template <class T>
struct slist_defaults
: pack_options
< none
, base_hook
< typename detail::eval_if_c
< internal_default_slist_hook<T>::value
, get_default_slist_hook<T>
, detail::identity<none>
>::type
>
, constant_time_size<true>
, size_type<std::size_t>
>::type
{};
/// @endcond
//! The class template slist is an intrusive container, that encapsulates //! 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 //! a singly-linked list. You can use such a list to squeeze the last bit
//! of performance from your application. Unfortunately, the little gains //! 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 //! this limitation some other member functions with rather unusual semantics
//! have to be introduced. //! have to be introduced.
//! //!
//! The template parameter ValueTraits is called "value traits". It stores //! The template parameter \c T is the type to be managed by the container.
//! information and operations about the type to be stored in 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 //! The container supports the following options:
//! will be embedded in the class, that will keep track of the number of stored objects. //! \c base_hook<>/member_hook<>/value_traits<>,
//! This will allow constant-time O(1) size() member, instead of default O(N) size. //! \c constant_time_size<> and \c size_type<>.
//! //!
//! The iterators of slist are forward iterators. slist provides a static //! The iterators of slist are forward iterators. slist provides a static
//! function called "previous" to compute the previous iterator of a given iterator. //! 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 //! 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 //! iterator' means 'at the beginning of the list'. To improve the self-documentation
//! a "before_begin()" function is defined, returning the end() iterator. //! a "before_begin()" function is defined, returning the end() iterator.
template < class ValueTraits #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
, bool ConstantTimeSize //= true template<class T, class ...Options>
, class SizeType //= std::size_t #else
> template<class Config>
class slist #endif
: private detail::size_holder<ConstantTimeSize, SizeType> class slist_impl
{ {
/// @cond
private:
typename ValueTraits::node_traits::node root_;
typedef slist<ValueTraits, ConstantTimeSize, SizeType> this_type;
typedef typename ValueTraits::node_traits node_traits;
typedef detail::size_holder<ConstantTimeSize, SizeType> size_traits;
//! This class is
//! non-copyable
slist (const slist&);
//! This class is
//! non-asignable
slist &operator =(const slist&);
/// @endcond
//Public typedefs //Public typedefs
public: public:
typedef ValueTraits value_traits; typedef typename Config::value_traits value_traits;
typedef typename ValueTraits::value_type value_type; /// @cond
typedef typename ValueTraits::pointer pointer; static const bool external_value_traits =
typedef typename ValueTraits::const_pointer const_pointer; detail::external_value_traits_is_true<value_traits>::value;
typedef typename detail::eval_if_c
< external_value_traits
, detail::eval_value_traits<value_traits>
, detail::identity<value_traits>
>::type real_value_traits;
/// @endcond
typedef typename real_value_traits::pointer pointer;
typedef typename real_value_traits::const_pointer const_pointer;
typedef typename std::iterator_traits<pointer>::value_type value_type;
typedef typename std::iterator_traits<pointer>::reference reference; typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference; typedef typename std::iterator_traits<const_pointer>::reference const_reference;
typedef typename std::iterator_traits<pointer>::difference_type difference_type; typedef typename std::iterator_traits<pointer>::difference_type difference_type;
typedef SizeType size_type; typedef typename Config::size_type size_type;
typedef detail::slist_iterator<value_type, ValueTraits> iterator; typedef slist_iterator<slist_impl, false> iterator;
typedef detail::slist_iterator<const value_type, ValueTraits> const_iterator; typedef slist_iterator<slist_impl, true> const_iterator;
typedef typename real_value_traits::node_traits node_traits;
/// @cond
private:
typedef typename node_traits::node node; typedef typename node_traits::node node;
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
<pointer, node>::type node_ptr; <pointer, node>::type node_ptr;
typedef typename boost::pointer_to_other typedef typename boost::pointer_to_other
<pointer, const node>::type const_node_ptr; <pointer, const node>::type const_node_ptr;
typedef circular_slist_algorithms<node_traits> node_algorithms; typedef circular_slist_algorithms<node_traits> node_algorithms;
static const bool constant_time_size = Config::constant_time_size;
static const bool stateful_value_traits = detail::store_cont_ptr_on_it<slist_impl>::value;
/// @cond
private:
typedef detail::size_holder<constant_time_size, size_type> 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 = enum { safemode_or_autounlink =
(int)ValueTraits::linking_policy == (int)auto_unlink || (int)real_value_traits::link_mode == (int)auto_unlink ||
(int)ValueTraits::linking_policy == (int)safe_link }; (int)real_value_traits::link_mode == (int)safe_link };
//Constant-time size is incompatible with auto-unlink hooks! //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() node_ptr get_root_node()
{ return node_ptr(&root_); } { return node_ptr(&data_.root_plus_size_.root_); }
const_node_ptr get_root_node() const 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) static node_ptr uncast(const_node_ptr ptr)
{ {
return node_ptr(const_cast<node*>(detail::get_pointer(ptr))); return node_ptr(const_cast<node*>(detail::get_pointer(ptr)));
} }
static iterator previous_node(iterator beg, iterator i) struct root_plus_size
: public size_traits
{ {
return iterator node root_;
(node_algorithms::get_previous_node(beg.pointed_node(), i.pointed_node())); };
}
static const_iterator previous_node(const_iterator beg, const_iterator i) struct data_t
: public slist_impl::value_traits
{ {
return const_iterator typedef typename slist_impl::value_traits value_traits;
(node_algorithms::get_previous_node(beg.pointed_node(), i.pointed_node())); data_t(const value_traits &val_traits)
} : value_traits(val_traits)
{}
root_plus_size root_plus_size_;
} data_;
size_traits &priv_size_traits()
{ return data_.root_plus_size_; }
const size_traits &priv_size_traits() const
{ return data_.root_plus_size_; }
const real_value_traits &get_real_value_traits(detail::bool_<false>) const
{ return data_; }
const real_value_traits &get_real_value_traits(detail::bool_<true>) const
{ return data_.get_value_traits(*this); }
real_value_traits &get_real_value_traits(detail::bool_<false>)
{ return data_; }
real_value_traits &get_real_value_traits(detail::bool_<true>)
{ return data_.get_value_traits(*this); }
/// @endcond /// @endcond
public:
const real_value_traits &get_real_value_traits() const
{ return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
real_value_traits &get_real_value_traits()
{ return this->get_real_value_traits(detail::bool_<external_value_traits>()); }
public: public:
//! <b>Effects</b>: constructs an empty list. //! <b>Effects</b>: constructs an empty list.
//! //!
@@ -136,9 +214,10 @@ class slist
//! //!
//! <b>Throws</b>: If value_traits::node_traits::node //! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks). //! 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()); node_algorithms::init(this->get_root_node());
} }
@@ -151,9 +230,10 @@ class slist
//! <b>Throws</b>: If value_traits::node_traits::node //! <b>Throws</b>: If value_traits::node_traits::node
//! constructor throws (this does not happen with predefined Boost.Intrusive hooks). //! constructor throws (this does not happen with predefined Boost.Intrusive hooks).
template<class Iterator> template<class Iterator>
slist(Iterator b, Iterator e) slist_impl(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
: data_(v_traits)
{ {
size_traits::set_size(size_type(0)); this->priv_size_traits().set_size(size_type(0));
node_algorithms::init(this->get_root_node()); node_algorithms::init(this->get_root_node());
insert_after(before_begin(), b, e); insert_after(before_begin(), b, e);
} }
@@ -162,12 +242,12 @@ class slist
//! or auto-unlink value, the destructor does nothing //! or auto-unlink value, the destructor does nothing
//! (ie. no code is generated). Otherwise it detaches all elements from this. //! (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 //! 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. //! are set to their default value.
//! //!
//! <b>Complexity</b>: Linear to the number of elements in the list, if //! <b>Complexity</b>: Linear to the number of elements in the list, if
//! it's a safe-mode or auto-unlink value. Otherwise constant. //! it's a safe-mode or auto-unlink value. Otherwise constant.
~slist() ~slist_impl()
{ this->clear(); } { this->clear(); }
//! <b>Effects</b>: Erases all the elements of the container. //! <b>Effects</b>: Erases all the elements of the container.
@@ -185,7 +265,7 @@ class slist
} }
else{ else{
node_algorithms::init(this->get_root_node()); 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
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
void push_front(reference value) 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) if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert));
node_algorithms::link_after(this->get_root_node(), to_insert); node_algorithms::link_after(this->get_root_node(), to_insert);
size_traits::increment(); this->priv_size_traits().increment();
} }
//! <b>Effects</b>: Erases the first element of the list. //! <b>Effects</b>: 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_ptr to_erase = node_traits::get_next(this->get_root_node());
node_algorithms::unlink_after(this->get_root_node()); node_algorithms::unlink_after(this->get_root_node());
size_traits::decrement(); this->priv_size_traits().decrement();
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
} }
@@ -254,7 +334,7 @@ class slist
{ {
node_ptr to_erase = node_traits::get_next(this->get_root_node()); node_ptr to_erase = node_traits::get_next(this->get_root_node());
this->pop_front(); this->pop_front();
disposer(ValueTraits::to_value_ptr(to_erase)); disposer(get_real_value_traits().to_value_ptr(to_erase));
} }
//! <b>Effects</b>: Returns a reference to the first element of the list. //! <b>Effects</b>: Returns a reference to the first element of the list.
@@ -263,7 +343,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
reference front() reference front()
{ return *ValueTraits::to_value_ptr(node_traits::get_next(this->get_root_node())); } { return *get_real_value_traits().to_value_ptr(node_traits::get_next(this->get_root_node())); }
//! <b>Effects</b>: Returns a const_reference to the first element of the list. //! <b>Effects</b>: Returns a const_reference to the first element of the list.
//! //!
@@ -271,7 +351,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_reference front() const const_reference front() const
{ return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); } { return *get_real_value_traits().to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); }
//! <b>Effects</b>: Returns an iterator to the first element contained in the list. //! <b>Effects</b>: Returns an iterator to the first element contained in the list.
//! //!
@@ -279,7 +359,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
iterator begin() iterator begin()
{ return iterator (node_traits::get_next(this->get_root_node())); } { return iterator (node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the list. //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
//! //!
@@ -287,7 +367,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_iterator begin() const const_iterator begin() const
{ return const_iterator (node_traits::get_next(this->get_root_node())); } { return const_iterator (node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the list. //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
//! //!
@@ -295,7 +375,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_iterator cbegin() const const_iterator cbegin() const
{ return const_iterator (node_traits::get_next(this->get_root_node())); } { return const_iterator (node_traits::get_next(this->get_root_node()), this); }
//! <b>Effects</b>: Returns an iterator to the end of the list. //! <b>Effects</b>: Returns an iterator to the end of the list.
//! //!
@@ -303,7 +383,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
iterator end() iterator end()
{ return iterator (this->get_root_node()); } { return iterator (this->get_root_node(), this); }
//! <b>Effects</b>: Returns a const_iterator to the end of the list. //! <b>Effects</b>: Returns a const_iterator to the end of the list.
//! //!
@@ -311,7 +391,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_iterator end() const const_iterator end() const
{ return const_iterator (uncast(this->get_root_node())); } { return const_iterator (uncast(this->get_root_node()), this); }
//! <b>Effects</b>: Returns a const_iterator to the end of the list. //! <b>Effects</b>: Returns a const_iterator to the end of the list.
//! //!
@@ -319,7 +399,7 @@ class slist
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
const_iterator cend() const const_iterator cend() const
{ return const_iterator (uncast(this->get_root_node())); } { return const_iterator (uncast(this->get_root_node()), this); }
//! <b>Effects</b>: Returns an iterator that points to a position //! <b>Effects</b>: Returns an iterator that points to a position
//! before the first element. Equivalent to "end()" //! before the first element. Equivalent to "end()"
@@ -356,11 +436,8 @@ class slist
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
static slist &container_from_end_iterator(iterator end_iterator) static slist_impl &container_from_end_iterator(iterator end_iterator)
{ { return priv_container_from_end_iterator(end_iterator); }
return *detail::parent_from_member<slist, node>
( detail::get_pointer(end_iterator.pointed_node()), &slist::root_);
}
//! <b>Precondition</b>: end_iterator must be a valid end const_iterator //! <b>Precondition</b>: end_iterator must be a valid end const_iterator
//! of slist. //! of slist.
@@ -370,24 +447,21 @@ class slist
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Constant. //! <b>Complexity</b>: Constant.
static const slist &container_from_end_iterator(const_iterator end_iterator) static const slist_impl &container_from_end_iterator(const_iterator end_iterator)
{ { return priv_container_from_end_iterator(end_iterator); }
return *detail::parent_from_member<slist, node>
( detail::get_pointer(end_iterator.pointed_node()), &slist::root_);
}
//! <b>Effects</b>: Returns the number of the elements contained in the list. //! <b>Effects</b>: Returns the number of the elements contained in the list.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Linear to the number of elements contained in the list. //! <b>Complexity</b>: Linear to the number of elements contained in the list.
//! if ConstantTimeSize is false. Constant time otherwise. //! if constant_time_size is false. Constant time otherwise.
//! //!
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
size_type size() const size_type size() const
{ {
if(ConstantTimeSize) if(constant_time_size)
return size_traits::get_size(); return this->priv_size_traits().get_size();
else else
return node_algorithms::count(this->get_root_node()) - 1; return node_algorithms::count(this->get_root_node()) - 1;
} }
@@ -409,13 +483,13 @@ class slist
//! <b>Complexity</b>: Linear to the number of elements of both lists. //! <b>Complexity</b>: Linear to the number of elements of both lists.
//! //!
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
void swap(slist& other) void swap(slist_impl& other)
{ {
node_algorithms::swap_nodes(this->get_root_node(), other.get_root_node()); node_algorithms::swap_nodes(this->get_root_node(), other.get_root_node());
if(ConstantTimeSize){ if(constant_time_size){
size_type backup = size_traits::get_size(); size_type backup = this->priv_size_traits().get_size();
size_traits::set_size(other.get_size()); this->priv_size_traits().set_size(other.priv_size_traits().get_size());
other.set_size(backup); other.priv_size_traits().set_size(backup);
} }
} }
@@ -533,25 +607,21 @@ class slist
//! //!
//! <b>Throws</b>: If cloner throws. //! <b>Throws</b>: If cloner throws.
template <class Cloner, class Disposer> template <class Cloner, class Disposer>
void clone_from(const slist &src, Cloner cloner, Disposer disposer) void clone_from(const slist_impl &src, Cloner cloner, Disposer disposer)
{ {
this->clear_and_dispose(disposer); this->clear_and_dispose(disposer);
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING BOOST_INTRUSIVE_TRY{
BOOST_TRY{
#endif
iterator prev = this->before_begin(); iterator prev = this->before_begin();
const_iterator b(src.begin()), e(src.end()); const_iterator b(src.begin()), e(src.end());
for(; b != e; ++b, ++prev){ for(; b != e; ++b, ++prev){
this->insert_after(prev, *cloner(*b)); this->insert_after(prev, *cloner(*b));
} }
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
} }
BOOST_CATCH(...){ BOOST_INTRUSIVE_CATCH(...){
this->clear_and_dispose(disposer); this->clear_and_dispose(disposer);
BOOST_RETHROW; BOOST_RETHROW;
} }
BOOST_CATCH_END BOOST_INTRUSIVE_CATCH_END
#endif
} }
//! <b>Requires</b>: value must be an lvalue and prev_p must point to an element //! <b>Requires</b>: value must be an lvalue and prev_p must point to an element
@@ -569,12 +639,12 @@ class slist
//! <b>Note</b>: Does not affect the validity of iterators and references. //! <b>Note</b>: Does not affect the validity of iterators and references.
iterator insert_after(iterator prev_p, reference value) 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) if(safemode_or_autounlink)
BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n)); BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n));
node_algorithms::link_after(prev_p.pointed_node(), n); node_algorithms::link_after(prev_p.pointed_node(), n);
size_traits::increment(); this->priv_size_traits().increment();
return iterator (n); return iterator (n, this);
} }
//! <b>Requires</b>: Dereferencing iterator must yield //! <b>Requires</b>: Dereferencing iterator must yield
@@ -644,7 +714,7 @@ class slist
iterator it(prev); ++it; iterator it(prev); ++it;
node_ptr to_erase(it.pointed_node()); node_ptr to_erase(it.pointed_node());
node_algorithms::unlink_after(prev.pointed_node()); node_algorithms::unlink_after(prev.pointed_node());
size_traits::decrement(); this->priv_size_traits().decrement();
iterator ret(++prev); iterator ret(++prev);
if(safemode_or_autounlink) if(safemode_or_autounlink)
node_algorithms::init(to_erase); node_algorithms::init(to_erase);
@@ -725,7 +795,7 @@ class slist
iterator it(prev); ++it; iterator it(prev); ++it;
node_ptr to_erase(it.pointed_node()); node_ptr to_erase(it.pointed_node());
iterator ret(this->erase_after(prev)); 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; return ret;
} }
@@ -853,7 +923,7 @@ class slist
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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()){ if (!x.empty()){
iterator last_x(x.previous(x.end())); iterator last_x(x.previous(x.end()));
@@ -861,8 +931,8 @@ class slist
( prev.pointed_node() ( prev.pointed_node()
, x.end().pointed_node() , x.end().pointed_node()
, last_x.pointed_node()); , last_x.pointed_node());
size_traits::set_size(size_traits::get_size() + x.get_size()); this->priv_size_traits().set_size(this->priv_size_traits().get_size() + x.priv_size_traits().get_size());
x.set_size(size_type(0)); x.priv_size_traits().set_size(size_type(0));
return last_x; return last_x;
} }
else{ else{
@@ -883,15 +953,15 @@ class slist
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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; iterator nxt = prev_ele;
++nxt; ++nxt;
if (nxt != prev && prev_ele != prev){ if (nxt != prev && prev_ele != prev){
node_algorithms::transfer_after node_algorithms::transfer_after
(prev.pointed_node(), prev_ele.pointed_node(), nxt.pointed_node()); (prev.pointed_node(), prev_ele.pointed_node(), nxt.pointed_node());
size_traits::increment(); this->priv_size_traits().increment();
x.decrement(); x.priv_size_traits().decrement();
} }
} }
@@ -906,19 +976,19 @@ class slist
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Linear to the number of elements transferred //! <b>Complexity</b>: Linear to the number of elements transferred
//! if ConstantTimeSize is true. Constant-time otherwise. //! if constant_time_size is true. Constant-time otherwise.
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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 (before_first != before_last){
if(ConstantTimeSize){ if(constant_time_size){
size_type increment = std::distance(before_first, before_last); size_type increment = std::distance(before_first, before_last);
node_algorithms::transfer_after node_algorithms::transfer_after
(prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node());
size_traits::set_size(size_traits::get_size() + increment); this->priv_size_traits().set_size(this->priv_size_traits().get_size() + increment);
x.set_size(x.get_size() - increment); x.priv_size_traits().set_size(x.priv_size_traits().get_size() - increment);
} }
else{ else{
node_algorithms::transfer_after node_algorithms::transfer_after
@@ -941,15 +1011,15 @@ class slist
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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(n){
if(ConstantTimeSize){ if(constant_time_size){
BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(before_first, before_last) == n); BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(before_first, before_last) == n);
node_algorithms::transfer_after node_algorithms::transfer_after
(prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node());
size_traits::set_size(size_traits::get_size() + n); this->priv_size_traits().set_size(this->priv_size_traits().get_size() + n);
x.set_size(x.get_size() - n); x.priv_size_traits().set_size(x.priv_size_traits().get_size() - n);
} }
else{ else{
node_algorithms::transfer_after node_algorithms::transfer_after
@@ -975,7 +1045,7 @@ class slist
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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); } { return splice_after(this->previous(it), x); }
//! <b>Requires</b>: it p must be a valid iterator of *this. //! <b>Requires</b>: it p must be a valid iterator of *this.
@@ -991,7 +1061,7 @@ class slist
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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)); } { return splice_after(this->previous(pos), x, this->previous(elem)); }
//! <b>Requires</b>: pos must be a dereferenceable iterator in *this //! <b>Requires</b>: pos must be a dereferenceable iterator in *this
@@ -1004,11 +1074,11 @@ class slist
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Complexity</b>: Linear to the sum of elements before pos, first, and last. //! <b>Complexity</b>: Linear to the sum of elements before pos, first, and last.
//! Plus linear to the number of elements transferred if ConstantTimeSize is true. //! Plus linear to the number of elements transferred if constant_time_size is true.
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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)); } { return splice_after(this->previous(pos), x, this->previous(first), this->previous(last)); }
//! <b>Requires</b>: pos must be a dereferenceable iterator in *this //! <b>Requires</b>: pos must be a dereferenceable iterator in *this
@@ -1025,7 +1095,7 @@ class slist
//! //!
//! <b>Note</b>: Iterators of values obtained from list x now point to elements of this //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
//! list. Iterators of this list and all the references are not invalidated. //! 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); } { return splice_after(this->previous(pos), x, this->previous(first), this->previous(last), n); }
//! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>. //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
@@ -1044,8 +1114,8 @@ class slist
{ {
if (node_traits::get_next(node_traits::get_next(this->get_root_node())) if (node_traits::get_next(node_traits::get_next(this->get_root_node()))
!= this->get_root_node()) { != this->get_root_node()) {
slist carry; slist_impl carry;
slist counter[64]; slist_impl counter[64];
int fill = 0; int fill = 0;
iterator last_inserted; iterator last_inserted;
while(!this->empty()){ while(!this->empty()){
@@ -1057,8 +1127,10 @@ class slist
} }
BOOST_INTRUSIVE_INVARIANT_ASSERT(counter[i].empty()); BOOST_INTRUSIVE_INVARIANT_ASSERT(counter[i].empty());
iterator last_element(previous_node(last_inserted, carry.end())); node_ptr p = node_algorithms::get_previous_node
if(ConstantTimeSize){ (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 counter[i].splice_after( counter[i].end(), carry
, carry.before_begin(), last_element , carry.before_begin(), last_element
, carry.size()); , carry.size());
@@ -1067,19 +1139,18 @@ class slist
counter[i].splice_after( counter[i].end(), carry counter[i].splice_after( counter[i].end(), carry
, carry.before_begin(), last_element); , 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) if(i == fill)
++fill; ++fill;
} }
for (int i = 1; i < fill; ++i) for (int i = 1; i < fill; ++i)
last_inserted = counter[i].merge(counter[i-1], p); last_inserted = counter[i].merge(counter[i-1], p);
//this->swap(counter[fill-1]);
BOOST_INTRUSIVE_INVARIANT_ASSERT(this->empty()); BOOST_INTRUSIVE_INVARIANT_ASSERT(this->empty());
iterator last_element(previous_node(last_inserted, counter[--fill].end())); node_ptr p = node_algorithms::get_previous_node
if(ConstantTimeSize){ (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() this->splice_after( end(), counter[fill], counter[fill].before_begin()
, last_element, counter[fill].size()); , last_element, counter[fill].size());
} }
@@ -1126,7 +1197,7 @@ class slist
//! //!
//! <b>Note</b>: Iterators and references are not invalidated. //! <b>Note</b>: Iterators and references are not invalidated.
template<class Predicate> template<class Predicate>
iterator merge(slist& x, Predicate p) iterator merge(slist_impl& x, Predicate p)
{ {
iterator a(before_begin()), e(end()), ax(x.before_begin()); iterator a(before_begin()), e(end()), ax(x.before_begin());
iterator last_inserted(e); iterator last_inserted(e);
@@ -1161,7 +1232,7 @@ class slist
//! size() + x.size() - 1 comparisons. //! size() + x.size() - 1 comparisons.
//! //!
//! <b>Note</b>: Iterators and references are not invalidated //! <b>Note</b>: Iterators and references are not invalidated
void merge(slist& x) void merge(slist_impl& x)
{ this->merge(x, std::less<value_type>()); } { this->merge(x, std::less<value_type>()); }
//! <b>Effects</b>: Reverses the order of elements in the list. //! <b>Effects</b>: Reverses the order of elements in the list.
@@ -1328,10 +1399,13 @@ class slist
//! <b>Complexity</b>: Constant time. //! <b>Complexity</b>: Constant time.
//! //!
//! <b>Note</b>: Iterators and references are not invalidated. //! <b>Note</b>: Iterators and references are not invalidated.
static iterator iterator_to(reference value) //! This static function is available only if the <i>value traits</i>
//! is stateless.
static iterator s_iterator_to(reference value)
{ {
BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(value))); BOOST_STATIC_ASSERT((!stateful_value_traits));
return iterator (ValueTraits::to_node_ptr(value)); BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(value)));
return iterator (value_traits::to_node_ptr(value), 0);
} }
//! <b>Requires</b>: value must be a const reference to a value inserted in a list. //! <b>Requires</b>: value must be a const reference to a value inserted in a list.
@@ -1343,10 +1417,43 @@ class slist
//! <b>Complexity</b>: Constant time. //! <b>Complexity</b>: Constant time.
//! //!
//! <b>Note</b>: Iterators and references are not invalidated. //! <b>Note</b>: Iterators and references are not invalidated.
static const_iterator iterator_to(const_reference value) //! This static function is available only if the <i>value traits</i>
//! is stateless.
static const_iterator s_iterator_to(const_reference value)
{ {
BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast<reference> (value)))); BOOST_STATIC_ASSERT((!stateful_value_traits));
return const_iterator (ValueTraits::to_node_ptr(const_cast<reference> (value))); BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(const_cast<reference> (value))));
return const_iterator (value_traits::to_node_ptr(const_cast<reference> (value)), 0);
}
//! <b>Requires</b>: value must be a reference to a value inserted in a list.
//!
//! <b>Effects</b>: This function returns a const_iterator pointing to the element
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
iterator iterator_to(reference value)
{
BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(value)));
return iterator (value_traits::to_node_ptr(value), this);
}
//! <b>Requires</b>: value must be a const reference to a value inserted in a list.
//!
//! <b>Effects</b>: This function returns an iterator pointing to the element.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Constant time.
//!
//! <b>Note</b>: Iterators and references are not invalidated.
const_iterator iterator_to(const_reference value) const
{
BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(const_cast<reference> (value))));
return const_iterator (value_traits::to_node_ptr(const_cast<reference> (value)), this);
} }
//! <b>Returns</b>: The iterator to the element before i in the list. //! <b>Returns</b>: The iterator to the element before i in the list.
@@ -1360,7 +1467,7 @@ class slist
{ {
return iterator return iterator
(node_algorithms::get_previous_node (node_algorithms::get_previous_node
(before_begin().pointed_node(), i.pointed_node())); (before_begin().pointed_node(), i.pointed_node()), 0);
} }
//! <b>Returns</b>: The const_iterator to the element before i in the list. //! <b>Returns</b>: The const_iterator to the element before i in the list.
@@ -1374,17 +1481,52 @@ class slist
{ {
return const_iterator return const_iterator
(node_algorithms::get_previous_node (node_algorithms::get_previous_node
(before_begin().pointed_node(), i.pointed_node())); (before_begin().pointed_node(), i.pointed_node()), 0);
}
private:
static slist_impl &priv_container_from_end_iterator(const const_iterator &end_iterator)
{
root_plus_size *r = detail::parent_from_member<root_plus_size, node>
( detail::get_pointer(end_iterator.pointed_node()), &root_plus_size::root_);
data_t *d = detail::parent_from_member<data_t, root_plus_size>
( r, &data_t::root_plus_size_);
slist_impl *s = detail::parent_from_member<slist_impl, data_t>(d, &slist_impl::data_);
return *s;
} }
}; };
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator==(const slist<V, C, S>& x, const slist<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator<
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
#else
(const slist_impl<Config> &x, const slist_impl<Config> &y)
#endif
{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class ...Options>
#else
template<class Config>
#endif
bool operator==
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
#else
(const slist_impl<Config> &x, const slist_impl<Config> &y)
#endif
{ {
typedef slist_impl<Config> slist_type;
typedef typename slist_type::const_iterator const_iterator;
const bool C = slist_type::constant_time_size;
if(C && x.size() != y.size()){ if(C && x.size() != y.size()){
return false; return false;
} }
typedef typename slist<V, C, S>::const_iterator const_iterator;
const_iterator end1 = x.end(); const_iterator end1 = x.end();
const_iterator i1 = x.begin(); const_iterator i1 = x.begin();
@@ -1406,31 +1548,131 @@ inline bool operator==(const slist<V, C, S>& x, const slist<V, C, S>& y)
} }
} }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator<(const slist<V, C, S>& x, template<class T, class ...Options>
const slist<V, C, S>& y) #else
{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } template<class Config>
#endif
template <class V, bool C, class S> inline bool operator!=
inline bool operator!=(const slist<V, C, S>& x, const slist<V, C, S>& y) #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
#else
(const slist_impl<Config> &x, const slist_impl<Config> &y)
#endif
{ return !(x == y); } { return !(x == y); }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator>(const slist<V, C, S>& x, const slist<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator>
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
#else
(const slist_impl<Config> &x, const slist_impl<Config> &y)
#endif
{ return y < x; } { return y < x; }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator<=(const slist<V, C, S>& x, const slist<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator<=
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
#else
(const slist_impl<Config> &x, const slist_impl<Config> &y)
#endif
{ return !(y < x); } { return !(y < x); }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline bool operator>=(const slist<V, C, S>& x, const slist<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline bool operator>=
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(const slist_impl<T, Options...> &x, const slist_impl<T, Options...> &y)
#else
(const slist_impl<Config> &x, const slist_impl<Config> &y)
#endif
{ return !(x < y); } { return !(x < y); }
template <class V, bool C, class S> #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
inline void swap(slist<V, C, S>& x, slist<V, C, S>& y) template<class T, class ...Options>
#else
template<class Config>
#endif
inline void swap
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
(slist_impl<T, Options...> &x, slist_impl<T, Options...> &y)
#else
(slist_impl<Config> &x, slist_impl<Config> &y)
#endif
{ x.swap(y); } { x.swap(y); }
//! Helper metafunction to define a \c slist that yields to the same type when the
//! same options (either explicitly or implicitly) are used.
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class ...Options>
#else
template<class T, class O1 = none, class O2 = none, class O3 = none>
#endif
struct make_slist
{
/// @cond
typedef typename pack_options
< slist_defaults<T>, O1, O2, O3>::type packed_options;
typedef typename detail::get_value_traits
<T, typename packed_options::value_traits>::type value_traits;
typedef slist_impl
<
slistopt
< value_traits
, typename packed_options::size_type
, packed_options::constant_time_size
>
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class T, class O1, class O2, class O3>
class slist
: public make_slist<T, O1, O2, O3>::type
{
typedef typename make_slist
<T, O1, O2, O3>::type Base;
typedef typename Base::real_value_traits real_value_traits;
//Assert if passed value traits are compatible with the type
BOOST_STATIC_ASSERT((detail::is_same<typename real_value_traits::value_type, T>::value));
public:
typedef typename Base::value_traits value_traits;
typedef typename Base::iterator iterator;
typedef typename Base::const_iterator const_iterator;
slist(const value_traits &v_traits = value_traits())
: Base(v_traits)
{}
template<class Iterator>
slist(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
: Base(b, e, v_traits)
{}
static slist &container_from_end_iterator(iterator end_iterator)
{ return static_cast<slist &>(Base::container_from_end_iterator(end_iterator)); }
static const slist &container_from_end_iterator(const_iterator end_iterator)
{ return static_cast<const slist &>(Base::container_from_end_iterator(end_iterator)); }
};
#endif
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost

View File

@@ -17,19 +17,48 @@
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp> #include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/utilities.hpp> #include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/detail/slist_node.hpp> #include <boost/intrusive/detail/slist_node.hpp>
#include <boost/intrusive/circular_slist_algorithms.hpp> #include <boost/intrusive/circular_slist_algorithms.hpp>
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/options.hpp>
#include <boost/intrusive/tag.hpp> #include <boost/intrusive/detail/generic_hook.hpp>
#include <boost/static_assert.hpp>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
/// @cond
template<class VoidPointer>
struct get_slist_node_algo
{
typedef circular_slist_algorithms<slist_node_traits<VoidPointer> > type;
};
/// @endcond
//! Helper metafunction to define a \c slist_base_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class ...Options>
#else
template<class O1 = none, class O2 = none, class O3 = none>
#endif
struct make_slist_base_hook
{
/// @cond
typedef typename pack_options
< hook_defaults, O1, O2, O3>::type packed_options;
typedef detail::generic_hook
< get_slist_node_algo<typename packed_options::void_pointer>
, typename packed_options::tag
, packed_options::link_mode
, detail::SlistBaseHook
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Derive a class from slist_base_hook in order to store objects in //! 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 //! in an list. slist_base_hook holds the data necessary to maintain the
//! list and provides an appropriate value_traits class for slist. //! list and provides an appropriate value_traits class for list.
//! //!
//! The first integer template argument defines a tag to identify the node. //! 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 //! 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 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 //! The third argument is the pointer type that will be used internally in the hook
//! and the slist configured from this hook. //! and the list configured from this hook.
template< class Tag //= tag #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
, linking_policy Policy //= safe_link template<class ...Options>
, class VoidPointer //= void * #else
> template<class O1, class O2, class O3>
#endif
class slist_base_hook class slist_base_hook
: private detail::slist_node_traits<VoidPointer>::node : public make_slist_base_hook<O1, O2, O3>::type
{ {
public: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
typedef detail::slist_node_traits<VoidPointer> node_traits; //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
enum { linking_policy = Policy };
/// @cond
private:
typedef circular_slist_algorithms<node_traits> node_algorithms;
/// @endcond
public:
typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef slist_base_hook
<Tag, Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type>::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type>::type const_this_type_ptr;
/// @cond
private:
node_ptr this_as_node()
{ return node_ptr(static_cast<node *const>(this)); }
const_node_ptr this_as_node() const
{ return const_node_ptr(static_cast<const node *const>(this)); }
/// @endcond
public:
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. //! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
slist_base_hook() slist_base_hook();
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing a copy-constructor //! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using slist_base_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
slist_base_hook(const slist_base_hook& ) slist_base_hook(const slist_base_hook& );
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: Empty function. The argument is ignored. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing an assignment operator //! <b>Rationale</b>: Providing an assignment operator
//! makes classes using slist_base_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
slist_base_hook& operator=(const slist_base_hook& ) slist_base_hook& operator=(const slist_base_hook& );
{ return *this; }
//! <b>Effects</b>: If Policy is normal_link, the destructor does //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the //! 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 Policy is //! object is stored in an slist an assertion is raised. If link_mode is
//! auto_unlink and "is_linked()" is true, the node is unlinked. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
~slist_base_hook() ~slist_base_hook();
{ detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node //! related to those nodes in one or two containers. That is, if the node
@@ -143,174 +125,99 @@ class slist_base_hook
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void swap_nodes(slist_base_hook &other) void swap_nodes(slist_base_hook &other);
{ node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink. //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//! //!
//! <b>Returns</b>: true, if the node belongs to a container, false //! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether list::iterator_to //! otherwise. This function can be used to test whether \c slist::iterator_to
//! will return a valid iterator. //! will return a valid iterator.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
bool is_linked() const bool is_linked() const;
{
//is_linked() can be only used in safe-mode or auto-unlink
BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
return !node_algorithms::unique(this_as_node());
}
//! <b>Effects</b>: Removes the node if it's inserted in a container. //! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if Policy is auto_unlink. //! This function is only allowed if link_mode is \c auto_unlink.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void unlink() void unlink();
{ #endif
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. //! Helper metafunction to define a \c slist_member_hook that yields to the same
//! The template argument T defines the class type stored in list. Objects //! type when the same options (either explicitly or implicitly) are used.
//! of type T and of types derived from T can be stored. T doesn't need to be #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! copy-constructible or assignable. template<class ...Options>
template<class T> #else
struct value_traits template<class O1 = none, class O2 = none, class O3 = none>
: detail::derivation_hook_value_traits<T, this_type, Tag> #endif
{}; struct make_slist_member_hook
{
/// @cond
typedef typename pack_options
< hook_defaults, O1, O2, O3>::type packed_options;
//! <b>Effects</b>: Converts a pointer to a node into typedef detail::generic_hook
//! a pointer to the hook that holds that node. < get_slist_node_algo<typename packed_options::void_pointer>
//! , member_tag
//! <b>Throws</b>: Nothing. , packed_options::link_mode
static this_type_ptr to_hook_ptr(node_ptr p) , detail::NoBaseHook
{ > implementation_defined;
return this_type_ptr(static_cast<slist_base_hook*> (detail::get_pointer(p))); /// @endcond
} typedef implementation_defined type;
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into
//! a const pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p)
{
return const_this_type_ptr(static_cast<const slist_base_hook*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Returns a pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
node_ptr to_node_ptr()
{ return this_as_node(); }
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
const_node_ptr to_node_ptr() const
{ return this_as_node(); }
}; };
//! Put a public data member slist_member_hook in order to store objects of this class in //! 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 //! an list. slist_member_hook holds the data necessary for maintaining the list and
//! provides an appropriate value_traits class for slist. //! provides an appropriate value_traits class for list.
//! //!
//! The template argument T defines the class type stored in slist. Objects of type //! The first boolean template parameter will specify the linking mode of the hook.
//! 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 second argument is the pointer type that will be used internally in the hook
//! //! and the list configured from this hook.
//! The third argument is the pointer type that will be used internally in the hook #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! and the slist configured from this hook. template<class ...Options>
template< linking_policy Policy //= safe_link #else
, class VoidPointer //= void * template<class O1, class O2, class O3>
> #endif
class slist_member_hook class slist_member_hook
: private detail::slist_node_traits<VoidPointer>::node : public make_slist_member_hook<O1, O2, O3>::type
{ {
public: #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
typedef detail::slist_node_traits<VoidPointer> node_traits; //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
enum { linking_policy = Policy };
/// @cond
private:
typedef circular_slist_algorithms<node_traits> node_algorithms;
/// @endcond
public:
typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef slist_member_hook
<Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type >::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type >::type const_this_type_ptr;
/// @cond
private:
node_ptr this_as_node()
{ return node_ptr(static_cast<node *const>(this)); }
const_node_ptr this_as_node() const
{ return const_node_ptr(static_cast<const node *const>(this)); }
/// @endcond
public:
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. //! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
slist_member_hook() slist_member_hook();
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing a copy-constructor //! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using slist_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
slist_member_hook(const slist_member_hook& ) slist_member_hook(const slist_member_hook& );
: node()
{
if(Policy == safe_link || Policy == auto_unlink){
node_algorithms::init(this_as_node());
}
}
//! <b>Effects</b>: Empty function. The argument is ignored. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing an assignment operator //! <b>Rationale</b>: Providing an assignment operator
//! makes classes using slist_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
slist_member_hook& operator=(const slist_member_hook& ) slist_member_hook& operator=(const slist_member_hook& );
{ return *this; }
//! <b>Effects</b>: If Policy is normal_link, the destructor does //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the //! 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 Policy is //! object is stored in an slist an assertion is raised. If link_mode is
//! auto_unlink and "is_linked()" is true, the node is unlinked. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
~slist_member_hook() ~slist_member_hook();
{ detail::destructor_impl(*this, detail::dispatcher<Policy>()); }
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node //! related to those nodes in one or two containers. That is, if the node
@@ -324,77 +231,28 @@ class slist_member_hook
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void swap_nodes(slist_member_hook& other) void swap_nodes(slist_member_hook &other);
{ node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); }
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink. //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//! //!
//! <b>Returns</b>: true, if the node belongs to a container, false //! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether list::iterator_to //! otherwise. This function can be used to test whether \c slist::iterator_to
//! will return a valid iterator. //! will return a valid iterator.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
bool is_linked() const bool is_linked() const;
{
//is_linked() can be only used in safe-mode or auto-unlink
BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink));
return !node_algorithms::unique(this_as_node());
}
//! <b>Effects</b>: Removes the node if it's inserted in a container. //! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if Policy is auto_unlink. //! This function is only allowed if link_mode is \c auto_unlink.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void unlink() void unlink();
{ #endif
BOOST_STATIC_ASSERT((Policy == auto_unlink));
node_algorithms::unlink(this_as_node());
node_algorithms::init(this_as_node());
}
//! The value_traits class is used as the first template argument for list.
//! The template argument is a pointer to member pointing to the node in
//! the class. Objects of type T and of types derived from T can be stored.
//! T doesn't need to be copy-constructible or assignable.
template<class T, this_type T::* M>
struct value_traits
: detail::member_hook_value_traits<T, this_type, M>
{};
//! <b>Effects</b>: Converts a pointer to a node into
//! a pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static this_type_ptr to_hook_ptr(node_ptr p)
{
return this_type_ptr(static_cast<this_type*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into
//! a const pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p)
{
return const_this_type_ptr(static_cast<const this_type*> (detail::get_pointer(p)));
}
//! <b>Effects</b>: Returns a pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
node_ptr to_node_ptr()
{ return this_as_node(); }
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
const_node_ptr to_node_ptr() const
{ return this_as_node(); }
}; };
} //namespace intrusive } //namespace intrusive
} //namespace boost } //namespace boost
#include<boost/intrusive/detail/config_end.hpp> #include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_SLIST_HOOK_HPP #endif //BOOST_INTRUSIVE_SLIST_HOOK_HPP

View File

@@ -1,26 +0,0 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2007
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_DEFAULT_TAG_HPP
#define BOOST_INTRUSIVE_DEFAULT_TAG_HPP
namespace boost {
namespace intrusive {
//!This is the declaration of the default
//!hook used by base hooks
class tag;
} //namespace intrusive
} //namespace boost
#endif //BOOST_INTRUSIVE_DEFAULT_TAG_HPP

View File

@@ -13,7 +13,7 @@
#ifndef BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP #ifndef BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP #define BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/link_mode.hpp>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
@@ -21,7 +21,7 @@ namespace intrusive {
//!This value traits template is used to create value traits //!This value traits template is used to create value traits
//!from user defined node traits where value_traits::value_type and //!from user defined node traits where value_traits::value_type and
//!node_traits::node should be equal //!node_traits::node should be equal
template<class NodeTraits, linking_policy LinkingPolicy = safe_link> template<class NodeTraits, link_mode_type LinkMode = normal_link>
struct trivial_value_traits struct trivial_value_traits
{ {
typedef NodeTraits node_traits; typedef NodeTraits node_traits;
@@ -30,7 +30,7 @@ struct trivial_value_traits
typedef typename node_traits::node value_type; typedef typename node_traits::node value_type;
typedef node_ptr pointer; typedef node_ptr pointer;
typedef const_node_ptr const_pointer; typedef const_node_ptr const_pointer;
enum { linking_policy = LinkingPolicy }; static const link_mode_type link_mode = LinkMode;
static node_ptr to_node_ptr (value_type &value) { return node_ptr(&value); } 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 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 pointer to_value_ptr(node_ptr n) { return pointer(n); }

File diff suppressed because it is too large Load Diff

View File

@@ -11,19 +11,50 @@
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_HASHSET_HOOK_HPP #ifndef BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
#define BOOST_INTRUSIVE_HASHSET_HOOK_HPP #define BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
#include <boost/intrusive/detail/config_begin.hpp> #include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp> #include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/utilities.hpp> #include <boost/intrusive/detail/utilities.hpp>
#include <boost/intrusive/detail/pointer_to_other.hpp>
#include <boost/intrusive/slist_hook.hpp> #include <boost/intrusive/slist_hook.hpp>
#include <boost/intrusive/linking_policy.hpp> #include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/generic_hook.hpp>
namespace boost { namespace boost {
namespace intrusive { namespace intrusive {
/// @cond
template<class VoidPointer>
struct get_uset_node_algo
{
typedef circular_slist_algorithms<slist_node_traits<VoidPointer> > type;
};
/// @endcond
//! Helper metafunction to define a \c unordered_set_base_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
template<class ...Options>
#else
template<class O1 = none, class O2 = none, class O3 = none>
#endif
struct make_unordered_set_base_hook
{
/// @cond
typedef typename pack_options
< hook_defaults, O1, O2, O3>::type packed_options;
typedef detail::generic_hook
< get_slist_node_algo<typename packed_options::void_pointer>
, typename packed_options::tag
, packed_options::link_mode
, detail::UsetBaseHook
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Derive a class from unordered_set_base_hook in order to store objects in //! 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 //! 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. //! 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 //! 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. //! and the unordered_set/unordered_multi_set configured from this hook.
template< class Tag //= tag #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
, linking_policy Policy //= safe_link template<class ...Options>
, class VoidPointer //= void * #else
> template<class O1, class O2, class O3>
#endif
class unordered_set_base_hook class unordered_set_base_hook
: public make_unordered_set_base_hook<O1, O2, O3>::type
{ {
/// @cond #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
typedef slist_base_hook<Tag, Policy, VoidPointer> IsListHook; //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
IsListHook m_slisthook;
typedef IsListHook implementation_defined;
/// @endcond
public:
enum { linking_policy = Policy };
typedef typename implementation_defined::node_traits node_traits;
typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef unordered_set_base_hook
<Tag, Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type>::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type>::type const_this_type_ptr;
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. //! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
unordered_set_base_hook() unordered_set_base_hook();
: m_slisthook()
{}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing a copy-constructor //! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using unordered_set_base_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
unordered_set_base_hook(const unordered_set_base_hook &other) unordered_set_base_hook(const unordered_set_base_hook& );
: m_slisthook(other.m_slisthook)
{}
//! <b>Effects</b>: Empty function. The argument is ignored. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing an assignment operator //! <b>Rationale</b>: Providing an assignment operator
//! makes classes using unordered_set_base_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. "swap" can be used to emulate //! user to do some additional work. \c swap can be used to emulate
//! move-semantics. //! move-semantics.
unordered_set_base_hook& operator=(const unordered_set_base_hook &other) unordered_set_base_hook& operator=(const unordered_set_base_hook& );
{ return *this; }
//! <b>Effects</b>: If Policy is normal_link, the destructor does //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the //! 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 Policy is //! object is stored in an unordered_set an assertion is raised. If link_mode is
//! auto_unlink and "is_linked()" is true, the node is unlinked. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
~unordered_set_base_hook() ~unordered_set_base_hook();
{} //m_slisthook's destructor does the job
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink. //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(unordered_set_base_hook &other);
//! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//! //!
//! <b>Returns</b>: true, if the node belongs to a container, false //! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether unordered_set/unordered_multiset::iterator_to //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
//! will return a valid iterator. //! will return a valid iterator.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
bool is_linked() const bool is_linked() const;
{ return m_slisthook.is_linked(); }
//! The value_traits class is used as the first template argument for unordered_set/unordered_multiset. //! <b>Effects</b>: Removes the node if it's inserted in a container.
//! The template argument T defines the class type stored in unordered_set/unordered_multiset. Objects //! This function is only allowed if link_mode is \c auto_unlink.
//! of type T and of types derived from T can be stored. T doesn't need to be
//! copy-constructible or assignable.
template<class T>
struct value_traits
: detail::derivation_hook_value_traits<T, this_type, Tag>
{};
//! <b>Effects</b>: Converts a pointer to a node into
//! a pointer to the hook that holds that node.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
static this_type_ptr to_hook_ptr(node_ptr p) void unlink();
{ #endif
return this_type_ptr((this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p))); };
}
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into
//! a const pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p)
{
return const_this_type_ptr((const this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p)));
}
//! <b>Effects</b>: Returns a pointer to the node that this hook holds. //! 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.
//! <b>Throws</b>: Nothing. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
node_ptr to_node_ptr() template<class ...Options>
{ return m_slisthook.to_node_ptr(); } #else
template<class O1 = none, class O2 = none, class O3 = none>
#endif
struct make_unordered_set_member_hook
{
/// @cond
typedef typename pack_options
< hook_defaults, O1, O2, O3>::type packed_options;
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds. typedef detail::generic_hook
//! < get_uset_node_algo<typename packed_options::void_pointer>
//! <b>Throws</b>: Nothing. , member_tag
const_node_ptr to_node_ptr() const , packed_options::link_mode
{ return m_slisthook.to_node_ptr(); } , 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 //! 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 //! 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. //! and the unordered_set/unordered_multi_set configured from this hook.
template< linking_policy Policy //= safe_link #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
, class VoidPointer //= void * template<class ...Options>
> #else
template<class O1, class O2, class O3>
#endif
class unordered_set_member_hook class unordered_set_member_hook
: public make_unordered_set_member_hook<O1, O2, O3>::type
{ {
/// @cond #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
typedef slist_member_hook<Policy, VoidPointer> IsListHook; //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
IsListHook m_slisthook;
typedef IsListHook implementation_defined;
/// @endcond
public:
enum { linking_policy = Policy };
typedef typename implementation_defined::node_traits node_traits;
typedef typename node_traits::node node;
typedef typename boost::pointer_to_other
<VoidPointer, node>::type node_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const node>::type const_node_ptr;
typedef unordered_set_member_hook
<Policy, VoidPointer> this_type;
typedef typename boost::pointer_to_other
<VoidPointer, this_type>::type this_type_ptr;
typedef typename boost::pointer_to_other
<VoidPointer, const this_type>::type const_this_type_ptr;
public:
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk
//! initializes the node to an unlinked state. //! initializes the node to an unlinked state.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
unordered_set_member_hook() unordered_set_member_hook();
: m_slisthook()
{}
//! <b>Effects</b>: If Policy is auto_unlink or safe_mode_linnk //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored. //! initializes the node to an unlinked state. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing a copy-constructor //! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using unordered_set_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. //! user to do some additional work. \c swap can be used to emulate
unordered_set_member_hook(const unordered_set_member_hook &other) //! move-semantics.
: m_slisthook(other.m_slisthook) unordered_set_member_hook(const unordered_set_member_hook& );
{}
//! <b>Effects</b>: Empty function. The argument is ignored. //! <b>Effects</b>: Empty function. The argument is ignored.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
//! //!
//! <b>Rationale</b>: Providing an assignment operator //! <b>Rationale</b>: Providing an assignment operator
//! makes classes using unordered_set_member_hook STL-compliant without forcing the //! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. //! user to do some additional work. \c swap can be used to emulate
unordered_set_member_hook& operator=(const unordered_set_member_hook &other) //! move-semantics.
{ return *this; } unordered_set_member_hook& operator=(const unordered_set_member_hook& );
//! <b>Effects</b>: If Policy is normal_link, the destructor does //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If Policy is safe_link and the //! 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 Policy is //! object is stored in an unordered_set an assertion is raised. If link_mode is
//! auto_unlink and "is_linked()" is true, the node is unlinked. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
~unordered_set_member_hook() ~unordered_set_member_hook();
{} //m_slisthook's destructor does the job
//! <b>Precondition</b>: Policy must be safe_link or auto_unlink. //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
bool is_linked() const //!
{ return m_slisthook.is_linked(); } //! <b>Throws</b>: 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. //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//! 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. //! <b>Returns</b>: true, if the node belongs to a container, false
//! T doesn't need to be copy-constructible or assignable. //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
template<class T, this_type T::* M> //! will return a valid iterator.
struct value_traits //!
: detail::member_hook_value_traits<T, this_type, M> //! <b>Complexity</b>: Constant
{}; bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container. //! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if Policy is auto_unlink. //! This function is only allowed if link_mode is \c auto_unlink.
//! //!
//! <b>Throws</b>: Nothing. //! <b>Throws</b>: Nothing.
void unlink() void unlink();
{ m_slisthook.unlink(); } #endif
//! <b>Effects</b>: Converts a pointer to a node into
//! a pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static this_type_ptr to_hook_ptr(node_ptr p)
{
return this_type_ptr((this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p)));
}
//! <b>Effects</b>: Converts a const pointer to a node stored in a container into
//! a const pointer to the hook that holds that node.
//!
//! <b>Throws</b>: Nothing.
static const_this_type_ptr to_hook_ptr(const_node_ptr p)
{
return const_this_type_ptr((const this_type*)detail::get_pointer(IsListHook::to_hook_ptr(p)));
}
//! <b>Effects</b>: Returns a pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
node_ptr to_node_ptr()
{ return m_slisthook.to_node_ptr(); }
//! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
//!
//! <b>Throws</b>: Nothing.
const_node_ptr to_node_ptr() const
{ return m_slisthook.to_node_ptr(); }
}; };
} //namespace intrusive } //namespace intrusive
@@ -287,4 +255,4 @@ class unordered_set_member_hook
#include <boost/intrusive/detail/config_end.hpp> #include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_HASHSET_HOOK_HPP #endif //BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP