| ///////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2007-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. |
| // |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| #ifndef BOOST_INTRUSIVE_GENERIC_HOOK_HPP |
| #define BOOST_INTRUSIVE_GENERIC_HOOK_HPP |
| |
| #ifndef BOOST_CONFIG_HPP |
| # include <boost/config.hpp> |
| #endif |
| |
| #if defined(BOOST_HAS_PRAGMA_ONCE) |
| # pragma once |
| #endif |
| |
| #include <boost/intrusive/pointer_traits.hpp> |
| #include <boost/intrusive/link_mode.hpp> |
| #include <boost/intrusive/detail/mpl.hpp> |
| #include <boost/intrusive/detail/assert.hpp> |
| #include <boost/intrusive/detail/node_holder.hpp> |
| #include <boost/static_assert.hpp> |
| |
| namespace boost { |
| namespace intrusive { |
| |
| /// @cond |
| |
| namespace detail { |
| |
| template <link_mode_type LinkMode> |
| struct link_dispatch |
| {}; |
| |
| template<class Hook> |
| void destructor_impl(Hook &hook, detail::link_dispatch<safe_link>) |
| { //If this assertion raises, you might have destroyed an object |
| //while it was still inserted in a container that is alive. |
| //If so, remove the object from the container before destroying it. |
| (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked()); |
| } |
| |
| template<class Hook> |
| void destructor_impl(Hook &hook, detail::link_dispatch<auto_unlink>) |
| { hook.unlink(); } |
| |
| template<class Hook> |
| void destructor_impl(Hook &, detail::link_dispatch<normal_link>) |
| {} |
| |
| } //namespace detail { |
| |
| enum base_hook_type |
| { NoBaseHookId |
| , ListBaseHookId |
| , SlistBaseHookId |
| , RbTreeBaseHookId |
| , HashBaseHookId |
| , AvlTreeBaseHookId |
| , BsTreeBaseHookId |
| , TreapTreeBaseHookId |
| , AnyBaseHookId |
| }; |
| |
| |
| template <class HookTags, unsigned int> |
| struct hook_tags_definer{}; |
| |
| template <class HookTags> |
| struct hook_tags_definer<HookTags, ListBaseHookId> |
| { typedef HookTags default_list_hook; }; |
| |
| template <class HookTags> |
| struct hook_tags_definer<HookTags, SlistBaseHookId> |
| { typedef HookTags default_slist_hook; }; |
| |
| template <class HookTags> |
| struct hook_tags_definer<HookTags, RbTreeBaseHookId> |
| { typedef HookTags default_rbtree_hook; }; |
| |
| template <class HookTags> |
| struct hook_tags_definer<HookTags, HashBaseHookId> |
| { typedef HookTags default_hashtable_hook; }; |
| |
| template <class HookTags> |
| struct hook_tags_definer<HookTags, AvlTreeBaseHookId> |
| { typedef HookTags default_avltree_hook; }; |
| |
| template <class HookTags> |
| struct hook_tags_definer<HookTags, BsTreeBaseHookId> |
| { typedef HookTags default_bstree_hook; }; |
| |
| template <class HookTags> |
| struct hook_tags_definer<HookTags, AnyBaseHookId> |
| { typedef HookTags default_any_hook; }; |
| |
| template |
| < class NodeTraits |
| , class Tag |
| , link_mode_type LinkMode |
| , base_hook_type BaseHookType |
| > |
| struct hooktags_impl |
| { |
| static const link_mode_type link_mode = LinkMode; |
| typedef Tag tag; |
| typedef NodeTraits node_traits; |
| static const bool is_base_hook = !detail::is_same<Tag, member_tag>::value; |
| static const bool safemode_or_autounlink = is_safe_autounlink<link_mode>::value; |
| static const unsigned int type = BaseHookType; |
| }; |
| |
| /// @endcond |
| |
| template |
| < class NodeAlgorithms |
| , class Tag |
| , link_mode_type LinkMode |
| , base_hook_type BaseHookType |
| > |
| class generic_hook |
| /// @cond |
| //If the hook is a base hook, derive generic hook from node_holder |
| //so that a unique base class is created to convert from the node |
| //to the type. This mechanism will be used by bhtraits. |
| // |
| //If the hook is a member hook, generic hook will directly derive |
| //from the hook. |
| : public detail::if_c |
| < detail::is_same<Tag, member_tag>::value |
| , typename NodeAlgorithms::node |
| , node_holder<typename NodeAlgorithms::node, Tag, BaseHookType> |
| >::type |
| //If this is the a default-tagged base hook derive from a class that |
| //will define an special internal typedef. Containers will be able to detect this |
| //special typedef and obtain generic_hook's internal types in order to deduce |
| //value_traits for this hook. |
| , public hook_tags_definer |
| < generic_hook<NodeAlgorithms, Tag, LinkMode, BaseHookType> |
| , detail::is_same<Tag, dft_tag>::value*BaseHookType> |
| /// @endcond |
| { |
| /// @cond |
| typedef NodeAlgorithms node_algorithms; |
| typedef typename node_algorithms::node node; |
| typedef typename node_algorithms::node_ptr node_ptr; |
| typedef typename node_algorithms::const_node_ptr const_node_ptr; |
| |
| public: |
| |
| typedef hooktags_impl |
| < typename NodeAlgorithms::node_traits |
| , Tag, LinkMode, BaseHookType> hooktags; |
| |
| node_ptr this_ptr() |
| { return pointer_traits<node_ptr>::pointer_to(static_cast<node&>(*this)); } |
| |
| const_node_ptr this_ptr() const |
| { return pointer_traits<const_node_ptr>::pointer_to(static_cast<const node&>(*this)); } |
| |
| public: |
| /// @endcond |
| |
| generic_hook() |
| { |
| if(hooktags::safemode_or_autounlink){ |
| node_algorithms::init(this->this_ptr()); |
| } |
| } |
| |
| generic_hook(const generic_hook& ) |
| { |
| if(hooktags::safemode_or_autounlink){ |
| node_algorithms::init(this->this_ptr()); |
| } |
| } |
| |
| generic_hook& operator=(const generic_hook& ) |
| { return *this; } |
| |
| ~generic_hook() |
| { |
| destructor_impl |
| (*this, detail::link_dispatch<hooktags::link_mode>()); |
| } |
| |
| void swap_nodes(generic_hook &other) |
| { |
| node_algorithms::swap_nodes |
| (this->this_ptr(), other.this_ptr()); |
| } |
| |
| bool is_linked() const |
| { |
| //is_linked() can be only used in safe-mode or auto-unlink |
| BOOST_STATIC_ASSERT(( hooktags::safemode_or_autounlink )); |
| return !node_algorithms::unique(this->this_ptr()); |
| } |
| |
| void unlink() |
| { |
| BOOST_STATIC_ASSERT(( (int)hooktags::link_mode == (int)auto_unlink )); |
| node_ptr n(this->this_ptr()); |
| if(!node_algorithms::inited(n)){ |
| node_algorithms::unlink(n); |
| node_algorithms::init(n); |
| } |
| } |
| }; |
| |
| } //namespace intrusive |
| } //namespace boost |
| |
| #endif //BOOST_INTRUSIVE_GENERIC_HOOK_HPP |