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:
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
typedef NodeTraits node_traits;
//! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
//!

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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/parent_from_member.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp>
#include <boost/intrusive/linking_policy.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <cstddef>
#include <iterator>
@@ -26,6 +26,64 @@ namespace boost {
namespace intrusive {
namespace detail {
template <class T>
struct internal_member_value_traits
{
template <class U> static detail::one test(...);
template <class U> static detail::two test(typename U::member_value_traits* = 0);
static const bool value = sizeof(test<T>(0)) == sizeof(detail::two);
};
template <class T>
struct internal_base_hook_bool
{
template<bool Add>
struct two_or_three {one _[2 + Add];};
template <class U> static one test(...);
template <class U> static two_or_three<U::boost_intrusive_tags::is_base_hook>
test (detail::bool_<U::boost_intrusive_tags::is_base_hook>* = 0);
static const int value = sizeof(test<T>(0));
};
template <class T>
struct internal_base_hook_bool_is_true
{
static const bool value = internal_base_hook_bool<T>::value == 3;
};
template <class T>
struct external_value_traits_bool
{
template<bool Add>
struct two_or_three {one _[2 + Add];};
template <class U> static one test(...);
template <class U> static two_or_three<U::external_value_traits>
test (detail::bool_<U::external_value_traits>* = 0);
static const int value = sizeof(test<T>(0));
};
template <class T>
struct external_bucket_traits_bool
{
template<bool Add>
struct two_or_three {one _[2 + Add];};
template <class U> static one test(...);
template <class U> static two_or_three<U::external_bucket_traits>
test (detail::bool_<U::external_bucket_traits>* = 0);
static const int value = sizeof(test<T>(0));
};
template <class T>
struct external_value_traits_is_true
{
static const bool value = external_value_traits_bool<T>::value == 3;
};
template<class Node, class Tag, link_mode_type LinkMode, int>
struct node_holder
: public Node
{};
template<class SmartPtr>
struct smart_ptr_type
{
@@ -49,7 +107,6 @@ template<class Ptr>
inline typename smart_ptr_type<Ptr>::pointer
get_pointer(const Ptr &ptr)
{ return smart_ptr_type<Ptr>::get(ptr); }
//{ using boost::get_pointer; return get_pointer(ptr); }
//This functor compares a stored value
//and the one passed as an argument
@@ -75,10 +132,20 @@ 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>
struct size_holder
{
enum { constant_time_size = ConstantSize };
static const bool constant_time_size = ConstantSize;
typedef SizeType size_type;
SizeType get_size() const
@@ -99,7 +166,7 @@ struct size_holder
template<class SizeType>
struct size_holder<false, SizeType>
{
enum { constant_time_size = false };
static const bool constant_time_size = false;
typedef SizeType size_type;
size_type get_size() const
@@ -115,11 +182,235 @@ struct size_holder<false, SizeType>
{}
};
template<class T, class DerivationHookType, typename Tag>
struct derivation_hook_value_traits
template<class KeyValueCompare, class Container>
struct key_nodeptr_comp
: private detail::ebo_functor_holder<KeyValueCompare>
{
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:
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 typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
@@ -127,173 +418,61 @@ struct derivation_hook_value_traits
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference;
enum { linking_policy = DerivationHookType::linking_policy };
static const link_mode_type link_mode = LinkMode;
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)
{ return static_cast<const DerivationHookType &>(value).to_node_ptr(); }
{ return static_cast<const node_holder*>(&value); }
static pointer to_value_ptr(node_ptr n)
{
return static_cast<T*>(detail::get_pointer(DerivationHookType::to_hook_ptr(n)));
}
{ return static_cast<T*>(static_cast<node_holder*>(&*n)); }
static const_pointer to_value_ptr(const_node_ptr n)
{
return static_cast<const T*>(detail::get_pointer(DerivationHookType::to_hook_ptr(n)));
}
{ return static_cast<const T*>(static_cast<const node_holder*>(&*n)); }
};
template<class T, class MemberHookType, MemberHookType T::* P>
struct member_hook_value_traits
template<class T, class Hook, Hook T::* P>
struct member_hook_traits
{
public:
typedef typename MemberHookType::node_traits node_traits;
typedef Hook hook_type;
typedef typename hook_type::boost_intrusive_tags::node_traits node_traits;
typedef typename node_traits::node node;
typedef T value_type;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef typename boost::pointer_to_other<node_ptr, T>::type pointer;
typedef typename boost::pointer_to_other<node_ptr, const T>::type const_pointer;
typedef value_type & reference;
typedef const value_type & const_reference;
enum { linking_policy = MemberHookType::linking_policy };
typedef typename std::iterator_traits<pointer>::reference reference;
typedef typename std::iterator_traits<const_pointer>::reference const_reference;
static const link_mode_type link_mode = Hook::boost_intrusive_tags::link_mode;
public:
static node_ptr to_node_ptr(reference value)
{
MemberHookType* result = &(value.*P);
return result->to_node_ptr();
return reinterpret_cast<node*>(&(value.*P));
}
static const_node_ptr to_node_ptr(const_reference value)
{
const MemberHookType* result = &(value.*P);
return result->to_node_ptr();
return static_cast<const node*>(&(value.*P));
}
static pointer to_value_ptr(node_ptr n)
{
return pointer
(
parent_from_member<value_type, MemberHookType>
(detail::get_pointer(MemberHookType::to_hook_ptr(n)), P)
);
return detail::parent_from_member<T, Hook>
(static_cast<Hook*>(detail::get_pointer(n)), P);
}
static const_pointer to_value_ptr(const_node_ptr n)
{
return const_pointer
(
parent_from_member<value_type, MemberHookType>
(detail::get_pointer(MemberHookType::to_hook_ptr(n)), P)
);
return detail::parent_from_member<T, Hook>
(static_cast<const Hook*>(detail::get_pointer(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 boost

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

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

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,15 @@
// in supporting documentation. Hewlett-Packard Company makes no
// representations about the suitability of this software for any
// purpose. It is provided "as is" without express or implied warranty.
//
// The tree destruction algorithm is based on Julienne Walker and The EC Team code:
//
// This code is in the public domain. Anyone may use it or change it in any way that
// they see fit. The author assumes no responsibility for damages incurred through
// use of the original code or any variations thereof.
//
// It is requested, but not required, that due credit is given to the original author
// and anyone who has modified the code through a header comment, such as this one.
#ifndef BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
#define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP
@@ -43,9 +52,7 @@
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <cstddef>
#ifndef BOOST_INTRUSIVE_DISABLE_EXCEPTION_HANDLING
#include <boost/detail/no_exceptions_support.hpp>
#endif
#include <boost/intrusive/detail/no_exceptions_support.hpp>
#include <boost/intrusive/detail/utilities.hpp>
@@ -67,7 +74,7 @@ namespace intrusive {
//! relinked into its place, rather than copied, so that the only
//! pointers invalidated are those referring to the deleted node.
//!
//! rbtree_algorithms is configured with a NodeTraits class, which capsulates the
//! rbtree_algorithms is configured with a NodeTraits class, which encapsulates the
//! information about the node to be manipulated. NodeTraits must support the
//! following interface:
//!
@@ -111,6 +118,7 @@ class rbtree_algorithms
/// @endcond
public:
typedef NodeTraits node_traits;
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
typedef typename NodeTraits::color color;
@@ -121,6 +129,27 @@ class rbtree_algorithms
{
return node_ptr(const_cast<node*>(::boost::intrusive::detail::get_pointer(ptr)));
}
static void swap_left(node_ptr this_node, node_ptr other_node)
{
node_ptr temp(NodeTraits::get_left(this_node));
NodeTraits::set_left(this_node, NodeTraits::get_left(other_node));
NodeTraits::set_left(other_node, temp);
}
static void swap_right(node_ptr this_node, node_ptr other_node)
{
node_ptr temp(NodeTraits::get_right(this_node));
NodeTraits::set_right(this_node, NodeTraits::get_right(other_node));
NodeTraits::set_right(other_node, temp);
}
static void swap_parent(node_ptr this_node, node_ptr other_node)
{
node_ptr temp(NodeTraits::get_parent(this_node));
NodeTraits::set_parent(this_node, NodeTraits::get_parent(other_node));
NodeTraits::set_parent(other_node, temp);
}
/// @endcond
public:
@@ -146,7 +175,14 @@ class rbtree_algorithms
//!
//! <b>Throws</b>: Nothing.
static void swap_tree(node_ptr header1, node_ptr header2)
{
{/*
if(NodeTraits::get_parent(header1)){
NodeTraits::node n1;
node_ptr n2(NodeTraits::get_parent(header1));
init(&n1);
swap_nodes(&n1, n2);
swap_nodes(&n1, n2);
}*/
if(header1 == header2)
return;
@@ -185,6 +221,276 @@ 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>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>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.
template <class Cloner, class Disposer>
static void clone_tree
static void clone
(const_node_ptr source_header, node_ptr target_header, Cloner cloner, Disposer disposer)
{
if(!unique(target_header)){
node_ptr p;
while((p = unlink_leftmost_without_rebalance(target_header))){
disposer(p);
}
clear_and_dispose(target_header, disposer);
}
node_ptr source_root = NodeTraits::get_parent(source_header);
node_ptr leftmost, rightmost;
node_ptr new_root = clone_subtree
(source_header, target_header, cloner, disposer, leftmost, rightmost);
//Now update header node
NodeTraits::set_parent(target_header, new_root);
NodeTraits::set_left (target_header, leftmost);
NodeTraits::set_right (target_header, rightmost);
}
//! <b>Requires</b>: "disposer" must be an object function
//! taking a node_ptr parameter and shouldn't throw.
//!
//! <b>Effects</b>: Empties the target tree calling
//! <tt>void disposer::operator()(node_ptr)</tt> for every node of the tree
//! except the header.
//!
//! <b>Complexity</b>: Linear to the number of element of the source tree plus the.
//! number of elements of tree target tree when calling this function.
//!
//! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.
template<class Disposer>
static void clear_and_dispose(node_ptr header, Disposer disposer)
{
node_ptr source_root = NodeTraits::get_parent(header);
if(!source_root)
return;
NodeTraits::set_parent
( target_header
, deep_clone_node(source_root, target_header, cloner, disposer));
NodeTraits::set_left(target_header, minimum(NodeTraits::get_parent(target_header)));
NodeTraits::set_right(target_header, maximum(NodeTraits::get_parent(target_header)));
dispose_subtree(source_root, disposer);
init_header(header);
}
//! <b>Requires</b>: "header" must be the header node of a tree.
@@ -694,6 +1021,17 @@ class rbtree_algorithms
bool link_left = (y == h) ||
comp(new_node, y);
link_and_balance(new_node, y, link_left, h);
/*
//erase me
NodeTraits::node n;
init(&n);
if(y!=h)
x = x;
node_ptr n1(y!=h ? y : &n);
node_ptr n2(new_node);
swap_nodes(n2, n1);
swap_nodes(n2, n1);
*/
return new_node;
}
@@ -725,6 +1063,17 @@ class rbtree_algorithms
bool link_left = (y == h) ||
!comp(y, new_node);
link_and_balance(new_node, y, link_left, h);
/*
//erase me
NodeTraits::node n;
init(&n);
if(y!=h)
x = x;
node_ptr n1(y!=h ? y : &n);
node_ptr n2(new_node);
swap_nodes(n2, n1);
swap_nodes(n2, n1);
*/
return new_node;
}
@@ -752,6 +1101,14 @@ class rbtree_algorithms
!comp(new_node, (prev = prev_node(hint)))){
bool link_left = unique(header) || !NodeTraits::get_left(hint);
link_and_balance(new_node, link_left ? hint : prev, link_left, header);
/*
//erase me
NodeTraits::node n1;
node_ptr n2(new_node);
init(&n1);
swap_nodes(n2, &n1);
swap_nodes(&n1, n2);
*/
return new_node;
}
else{
@@ -922,6 +1279,109 @@ class rbtree_algorithms
/// @cond
template <class Cloner, class Disposer>
static node_ptr clone_subtree
( const_node_ptr source_parent, node_ptr target_parent
, Cloner cloner, Disposer disposer
, node_ptr &leftmost_out, node_ptr &rightmost_out
)
{
node_ptr target_sub_root = target_parent;
node_ptr source_root = NodeTraits::get_parent(source_parent);
if(!source_root){
leftmost_out = rightmost_out = source_root;
}
else{
//We'll calculate leftmost and rightmost nodes while iterating
node_ptr current = source_root;
node_ptr insertion_point = target_sub_root = cloner(current);
//We'll calculate leftmost and rightmost nodes while iterating
node_ptr leftmost = target_sub_root;
node_ptr rightmost = target_sub_root;
//First set the subroot
NodeTraits::set_left(target_sub_root, 0);
NodeTraits::set_right(target_sub_root, 0);
NodeTraits::set_parent(target_sub_root, target_parent);
NodeTraits::set_color(target_sub_root, NodeTraits::get_color(current));
try {
while(true) {
//First clone left nodes
if( NodeTraits::get_left(current) &&
!NodeTraits::get_left(insertion_point)) {
current = NodeTraits::get_left(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, 0);
NodeTraits::set_right (insertion_point, 0);
NodeTraits::set_color (insertion_point, NodeTraits::get_color(current));
//Insert left
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_left (temp, insertion_point);
//Update leftmost
if(rightmost == target_sub_root)
leftmost = insertion_point;
}
//Then clone right nodes
else if( NodeTraits::get_right(current) &&
!NodeTraits::get_right(insertion_point)){
current = NodeTraits::get_right(current);
node_ptr temp = insertion_point;
//Clone and mark as leaf
insertion_point = cloner(current);
NodeTraits::set_left (insertion_point, 0);
NodeTraits::set_right (insertion_point, 0);
NodeTraits::set_color (insertion_point, NodeTraits::get_color(current));
//Insert right
NodeTraits::set_parent(insertion_point, temp);
NodeTraits::set_right (temp, insertion_point);
//Update rightmost
rightmost = insertion_point;
}
//If not, go up
else if(current == source_root){
break;
}
else{
//Branch completed, go up searching more nodes to clone
current = NodeTraits::get_parent(current);
insertion_point = NodeTraits::get_parent(insertion_point);
}
}
}
catch(...) {
dispose_subtree(target_sub_root, disposer);
throw;
}
leftmost_out = leftmost;
rightmost_out = rightmost;
}
return target_sub_root;
}
template<class Disposer>
static void dispose_subtree(node_ptr x, Disposer disposer)
{
node_ptr save;
while (x){
save = NodeTraits::get_left(x);
if (save) {
// Right rotation
NodeTraits::set_left(x, NodeTraits::get_right(save));
NodeTraits::set_right(save, x);
}
else {
save = NodeTraits::get_right(x);
init(x);
disposer(x);
}
x = save;
}
}
//! <b>Requires</b>: z is the node to be inserted, par is its parent,
//! left, indicates if z should be a left node of par and header is the header
//! of the tree.
@@ -1106,59 +1566,6 @@ class rbtree_algorithms
}
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
};

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

View File

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

View File

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

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

File diff suppressed because it is too large Load Diff

View File

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