mirror of
https://github.com/boostorg/intrusive.git
synced 2025-05-09 23:03:56 +00:00
240 lines
8.0 KiB
C++
240 lines
8.0 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (C) Copyright Ion Gaztanaga 2007-2009
|
|
//
|
|
// 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.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
#include <boost/intrusive/list.hpp>
|
|
#include <boost/intrusive/slist.hpp>
|
|
#include <boost/intrusive/rbtree.hpp>
|
|
#include <boost/intrusive/hashtable.hpp>
|
|
#include <boost/pointer_to_other.hpp>
|
|
#include <functional>
|
|
#include <vector>
|
|
|
|
using namespace boost::intrusive;
|
|
|
|
class MyClass
|
|
{
|
|
public:
|
|
int int_;
|
|
|
|
MyClass(int i = 0)
|
|
: int_(i)
|
|
{}
|
|
friend bool operator > (const MyClass &l, const MyClass &r)
|
|
{ return l.int_ > r.int_; }
|
|
friend bool operator == (const MyClass &l, const MyClass &r)
|
|
{ return l.int_ == r.int_; }
|
|
friend std::size_t hash_value(const MyClass &v)
|
|
{ return boost::hash_value(v.int_); }
|
|
};
|
|
|
|
const int NumElements = 100;
|
|
|
|
template<class NodeTraits>
|
|
struct external_traits
|
|
{
|
|
typedef NodeTraits 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 MyClass value_type;
|
|
typedef typename boost::pointer_to_other
|
|
<node_ptr, MyClass>::type pointer;
|
|
typedef typename boost::pointer_to_other
|
|
<node_ptr, const MyClass>::type const_pointer;
|
|
static const link_mode_type link_mode = normal_link;
|
|
|
|
external_traits(pointer values, std::size_t NumElem)
|
|
: values_(values), node_array_(NumElem)
|
|
{}
|
|
|
|
node_ptr to_node_ptr (value_type &value)
|
|
{ return (&node_array_[0]) + (&value - values_); }
|
|
|
|
const_node_ptr to_node_ptr (const value_type &value) const
|
|
{ return &node_array_[0] + (&value - values_); }
|
|
|
|
pointer to_value_ptr(node_ptr n)
|
|
{ return values_ + (n - &node_array_[0]); }
|
|
|
|
const_pointer to_value_ptr(const_node_ptr n) const
|
|
{ return values_ + (n - &node_array_[0]); }
|
|
|
|
pointer values_;
|
|
std::vector<node> node_array_;
|
|
};
|
|
|
|
template<class NodeTraits>
|
|
struct value_traits_proxy;
|
|
|
|
template<class T>
|
|
struct traits_holder
|
|
: public T
|
|
{};
|
|
|
|
typedef value_traits_proxy<list_node_traits<void*> > list_value_traits_proxy;
|
|
typedef value_traits_proxy<slist_node_traits<void*> > slist_value_traits_proxy;
|
|
typedef value_traits_proxy<rbtree_node_traits<void*> > rbtree_value_traits_proxy;
|
|
typedef value_traits_proxy<traits_holder<slist_node_traits<void*> > > hash_value_traits_proxy;
|
|
|
|
struct uset_bucket_traits
|
|
{
|
|
private:
|
|
typedef unordered_bucket<value_traits<external_traits
|
|
<traits_holder<slist_node_traits<void*> > > > >::type bucket_type;
|
|
|
|
//Non-copyable
|
|
uset_bucket_traits(const uset_bucket_traits &other);
|
|
uset_bucket_traits & operator=(const uset_bucket_traits &other);
|
|
|
|
public:
|
|
static const std::size_t NumBuckets = 100;
|
|
|
|
uset_bucket_traits(){}
|
|
|
|
bucket_type * bucket_begin() const
|
|
{ return buckets_; }
|
|
|
|
std::size_t bucket_count() const
|
|
{ return NumBuckets; }
|
|
|
|
mutable bucket_type buckets_[NumBuckets];
|
|
};
|
|
|
|
struct bucket_traits_proxy
|
|
{
|
|
static const bool external_bucket_traits = true;
|
|
typedef uset_bucket_traits bucket_traits;
|
|
|
|
template<class Container>
|
|
bucket_traits &get_bucket_traits(Container &cont);
|
|
|
|
template<class Container>
|
|
const bucket_traits &get_bucket_traits(const Container &cont) const;
|
|
};
|
|
|
|
//Define a list that will store MyClass using the external hook
|
|
typedef list<MyClass, value_traits<list_value_traits_proxy> > List;
|
|
//Define a slist that will store MyClass using the external hook
|
|
typedef slist<MyClass, value_traits<slist_value_traits_proxy> > Slist;
|
|
//Define a rbtree that will store MyClass using the external hook
|
|
typedef rbtree< MyClass
|
|
, value_traits<rbtree_value_traits_proxy>
|
|
, compare<std::greater<MyClass> > > Rbtree;
|
|
//Define a hashtable that will store MyClass using the external hook
|
|
typedef hashtable< MyClass
|
|
, value_traits<hash_value_traits_proxy>
|
|
, bucket_traits<bucket_traits_proxy>
|
|
> Hash;
|
|
|
|
template<class NodeTraits>
|
|
struct value_traits_proxy
|
|
{
|
|
static const bool external_value_traits = true;
|
|
typedef external_traits<NodeTraits> value_traits;
|
|
|
|
template<class Container>
|
|
const value_traits &get_value_traits(const Container &cont) const;
|
|
|
|
template<class Container>
|
|
value_traits &get_value_traits(Container &cont);
|
|
};
|
|
|
|
struct ContainerHolder
|
|
: public uset_bucket_traits
|
|
, public List
|
|
, public external_traits<list_node_traits<void*> >
|
|
, public Slist
|
|
, public external_traits<slist_node_traits<void*> >
|
|
, public Rbtree
|
|
, public external_traits<rbtree_node_traits<void*> >
|
|
, public Hash
|
|
, public external_traits<traits_holder<slist_node_traits<void*> > >
|
|
{
|
|
static const std::size_t NumBucket = 100;
|
|
ContainerHolder(MyClass *values, std::size_t num_elem)
|
|
: uset_bucket_traits()
|
|
, List()
|
|
, external_traits<list_node_traits<void*> >(values, num_elem)
|
|
, Slist()
|
|
, external_traits<slist_node_traits<void*> >(values, num_elem)
|
|
, Rbtree()
|
|
, external_traits<rbtree_node_traits<void*> >(values, num_elem)
|
|
, Hash(Hash::bucket_traits())
|
|
, external_traits<traits_holder<slist_node_traits<void*> > >(values, num_elem)
|
|
{}
|
|
};
|
|
|
|
template<class NodeTraits>
|
|
template<class Container>
|
|
typename value_traits_proxy<NodeTraits>::value_traits &
|
|
value_traits_proxy<NodeTraits>::get_value_traits(Container &cont)
|
|
{ return static_cast<value_traits&>(static_cast<ContainerHolder&>(cont)); }
|
|
|
|
template<class NodeTraits>
|
|
template<class Container>
|
|
const typename value_traits_proxy<NodeTraits>::value_traits &
|
|
value_traits_proxy<NodeTraits>::get_value_traits(const Container &cont) const
|
|
{ return static_cast<const value_traits&>(static_cast<const ContainerHolder&>(cont)); }
|
|
|
|
template<class Container>
|
|
typename bucket_traits_proxy::bucket_traits &
|
|
bucket_traits_proxy::get_bucket_traits(Container &cont)
|
|
{ return static_cast<bucket_traits&>(static_cast<ContainerHolder&>(cont)); }
|
|
|
|
template<class Container>
|
|
const typename bucket_traits_proxy::bucket_traits &
|
|
bucket_traits_proxy::get_bucket_traits(const Container &cont) const
|
|
{ return static_cast<const bucket_traits&>(static_cast<const ContainerHolder&>(cont)); }
|
|
|
|
int main()
|
|
{
|
|
MyClass values [NumElements];
|
|
//Create several MyClass objects, each one with a different value
|
|
for(int i = 0; i < NumElements; ++i)
|
|
values[i].int_ = i;
|
|
|
|
ContainerHolder cont_holder(values, NumElements);
|
|
List &my_list = static_cast<List &> (cont_holder);
|
|
Slist &my_slist = static_cast<Slist &> (cont_holder);
|
|
Rbtree &my_rbtree = static_cast<Rbtree &> (cont_holder);
|
|
Hash &my_hash = static_cast<Hash &> (cont_holder);
|
|
|
|
//Now insert them in containers
|
|
for(MyClass * it(&values[0]), *itend(&values[NumElements])
|
|
; it != itend; ++it){
|
|
my_list.push_front(*it);
|
|
my_slist.push_front(*it);
|
|
my_rbtree.insert_unique(*it);
|
|
my_hash.insert_unique(*it);
|
|
}
|
|
|
|
//Now test containers
|
|
{
|
|
List::const_iterator list_it (my_list.cbegin());
|
|
Slist::const_iterator slist_it (my_slist.cbegin());
|
|
Rbtree::const_iterator rbtree_it (my_rbtree.cbegin());
|
|
Hash::const_iterator hash_it (my_hash.cbegin());
|
|
MyClass *it_val(&values[NumElements] - 1), *it_rbeg_val(&values[0]-1);
|
|
|
|
//Test inserted objects
|
|
for(; it_val != it_rbeg_val; --it_val, ++list_it, ++slist_it, ++rbtree_it){
|
|
if(&*list_it != &*it_val) return 1;
|
|
if(&*slist_it != &*it_val) return 1;
|
|
if(&*rbtree_it != &*it_val) return 1;
|
|
hash_it = my_hash.find(*it_val);
|
|
if(hash_it == my_hash.cend() || &*hash_it != &*it_val)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|