generic_hook.hpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2007-2013
  4. //
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/intrusive for documentation.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. #ifndef BOOST_INTRUSIVE_GENERIC_HOOK_HPP
  13. #define BOOST_INTRUSIVE_GENERIC_HOOK_HPP
  14. #ifndef BOOST_CONFIG_HPP
  15. # include <boost/config.hpp>
  16. #endif
  17. #if defined(BOOST_HAS_PRAGMA_ONCE)
  18. # pragma once
  19. #endif
  20. #include <boost/intrusive/pointer_traits.hpp>
  21. #include <boost/intrusive/link_mode.hpp>
  22. #include <boost/intrusive/detail/mpl.hpp>
  23. #include <boost/intrusive/detail/assert.hpp>
  24. #include <boost/intrusive/detail/node_holder.hpp>
  25. #include <boost/intrusive/detail/algo_type.hpp>
  26. #include <boost/static_assert.hpp>
  27. namespace boost {
  28. namespace intrusive {
  29. /// @cond
  30. namespace detail {
  31. template <link_mode_type LinkMode>
  32. struct link_dispatch
  33. {};
  34. template<class Hook>
  35. BOOST_INTRUSIVE_FORCEINLINE void destructor_impl(Hook &hook, detail::link_dispatch<safe_link>)
  36. { //If this assertion raises, you might have destroyed an object
  37. //while it was still inserted in a container that is alive.
  38. //If so, remove the object from the container before destroying it.
  39. (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked());
  40. }
  41. template<class Hook>
  42. BOOST_INTRUSIVE_FORCEINLINE void destructor_impl(Hook &hook, detail::link_dispatch<auto_unlink>)
  43. { hook.unlink(); }
  44. template<class Hook>
  45. BOOST_INTRUSIVE_FORCEINLINE void destructor_impl(Hook &, detail::link_dispatch<normal_link>)
  46. {}
  47. } //namespace detail {
  48. enum base_hook_type
  49. { NoBaseHookId
  50. , ListBaseHookId
  51. , SlistBaseHookId
  52. , RbTreeBaseHookId
  53. , HashBaseHookId
  54. , AvlTreeBaseHookId
  55. , BsTreeBaseHookId
  56. , TreapTreeBaseHookId
  57. , AnyBaseHookId
  58. };
  59. template <class HookTags, unsigned int>
  60. struct hook_tags_definer{};
  61. template <class HookTags>
  62. struct hook_tags_definer<HookTags, ListBaseHookId>
  63. { typedef HookTags default_list_hook; };
  64. template <class HookTags>
  65. struct hook_tags_definer<HookTags, SlistBaseHookId>
  66. { typedef HookTags default_slist_hook; };
  67. template <class HookTags>
  68. struct hook_tags_definer<HookTags, RbTreeBaseHookId>
  69. { typedef HookTags default_rbtree_hook; };
  70. template <class HookTags>
  71. struct hook_tags_definer<HookTags, HashBaseHookId>
  72. { typedef HookTags default_hashtable_hook; };
  73. template <class HookTags>
  74. struct hook_tags_definer<HookTags, AvlTreeBaseHookId>
  75. { typedef HookTags default_avltree_hook; };
  76. template <class HookTags>
  77. struct hook_tags_definer<HookTags, BsTreeBaseHookId>
  78. { typedef HookTags default_bstree_hook; };
  79. template <class HookTags>
  80. struct hook_tags_definer<HookTags, AnyBaseHookId>
  81. { typedef HookTags default_any_hook; };
  82. template
  83. < class NodeTraits
  84. , class Tag
  85. , link_mode_type LinkMode
  86. , base_hook_type BaseHookType
  87. >
  88. struct hooktags_impl
  89. {
  90. static const link_mode_type link_mode = LinkMode;
  91. typedef Tag tag;
  92. typedef NodeTraits node_traits;
  93. static const bool is_base_hook = !detail::is_same<Tag, member_tag>::value;
  94. static const bool safemode_or_autounlink = is_safe_autounlink<link_mode>::value;
  95. static const unsigned int type = BaseHookType;
  96. };
  97. /// @endcond
  98. template
  99. < boost::intrusive::algo_types Algo
  100. , class NodeTraits
  101. , class Tag
  102. , link_mode_type LinkMode
  103. , base_hook_type BaseHookType
  104. >
  105. class generic_hook
  106. /// @cond
  107. //If the hook is a base hook, derive generic hook from node_holder
  108. //so that a unique base class is created to convert from the node
  109. //to the type. This mechanism will be used by bhtraits.
  110. //
  111. //If the hook is a member hook, generic hook will directly derive
  112. //from the hook.
  113. : public detail::if_c
  114. < detail::is_same<Tag, member_tag>::value
  115. , typename NodeTraits::node
  116. , node_holder<typename NodeTraits::node, Tag, BaseHookType>
  117. >::type
  118. //If this is the a default-tagged base hook derive from a class that
  119. //will define an special internal typedef. Containers will be able to detect this
  120. //special typedef and obtain generic_hook's internal types in order to deduce
  121. //value_traits for this hook.
  122. , public hook_tags_definer
  123. < generic_hook<Algo, NodeTraits, Tag, LinkMode, BaseHookType>
  124. , detail::is_same<Tag, dft_tag>::value ? BaseHookType : NoBaseHookId>
  125. /// @endcond
  126. {
  127. /// @cond
  128. typedef typename get_algo<Algo, NodeTraits>::type node_algorithms;
  129. typedef typename node_algorithms::node node;
  130. typedef typename node_algorithms::node_ptr node_ptr;
  131. typedef typename node_algorithms::const_node_ptr const_node_ptr;
  132. public:
  133. typedef hooktags_impl
  134. < NodeTraits
  135. , Tag, LinkMode, BaseHookType> hooktags;
  136. BOOST_INTRUSIVE_FORCEINLINE node_ptr this_ptr()
  137. { return pointer_traits<node_ptr>::pointer_to(static_cast<node&>(*this)); }
  138. BOOST_INTRUSIVE_FORCEINLINE const_node_ptr this_ptr() const
  139. { return pointer_traits<const_node_ptr>::pointer_to(static_cast<const node&>(*this)); }
  140. public:
  141. /// @endcond
  142. BOOST_INTRUSIVE_FORCEINLINE generic_hook()
  143. {
  144. if(hooktags::safemode_or_autounlink){
  145. node_algorithms::init(this->this_ptr());
  146. }
  147. }
  148. BOOST_INTRUSIVE_FORCEINLINE generic_hook(const generic_hook& )
  149. {
  150. if(hooktags::safemode_or_autounlink){
  151. node_algorithms::init(this->this_ptr());
  152. }
  153. }
  154. BOOST_INTRUSIVE_FORCEINLINE generic_hook& operator=(const generic_hook& )
  155. { return *this; }
  156. BOOST_INTRUSIVE_FORCEINLINE ~generic_hook()
  157. {
  158. destructor_impl
  159. (*this, detail::link_dispatch<hooktags::link_mode>());
  160. }
  161. BOOST_INTRUSIVE_FORCEINLINE void swap_nodes(generic_hook &other)
  162. {
  163. node_algorithms::swap_nodes
  164. (this->this_ptr(), other.this_ptr());
  165. }
  166. BOOST_INTRUSIVE_FORCEINLINE bool is_linked() const
  167. {
  168. //is_linked() can be only used in safe-mode or auto-unlink
  169. BOOST_STATIC_ASSERT(( hooktags::safemode_or_autounlink ));
  170. return !node_algorithms::unique(this->this_ptr());
  171. }
  172. BOOST_INTRUSIVE_FORCEINLINE void unlink()
  173. {
  174. BOOST_STATIC_ASSERT(( (int)hooktags::link_mode == (int)auto_unlink ));
  175. node_ptr n(this->this_ptr());
  176. if(!node_algorithms::inited(n)){
  177. node_algorithms::unlink(n);
  178. node_algorithms::init(n);
  179. }
  180. }
  181. };
  182. } //namespace intrusive
  183. } //namespace boost
  184. #endif //BOOST_INTRUSIVE_GENERIC_HOOK_HPP