blob: 5016697db90ff914cf86d47a57ffa8acaa0fa92b [file] [log] [blame]
/////////////////////////////////////////////////////////////////////////////
//
// (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;
}