1 /////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Olaf Krzikalla 2004-2006.
4 // (C) Copyright Ion Gaztanaga 2006-2012
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)
10 // See http://www.boost.org/libs/intrusive for documentation.
12 /////////////////////////////////////////////////////////////////////////////
14 #ifndef BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
15 #define BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
17 #include <boost/intrusive/detail/config_begin.hpp>
18 #include <boost/intrusive/intrusive_fwd.hpp>
19 #include <boost/pointer_cast.hpp>
20 #include <boost/intrusive/detail/utilities.hpp>
21 #include <boost/intrusive/pointer_traits.hpp>
22 #include <boost/intrusive/slist_hook.hpp>
23 #include <boost/intrusive/options.hpp>
24 #include <boost/intrusive/pointer_traits.hpp>
25 #include <boost/intrusive/detail/generic_hook.hpp>
32 template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
34 : public slist_node<VoidPointer>
36 typedef typename pointer_traits
37 <VoidPointer>::template rebind_pointer
38 < unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> >::type
40 node_ptr prev_in_group_;
44 template<class VoidPointer>
45 struct unordered_node<VoidPointer, false, true>
46 : public slist_node<VoidPointer>
48 typedef typename pointer_traits
49 <VoidPointer>::template rebind_pointer
50 < unordered_node<VoidPointer, false, true> >::type
52 node_ptr prev_in_group_;
55 template<class VoidPointer>
56 struct unordered_node<VoidPointer, true, false>
57 : public slist_node<VoidPointer>
59 typedef typename pointer_traits
60 <VoidPointer>::template rebind_pointer
61 < unordered_node<VoidPointer, true, false> >::type
66 template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
67 struct unordered_node_traits
68 : public slist_node_traits<VoidPointer>
70 typedef slist_node_traits<VoidPointer> reduced_slist_node_traits;
71 typedef unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> node;
73 typedef typename pointer_traits
74 <VoidPointer>::template rebind_pointer
75 < node >::type node_ptr;
76 typedef typename pointer_traits
77 <VoidPointer>::template rebind_pointer
78 < const node >::type const_node_ptr;
80 static const bool store_hash = StoreHash;
81 static const bool optimize_multikey = OptimizeMultiKey;
83 static node_ptr get_next(const const_node_ptr & n)
85 return pointer_traits<node_ptr>::pointer_to(static_cast<node&>(*n->next_));
88 static void set_next(const node_ptr & n, const node_ptr & next)
91 static node_ptr get_prev_in_group(const const_node_ptr & n)
92 { return n->prev_in_group_; }
94 static void set_prev_in_group(const node_ptr & n, const node_ptr & prev)
95 { n->prev_in_group_ = prev; }
97 static std::size_t get_hash(const const_node_ptr & n)
100 static void set_hash(const node_ptr & n, std::size_t h)
104 template<class NodeTraits>
105 struct unordered_group_adapter
107 typedef typename NodeTraits::node node;
108 typedef typename NodeTraits::node_ptr node_ptr;
109 typedef typename NodeTraits::const_node_ptr const_node_ptr;
111 static node_ptr get_next(const const_node_ptr & n)
112 { return NodeTraits::get_prev_in_group(n); }
114 static void set_next(const node_ptr & n, const node_ptr & next)
115 { NodeTraits::set_prev_in_group(n, next); }
118 template<class NodeTraits>
119 struct unordered_algorithms
120 : public circular_slist_algorithms<NodeTraits>
122 typedef circular_slist_algorithms<NodeTraits> base_type;
123 typedef unordered_group_adapter<NodeTraits> group_traits;
124 typedef circular_slist_algorithms<group_traits> group_algorithms;
126 static void init(typename base_type::node_ptr n)
129 group_algorithms::init(n);
132 static void init_header(typename base_type::node_ptr n)
134 base_type::init_header(n);
135 group_algorithms::init_header(n);
138 static void unlink(typename base_type::node_ptr n)
140 base_type::unlink(n);
141 group_algorithms::unlink(n);
145 template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
146 struct get_uset_node_algo
148 typedef typename detail::if_c
149 < (StoreHash || OptimizeMultiKey)
150 , unordered_node_traits<VoidPointer, StoreHash, OptimizeMultiKey>
151 , slist_node_traits<VoidPointer>
152 >::type node_traits_type;
153 typedef typename detail::if_c
155 , unordered_algorithms<node_traits_type>
156 , circular_slist_algorithms<node_traits_type>
161 //! Helper metafunction to define a \c unordered_set_base_hook that yields to the same
162 //! type when the same options (either explicitly or implicitly) are used.
163 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
164 template<class ...Options>
166 template<class O1 = none, class O2 = none, class O3 = none, class O4 = none>
168 struct make_unordered_set_base_hook
171 typedef typename pack_options
173 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
178 >::type packed_options;
180 typedef detail::generic_hook
181 < get_uset_node_algo<typename packed_options::void_pointer
182 , packed_options::store_hash
183 , packed_options::optimize_multikey
185 , typename packed_options::tag
186 , packed_options::link_mode
187 , detail::UsetBaseHook
188 > implementation_defined;
190 typedef implementation_defined type;
193 //! Derive a class from unordered_set_base_hook in order to store objects in
194 //! in an unordered_set/unordered_multi_set. unordered_set_base_hook holds the data necessary to maintain
195 //! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
197 //! The hook admits the following options: \c tag<>, \c void_pointer<>,
198 //! \c link_mode<>, \c store_hash<> and \c optimize_multikey<>.
200 //! \c tag<> defines a tag to identify the node.
201 //! The same tag value can be used in different classes, but if a class is
202 //! derived from more than one \c list_base_hook, then each \c list_base_hook needs its
205 //! \c void_pointer<> is the pointer type that will be used internally in the hook
206 //! and the the container configured to use this hook.
208 //! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
209 //! \c auto_unlink or \c safe_link).
211 //! \c store_hash<> will tell the hook to store the hash of the value
212 //! to speed up rehashings.
214 //! \c optimize_multikey<> will tell the hook to store a link to form a group
215 //! with other value with the same value to speed up searches and insertions
216 //! in unordered_multisets with a great number of with equivalent keys.
217 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
218 template<class ...Options>
220 template<class O1, class O2, class O3, class O4>
222 class unordered_set_base_hook
223 : public make_unordered_set_base_hook<
224 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
231 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
233 //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
234 //! initializes the node to an unlinked state.
236 //! <b>Throws</b>: Nothing.
237 unordered_set_base_hook();
239 //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
240 //! initializes the node to an unlinked state. The argument is ignored.
242 //! <b>Throws</b>: Nothing.
244 //! <b>Rationale</b>: Providing a copy-constructor
245 //! makes classes using the hook STL-compliant without forcing the
246 //! user to do some additional work. \c swap can be used to emulate
248 unordered_set_base_hook(const unordered_set_base_hook& );
250 //! <b>Effects</b>: Empty function. The argument is ignored.
252 //! <b>Throws</b>: Nothing.
254 //! <b>Rationale</b>: Providing an assignment operator
255 //! makes classes using the hook STL-compliant without forcing the
256 //! user to do some additional work. \c swap can be used to emulate
258 unordered_set_base_hook& operator=(const unordered_set_base_hook& );
260 //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
261 //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
262 //! object is stored in an unordered_set an assertion is raised. If link_mode is
263 //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
265 //! <b>Throws</b>: Nothing.
266 ~unordered_set_base_hook();
268 //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
269 //! related to those nodes in one or two containers. That is, if the node
270 //! this is part of the element e1, the node x is part of the element e2
271 //! and both elements are included in the containers s1 and s2, then after
272 //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
273 //! at the position of e1. If one element is not in a container, then
274 //! after the swap-operation the other element is not in a container.
275 //! Iterators to e1 and e2 related to those nodes are invalidated.
277 //! <b>Complexity</b>: Constant
279 //! <b>Throws</b>: Nothing.
280 void swap_nodes(unordered_set_base_hook &other);
282 //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
284 //! <b>Returns</b>: true, if the node belongs to a container, false
285 //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
286 //! will return a valid iterator.
288 //! <b>Complexity</b>: Constant
289 bool is_linked() const;
291 //! <b>Effects</b>: Removes the node if it's inserted in a container.
292 //! This function is only allowed if link_mode is \c auto_unlink.
294 //! <b>Throws</b>: Nothing.
300 //! Helper metafunction to define a \c unordered_set_member_hook that yields to the same
301 //! type when the same options (either explicitly or implicitly) are used.
302 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
303 template<class ...Options>
305 template<class O1 = none, class O2 = none, class O3 = none, class O4 = none>
307 struct make_unordered_set_member_hook
310 typedef typename pack_options
312 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
317 >::type packed_options;
319 typedef detail::generic_hook
320 < get_uset_node_algo< typename packed_options::void_pointer
321 , packed_options::store_hash
322 , packed_options::optimize_multikey
325 , packed_options::link_mode
327 > implementation_defined;
329 typedef implementation_defined type;
332 //! Put a public data member unordered_set_member_hook in order to store objects of this class in
333 //! an unordered_set/unordered_multi_set. unordered_set_member_hook holds the data necessary for maintaining the
334 //! unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
336 //! The hook admits the following options: \c void_pointer<>,
337 //! \c link_mode<> and \c store_hash<>.
339 //! \c void_pointer<> is the pointer type that will be used internally in the hook
340 //! and the the container configured to use this hook.
342 //! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
343 //! \c auto_unlink or \c safe_link).
345 //! \c store_hash<> will tell the hook to store the hash of the value
346 //! to speed up rehashings.
347 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
348 template<class ...Options>
350 template<class O1, class O2, class O3, class O4>
352 class unordered_set_member_hook
353 : public make_unordered_set_member_hook<
354 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
361 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
363 //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
364 //! initializes the node to an unlinked state.
366 //! <b>Throws</b>: Nothing.
367 unordered_set_member_hook();
369 //! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
370 //! initializes the node to an unlinked state. The argument is ignored.
372 //! <b>Throws</b>: Nothing.
374 //! <b>Rationale</b>: Providing a copy-constructor
375 //! makes classes using the hook STL-compliant without forcing the
376 //! user to do some additional work. \c swap can be used to emulate
378 unordered_set_member_hook(const unordered_set_member_hook& );
380 //! <b>Effects</b>: Empty function. The argument is ignored.
382 //! <b>Throws</b>: Nothing.
384 //! <b>Rationale</b>: Providing an assignment operator
385 //! makes classes using the hook STL-compliant without forcing the
386 //! user to do some additional work. \c swap can be used to emulate
388 unordered_set_member_hook& operator=(const unordered_set_member_hook& );
390 //! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
391 //! nothing (ie. no code is generated). If link_mode is \c safe_link and the
392 //! object is stored in an unordered_set an assertion is raised. If link_mode is
393 //! \c auto_unlink and \c is_linked() is true, the node is unlinked.
395 //! <b>Throws</b>: Nothing.
396 ~unordered_set_member_hook();
398 //! <b>Effects</b>: Swapping two nodes swaps the position of the elements
399 //! related to those nodes in one or two containers. That is, if the node
400 //! this is part of the element e1, the node x is part of the element e2
401 //! and both elements are included in the containers s1 and s2, then after
402 //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
403 //! at the position of e1. If one element is not in a container, then
404 //! after the swap-operation the other element is not in a container.
405 //! Iterators to e1 and e2 related to those nodes are invalidated.
407 //! <b>Complexity</b>: Constant
409 //! <b>Throws</b>: Nothing.
410 void swap_nodes(unordered_set_member_hook &other);
412 //! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
414 //! <b>Returns</b>: true, if the node belongs to a container, false
415 //! otherwise. This function can be used to test whether \c unordered_set::iterator_to
416 //! will return a valid iterator.
418 //! <b>Complexity</b>: Constant
419 bool is_linked() const;
421 //! <b>Effects</b>: Removes the node if it's inserted in a container.
422 //! This function is only allowed if link_mode is \c auto_unlink.
424 //! <b>Throws</b>: Nothing.
429 } //namespace intrusive
432 #include <boost/intrusive/detail/config_end.hpp>
434 #endif //BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP