unordered_set_hook.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Olaf Krzikalla 2004-2006.
  4. // (C) Copyright Ion Gaztanaga 2006-2013
  5. //
  6. // Distributed under the Boost Software License, Version 1.0.
  7. // (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // See http://www.boost.org/libs/intrusive for documentation.
  11. //
  12. /////////////////////////////////////////////////////////////////////////////
  13. #ifndef BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
  14. #define BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
  15. #include <boost/intrusive/detail/config_begin.hpp>
  16. #include <boost/intrusive/intrusive_fwd.hpp>
  17. #include <boost/intrusive/pointer_traits.hpp>
  18. #include <boost/intrusive/slist_hook.hpp>
  19. #include <boost/intrusive/options.hpp>
  20. #include <boost/intrusive/detail/generic_hook.hpp>
  21. #if defined(BOOST_HAS_PRAGMA_ONCE)
  22. # pragma once
  23. #endif
  24. namespace boost {
  25. namespace intrusive {
  26. /// @cond
  27. template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
  28. struct unordered_node
  29. : public slist_node<VoidPointer>
  30. {
  31. typedef typename pointer_traits
  32. <VoidPointer>::template rebind_pointer
  33. < unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> >::type
  34. node_ptr;
  35. node_ptr prev_in_group_;
  36. std::size_t hash_;
  37. };
  38. template<class VoidPointer>
  39. struct unordered_node<VoidPointer, false, true>
  40. : public slist_node<VoidPointer>
  41. {
  42. typedef typename pointer_traits
  43. <VoidPointer>::template rebind_pointer
  44. < unordered_node<VoidPointer, false, true> >::type
  45. node_ptr;
  46. node_ptr prev_in_group_;
  47. };
  48. template<class VoidPointer>
  49. struct unordered_node<VoidPointer, true, false>
  50. : public slist_node<VoidPointer>
  51. {
  52. typedef typename pointer_traits
  53. <VoidPointer>::template rebind_pointer
  54. < unordered_node<VoidPointer, true, false> >::type
  55. node_ptr;
  56. std::size_t hash_;
  57. };
  58. template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
  59. struct unordered_node_traits
  60. : public slist_node_traits<VoidPointer>
  61. {
  62. typedef slist_node_traits<VoidPointer> reduced_slist_node_traits;
  63. typedef unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> node;
  64. typedef typename pointer_traits
  65. <VoidPointer>::template rebind_pointer
  66. < node >::type node_ptr;
  67. typedef typename pointer_traits
  68. <VoidPointer>::template rebind_pointer
  69. < const node >::type const_node_ptr;
  70. static const bool store_hash = StoreHash;
  71. static const bool optimize_multikey = OptimizeMultiKey;
  72. BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_next(const const_node_ptr & n)
  73. { return pointer_traits<node_ptr>::static_cast_from(n->next_); }
  74. BOOST_INTRUSIVE_FORCEINLINE static void set_next(node_ptr n, node_ptr next)
  75. { n->next_ = next; }
  76. BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_prev_in_group(const const_node_ptr & n)
  77. { return n->prev_in_group_; }
  78. BOOST_INTRUSIVE_FORCEINLINE static void set_prev_in_group(node_ptr n, node_ptr prev)
  79. { n->prev_in_group_ = prev; }
  80. BOOST_INTRUSIVE_FORCEINLINE static std::size_t get_hash(const const_node_ptr & n)
  81. { return n->hash_; }
  82. BOOST_INTRUSIVE_FORCEINLINE static void set_hash(const node_ptr & n, std::size_t h)
  83. { n->hash_ = h; }
  84. };
  85. template<class NodeTraits>
  86. struct unordered_group_adapter
  87. {
  88. typedef typename NodeTraits::node node;
  89. typedef typename NodeTraits::node_ptr node_ptr;
  90. typedef typename NodeTraits::const_node_ptr const_node_ptr;
  91. static node_ptr get_next(const const_node_ptr & n)
  92. { return NodeTraits::get_prev_in_group(n); }
  93. static void set_next(node_ptr n, node_ptr next)
  94. { NodeTraits::set_prev_in_group(n, next); }
  95. };
  96. template<class NodeTraits>
  97. struct unordered_algorithms
  98. : public circular_slist_algorithms<NodeTraits>
  99. {
  100. typedef circular_slist_algorithms<NodeTraits> base_type;
  101. typedef unordered_group_adapter<NodeTraits> group_traits;
  102. typedef circular_slist_algorithms<group_traits> group_algorithms;
  103. typedef NodeTraits node_traits;
  104. typedef typename NodeTraits::node node;
  105. typedef typename NodeTraits::node_ptr node_ptr;
  106. typedef typename NodeTraits::const_node_ptr const_node_ptr;
  107. BOOST_INTRUSIVE_FORCEINLINE static void init(typename base_type::node_ptr n)
  108. {
  109. base_type::init(n);
  110. group_algorithms::init(n);
  111. }
  112. BOOST_INTRUSIVE_FORCEINLINE static void init_header(typename base_type::node_ptr n)
  113. {
  114. base_type::init_header(n);
  115. group_algorithms::init_header(n);
  116. }
  117. BOOST_INTRUSIVE_FORCEINLINE static void unlink(typename base_type::node_ptr n)
  118. {
  119. base_type::unlink(n);
  120. group_algorithms::unlink(n);
  121. }
  122. };
  123. //Class to avoid defining the same algo as a circular list, as hooks would be ambiguous between them
  124. template<class Algo>
  125. struct uset_algo_wrapper : public Algo
  126. {};
  127. template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
  128. struct get_uset_node_traits
  129. {
  130. typedef typename detail::if_c
  131. < (StoreHash || OptimizeMultiKey)
  132. , unordered_node_traits<VoidPointer, StoreHash, OptimizeMultiKey>
  133. , slist_node_traits<VoidPointer>
  134. >::type type;
  135. };
  136. template<bool OptimizeMultiKey>
  137. struct get_uset_algo_type
  138. {
  139. static const algo_types value = OptimizeMultiKey ? UnorderedAlgorithms : UnorderedCircularSlistAlgorithms;
  140. };
  141. template<class NodeTraits>
  142. struct get_algo<UnorderedAlgorithms, NodeTraits>
  143. {
  144. typedef unordered_algorithms<NodeTraits> type;
  145. };
  146. template<class NodeTraits>
  147. struct get_algo<UnorderedCircularSlistAlgorithms, NodeTraits>
  148. {
  149. typedef uset_algo_wrapper< circular_slist_algorithms<NodeTraits> > type;
  150. };
  151. /// @endcond
  152. //! Helper metafunction to define a \c unordered_set_base_hook that yields to the same
  153. //! type when the same options (either explicitly or implicitly) are used.
  154. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  155. template<class ...Options>
  156. #else
  157. template<class O1 = void, class O2 = void, class O3 = void, class O4 = void>
  158. #endif
  159. struct make_unordered_set_base_hook
  160. {
  161. /// @cond
  162. typedef typename pack_options
  163. < hook_defaults,
  164. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  165. O1, O2, O3, O4
  166. #else
  167. Options...
  168. #endif
  169. >::type packed_options;
  170. typedef generic_hook
  171. < get_uset_algo_type <packed_options::optimize_multikey>::value
  172. , typename get_uset_node_traits < typename packed_options::void_pointer
  173. , packed_options::store_hash
  174. , packed_options::optimize_multikey
  175. >::type
  176. , typename packed_options::tag
  177. , packed_options::link_mode
  178. , HashBaseHookId
  179. > implementation_defined;
  180. /// @endcond
  181. typedef implementation_defined type;
  182. };
  183. //! Derive a class from unordered_set_base_hook in order to store objects in
  184. //! in an unordered_set/unordered_multi_set. unordered_set_base_hook holds the data necessary to maintain
  185. //! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
  186. //!
  187. //! The hook admits the following options: \c tag<>, \c void_pointer<>,
  188. //! \c link_mode<>, \c store_hash<> and \c optimize_multikey<>.
  189. //!
  190. //! \c tag<> defines a tag to identify the node.
  191. //! The same tag value can be used in different classes, but if a class is
  192. //! derived from more than one \c list_base_hook, then each \c list_base_hook needs its
  193. //! unique tag.
  194. //!
  195. //! \c void_pointer<> is the pointer type that will be used internally in the hook
  196. //! and the container configured to use this hook.
  197. //!
  198. //! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
  199. //! \c auto_unlink or \c safe_link).
  200. //!
  201. //! \c store_hash<> will tell the hook to store the hash of the value
  202. //! to speed up rehashings.
  203. //!
  204. //! \c optimize_multikey<> will tell the hook to store a link to form a group
  205. //! with other value with the same value to speed up searches and insertions
  206. //! in unordered_multisets with a great number of with equivalent keys.
  207. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  208. template<class ...Options>
  209. #else
  210. template<class O1, class O2, class O3, class O4>
  211. #endif
  212. class unordered_set_base_hook
  213. : public make_unordered_set_base_hook<
  214. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  215. O1, O2, O3, O4
  216. #else
  217. Options...
  218. #endif
  219. >::type
  220. {
  221. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  222. public:
  223. //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
  224. //! initializes the node to an unlinked state.
  225. //!
  226. //! <b>Throws</b>: Nothing.
  227. unordered_set_base_hook();
  228. //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
  229. //! initializes the node to an unlinked state. The argument is ignored.
  230. //!
  231. //! <b>Throws</b>: Nothing.
  232. //!
  233. //! <b>Rationale</b>: Providing a copy-constructor
  234. //! makes classes using the hook STL-compliant without forcing the
  235. //! user to do some additional work. \c swap can be used to emulate
  236. //! move-semantics.
  237. unordered_set_base_hook(const unordered_set_base_hook& );
  238. //! <b>Effects</b>: Empty function. The argument is ignored.
  239. //!
  240. //! <b>Throws</b>: Nothing.
  241. //!
  242. //! <b>Rationale</b>: Providing an assignment operator
  243. //! makes classes using the hook STL-compliant without forcing the
  244. //! user to do some additional work. \c swap can be used to emulate
  245. //! move-semantics.
  246. unordered_set_base_hook& operator=(const unordered_set_base_hook& );
  247. //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
  248. //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
  249. //! object is stored in an unordered_set an assertion is raised. If link_mode is
  250. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
  251. //!
  252. //! <b>Throws</b>: Nothing.
  253. ~unordered_set_base_hook();
  254. //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
  255. //! related to those nodes in one or two containers. That is, if the node
  256. //! this is part of the element e1, the node x is part of the element e2
  257. //! and both elements are included in the containers s1 and s2, then after
  258. //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
  259. //! at the position of e1. If one element is not in a container, then
  260. //! after the swap-operation the other element is not in a container.
  261. //! Iterators to e1 and e2 related to those nodes are invalidated.
  262. //!
  263. //! <b>Complexity</b>: Constant
  264. //!
  265. //! <b>Throws</b>: Nothing.
  266. void swap_nodes(unordered_set_base_hook &other);
  267. //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
  268. //!
  269. //! <b>Returns</b>: true, if the node belongs to a container, false
  270. //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
  271. //! will return a valid iterator.
  272. //!
  273. //! <b>Complexity</b>: Constant
  274. bool is_linked() const;
  275. //! <b>Effects</b>: Removes the node if it's inserted in a container.
  276. //! This function is only allowed if link_mode is \c auto_unlink.
  277. //!
  278. //! <b>Throws</b>: Nothing.
  279. void unlink();
  280. #endif
  281. };
  282. //! Helper metafunction to define a \c unordered_set_member_hook that yields to the same
  283. //! type when the same options (either explicitly or implicitly) are used.
  284. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  285. template<class ...Options>
  286. #else
  287. template<class O1 = void, class O2 = void, class O3 = void, class O4 = void>
  288. #endif
  289. struct make_unordered_set_member_hook
  290. {
  291. /// @cond
  292. typedef typename pack_options
  293. < hook_defaults,
  294. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  295. O1, O2, O3, O4
  296. #else
  297. Options...
  298. #endif
  299. >::type packed_options;
  300. typedef generic_hook
  301. < get_uset_algo_type <packed_options::optimize_multikey>::value
  302. , typename get_uset_node_traits < typename packed_options::void_pointer
  303. , packed_options::store_hash
  304. , packed_options::optimize_multikey
  305. >::type
  306. , member_tag
  307. , packed_options::link_mode
  308. , NoBaseHookId
  309. > implementation_defined;
  310. /// @endcond
  311. typedef implementation_defined type;
  312. };
  313. //! Put a public data member unordered_set_member_hook in order to store objects of this class in
  314. //! an unordered_set/unordered_multi_set. unordered_set_member_hook holds the data necessary for maintaining the
  315. //! unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
  316. //!
  317. //! The hook admits the following options: \c void_pointer<>,
  318. //! \c link_mode<> and \c store_hash<>.
  319. //!
  320. //! \c void_pointer<> is the pointer type that will be used internally in the hook
  321. //! and the container configured to use this hook.
  322. //!
  323. //! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
  324. //! \c auto_unlink or \c safe_link).
  325. //!
  326. //! \c store_hash<> will tell the hook to store the hash of the value
  327. //! to speed up rehashings.
  328. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  329. template<class ...Options>
  330. #else
  331. template<class O1, class O2, class O3, class O4>
  332. #endif
  333. class unordered_set_member_hook
  334. : public make_unordered_set_member_hook<
  335. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  336. O1, O2, O3, O4
  337. #else
  338. Options...
  339. #endif
  340. >::type
  341. {
  342. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  343. public:
  344. //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
  345. //! initializes the node to an unlinked state.
  346. //!
  347. //! <b>Throws</b>: Nothing.
  348. unordered_set_member_hook();
  349. //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
  350. //! initializes the node to an unlinked state. The argument is ignored.
  351. //!
  352. //! <b>Throws</b>: Nothing.
  353. //!
  354. //! <b>Rationale</b>: Providing a copy-constructor
  355. //! makes classes using the hook STL-compliant without forcing the
  356. //! user to do some additional work. \c swap can be used to emulate
  357. //! move-semantics.
  358. unordered_set_member_hook(const unordered_set_member_hook& );
  359. //! <b>Effects</b>: Empty function. The argument is ignored.
  360. //!
  361. //! <b>Throws</b>: Nothing.
  362. //!
  363. //! <b>Rationale</b>: Providing an assignment operator
  364. //! makes classes using the hook STL-compliant without forcing the
  365. //! user to do some additional work. \c swap can be used to emulate
  366. //! move-semantics.
  367. unordered_set_member_hook& operator=(const unordered_set_member_hook& );
  368. //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
  369. //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
  370. //! object is stored in an unordered_set an assertion is raised. If link_mode is
  371. //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
  372. //!
  373. //! <b>Throws</b>: Nothing.
  374. ~unordered_set_member_hook();
  375. //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
  376. //! related to those nodes in one or two containers. That is, if the node
  377. //! this is part of the element e1, the node x is part of the element e2
  378. //! and both elements are included in the containers s1 and s2, then after
  379. //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
  380. //! at the position of e1. If one element is not in a container, then
  381. //! after the swap-operation the other element is not in a container.
  382. //! Iterators to e1 and e2 related to those nodes are invalidated.
  383. //!
  384. //! <b>Complexity</b>: Constant
  385. //!
  386. //! <b>Throws</b>: Nothing.
  387. void swap_nodes(unordered_set_member_hook &other);
  388. //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
  389. //!
  390. //! <b>Returns</b>: true, if the node belongs to a container, false
  391. //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
  392. //! will return a valid iterator.
  393. //!
  394. //! <b>Complexity</b>: Constant
  395. bool is_linked() const;
  396. //! <b>Effects</b>: Removes the node if it's inserted in a container.
  397. //! This function is only allowed if link_mode is \c auto_unlink.
  398. //!
  399. //! <b>Throws</b>: Nothing.
  400. void unlink();
  401. #endif
  402. };
  403. } //namespace intrusive
  404. } //namespace boost
  405. #include <boost/intrusive/detail/config_end.hpp>
  406. #endif //BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP