|
Boost : |
From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2007-08-08 08:19:46
Hi Ion and Olaf,
I recently started using Boost.Intrusive and it really works like a charm.
However, I've been wondering whether it would be possible to make the
"hook interface" easier to use and less demanding in terms of names that
are injected into client code. So I started experimenting a bit and the
attachment is what I came up with. I believe that scheme might actually
work (not sure, though)...
Regards,
Tobias
#include <boost/noncopyable.hpp>
namespace intrusive
{
// traits for customization
template< typename T >
struct slist_node_traits
{
typedef T* pointer_type;
typedef T& reference;
// ...
};
// management data for one node
template< typename T, class Traits = slist_node_traits<T> >
class slist_node_mgmt_data
{
template< typename U, class Tr > friend class slist;
typename Traits::pointer_type ptr_next;
public:
slist_node_mgmt_data() { }
};
// ADL extension point to allow Boost.Intrusive to work non-intrusively
// by e.g. using an external map<element,management data>
template< typename Element, class Traits >
slist_node_mgmt_data<Element,Traits>& get_mgmt(
slist_node_mgmt_data<Element,Traits>& that)
{
return that;
}
// single-linked list (incomplete for illustration)
template< typename T, class Traits = slist_node_traits<T> >
class slist : boost::noncopyable
{
typedef Traits traits;
public:
typedef typename traits::pointer_type pointer_type;
typedef typename traits::reference reference;
pointer_type ptr_first;
public:
void push_front(reference x)
{
get_mgmt(x).ptr_next = this->ptr_first;
this->ptr_first = & x;
}
void pop_front()
{
this->ptr_first = get_mgmt(* this->ptr_first).ptr_next;
}
reference front()
{
return *this->ptr_first;
}
// ...
};
}
#include <boost/detail/lightweight_test.hpp>
#include <map>
class foo
: public intrusive::slist_node_mgmt_data<foo>
// Note: Base class does not insert any names
{
int val_data;
public:
foo(int data)
: val_data(data)
{ }
int data() const
{ return this->val_data; }
// Note: No "member hook"
};
void foo_test()
{
intrusive::slist<foo> my_list;
foo foo1(1); my_list.push_front(foo1);
foo foo2(2); my_list.push_front(foo2);
BOOST_TEST( my_list.front().data() == 2 );
my_list.pop_front();
BOOST_TEST( my_list.front().data() == 1 );
my_list.pop_front();
}
// Ok, let's try non-intrusive Intrusive ;-)
class bar
// Note: No base class
{
int val_data;
public:
bar(int data)
: val_data(data)
{ }
int data() const
{ return this->val_data; }
// Note: No "member hook"
};
// Management facility
std::map<bar*,intrusive::slist_node_mgmt_data<bar> > bar_management;
intrusive::slist_node_mgmt_data<bar>& get_mgmt(bar& that)
{
return bar_management[& that];
}
void bar_test()
{
intrusive::slist<bar> my_list;
bar bar1(1); my_list.push_front(bar1);
bar bar2(2); my_list.push_front(bar2);
BOOST_TEST( my_list.front().data() == 2 );
my_list.pop_front();
BOOST_TEST( my_list.front().data() == 1 );
my_list.pop_front();
}
// Run the tests...
int main()
{
foo_test();
bar_test();
return boost::report_errors();
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk