Using function hooks

| Home | Libraries | People | FAQ | More

## Using function hooks

A programmer might find that base or member hooks are not flexible enough in some situations. In some applications it would be optimal to put a hook deep inside a member of a class or just outside the class. Boost.Intrusive has an easy option to allow such cases: `function_hook`.

This option is similar to `member_hook` or `base_hook`, but the programmer can specify a function object that tells the container how to obtain a hook from a value and vice versa. The programmer just needs to define the following function object:

    //This functor converts between value_type and a hook_type
    struct Functor
    {
       //Required types
       typedef /*impl-defined*/      hook_type;
       typedef /*impl-defined*/      hook_ptr;
       typedef /*impl-defined*/      const_hook_ptr;
       typedef /*impl-defined*/      value_type;
       typedef /*impl-defined*/      pointer;
       typedef /*impl-defined*/      const_pointer;
       //Required static functions
       static hook_ptr to_hook_ptr (value_type &value);
       static const_hook_ptr to_hook_ptr(const value_type &value);
       static pointer to_value_ptr(hook_ptr n);
       static const_pointer to_value_ptr(const_hook_ptr n);
    };

Converting from values to hooks is generally easy, since most hooks are in practice members or base classes of class data members. The inverse operation is a bit more complicated, but Boost.Intrusive offers a bit of help with the function `get_parent_from_member`, which allows easy conversions from the address of a data member to the address of the parent holding that member. Let's see a little example of `function_hook`:

    #include <boost/intrusive/list.hpp>
    #include <boost/intrusive/parent_from_member.hpp>

    using namespace boost::intrusive;

    struct MyClass
    {
       int dummy;
       //This internal type has a member hook
       struct InnerNode
       {
          int dummy;
          list_member_hook<> hook;
       } inner;
    };

    //This functor converts between MyClass and InnerNode's member hook
    struct Functor
    {
       //Required types
       typedef list_member_hook<>    hook_type;
       typedef hook_type*            hook_ptr;
       typedef const hook_type*      const_hook_ptr;
       typedef MyClass               value_type;
       typedef value_type*           pointer;
       typedef const value_type*     const_pointer;

       //Required static functions
       static hook_ptr to_hook_ptr (value_type &value)
          {  return &value.inner.hook; }
       static const_hook_ptr to_hook_ptr(const value_type &value)
          {  return &value.inner.hook; }
       static pointer to_value_ptr(hook_ptr n)
       {
          return get_parent_from_member<MyClass>
             (get_parent_from_member<MyClass::InnerNode>(n, &MyClass::InnerNode::hook)
             ,&MyClass::inner
          );
       }
       static const_pointer to_value_ptr(const_hook_ptr n)
       {
          return get_parent_from_member<MyClass>
             (get_parent_from_member<MyClass::InnerNode>(n, &MyClass::InnerNode::hook)
             ,&MyClass::inner
          );
       }
    };

    //Define a list that will use the hook accessed through the function object
    typedef list< MyClass, function_hook< Functor> >  List;

    int main()
    {
       MyClass n;
       List l;
       //Insert the node in both lists
       l.insert(l.begin(), n);
       assert(l.size() == 1);
       return 0;
    }