/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2010-2013
//
// 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/parent_from_member.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/intrusive/slist.hpp>
#include <boost/intrusive/set.hpp>
#include <boost/intrusive/unordered_set.hpp>
#include <boost/container_hash/hash.hpp>

using namespace boost::intrusive;

struct MyClass
{
   MyClass() : order(0) {}
   int order;

   //This internal type has two hooks
   struct InnerNode : public list_base_hook<>, public slist_base_hook<>
                    , public set_base_hook<>,  public unordered_set_base_hook<>
   {
      list_member_hook<>            listhook;
      slist_member_hook<>           slisthook;
      set_member_hook<>             sethook;
      unordered_set_member_hook<>   usethook;
   } inner;

   friend bool operator < (const MyClass &l, const MyClass &r)
      { return l.order < r.order; }
   friend bool operator == (const MyClass &l, const MyClass &r)
      { return l.order == r.order; }
   friend std::size_t hash_value(const MyClass &value)
      {  return std::size_t(value.order); }
};

//This functor converts between MyClass and the InnerNode member hook
#define InnerMemberHook(TAG, HOOKTYPE, MEMBERNAME)\
   struct InnerMemberHookFunctor##TAG \
   {\
      typedef HOOKTYPE              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;\
                                                \
      static hook_ptr to_hook_ptr (value_type &value)\
         {  return &value.inner.MEMBERNAME; }\
      static const_hook_ptr to_hook_ptr(const value_type &value)\
         {  return &value.inner.MEMBERNAME; }\
      static pointer to_value_ptr(hook_ptr n)\
      {\
         return get_parent_from_member<MyClass>\
            (get_parent_from_member<MyClass::InnerNode>(n, &MyClass::InnerNode::MEMBERNAME)\
            ,&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::MEMBERNAME)\
            ,&MyClass::inner\
         );\
      }\
   };\
//


//This functor converts between MyClass and the InnerNode base hook
#define InnerBaseHook(TAG, HOOKTYPE)\
   struct InnerBaseHookFunctor##TAG \
   {\
      typedef HOOKTYPE              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;\
                                                \
      static hook_ptr to_hook_ptr (value_type &value)\
         {  return &value.inner; }\
      static const_hook_ptr to_hook_ptr(const value_type &value)\
         {  return &value.inner; }\
      static pointer to_value_ptr(hook_ptr n)\
      {\
         return get_parent_from_member<MyClass>(static_cast<MyClass::InnerNode*>(n),&MyClass::inner);\
      }\
      static const_pointer to_value_ptr(const_hook_ptr n)\
      {\
         return get_parent_from_member<MyClass>(static_cast<const MyClass::InnerNode*>(n),&MyClass::inner);\
      }\
   };\
//

//List
InnerMemberHook(List, list_member_hook<>, listhook)
InnerBaseHook(List, list_base_hook<>)
//Slist
InnerMemberHook(Slist, slist_member_hook<>, slisthook)
InnerBaseHook(Slist, slist_base_hook<>)
//Set
InnerMemberHook(Set, set_member_hook<>, sethook)
InnerBaseHook(Set, set_base_hook<>)
//Unordered Set
InnerMemberHook(USet, unordered_set_member_hook<>, usethook)
InnerBaseHook(USet, unordered_set_base_hook<>)

//Define containers
typedef list < MyClass, function_hook< InnerMemberHookFunctorList> >         CustomListMember;
typedef list < MyClass, function_hook< InnerBaseHookFunctorList  > >         CustomListBase;
typedef slist< MyClass, function_hook< InnerMemberHookFunctorSlist> >        CustomSlistMember;
typedef slist< MyClass, function_hook< InnerBaseHookFunctorSlist  > >        CustomSlistBase;
typedef set  < MyClass, function_hook< InnerMemberHookFunctorSet> >          CustomSetMember;
typedef set  < MyClass, function_hook< InnerBaseHookFunctorSet  > >          CustomSetBase;
typedef unordered_set< MyClass, function_hook< InnerMemberHookFunctorUSet> > CustomUSetMember;
typedef unordered_set< MyClass, function_hook< InnerBaseHookFunctorUSet  > > CustomUSetBase;

int main()
{
   MyClass n;
   CustomListBase    listbase;
   CustomListMember  listmember;
   CustomSlistBase   slistbase;
   CustomSlistMember slistmember;
   CustomSetBase     setbase;
   CustomSetMember   setmember;
   CustomUSetBase::bucket_type buckets_uset[1];
   CustomUSetBase    usetbase(CustomUSetBase::bucket_traits(buckets_uset, 1));
   CustomUSetBase::bucket_type buckets_umultiset[1];
   CustomUSetMember  usetmember(CustomUSetMember::bucket_traits(buckets_umultiset, 1));

   listbase.insert(listbase.begin(), n);
   listmember.insert(listmember.begin(), n);
   slistbase.insert(slistbase.begin(), n);
   slistmember.insert(slistmember.begin(), n);
   setbase.insert(n);
   setmember.insert(n);
   usetbase.insert(n);
   usetmember.insert(n);

   return 0;
}
