Boost logo

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