1 /////////////////////////////////////////////////////////////////////////////
\r
3 // (C) Copyright Olaf Krzikalla 2004-2006.
\r
4 // (C) Copyright Ion GaztaƱaga 2006-2007
\r
6 // Distributed under the Boost Software License, Version 1.0.
\r
7 // (See accompanying file LICENSE_1_0.txt or copy at
\r
8 // http://www.boost.org/LICENSE_1_0.txt)
\r
10 // See http://www.boost.org/libs/intrusive for documentation.
\r
12 /////////////////////////////////////////////////////////////////////////////
\r
14 #ifndef BOOST_INTRUSIVE_IHASHSET_HOOK_HPP
\r
15 #define BOOST_INTRUSIVE_IHASHSET_HOOK_HPP
\r
17 #include "detail/config_begin.hpp"
\r
18 #include "detail/utilities.hpp"
\r
19 #include "detail/pointer_type.hpp"
\r
20 #include "detail/pointer_to_other.hpp"
\r
21 #include "islist_hook.hpp"
\r
22 #include "linking_policy.hpp"
\r
23 #include <boost/get_pointer.hpp>
\r
24 #include <stdexcept>
\r
27 namespace intrusive {
\r
29 //! Derive a class from iunordered_set_base_hook in order to store objects in
\r
30 //! in an iunordered_set/iunordered_multi_set. iunordered_set_base_hook holds the data necessary to maintain
\r
31 //! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for iunordered_set/iunordered_multi_set.
\r
33 //! The first integer template argument defines a tag to identify the node.
\r
34 //! The same tag value can be used in different classes, but if a class is
\r
35 //! derived from more than one iunordered_set_base_hook, then each iunordered_set_base_hook needs its
\r
38 //! The second boolean template parameter will activate the safe-mode checks
\r
39 //! if it's configured as "true".
\r
41 //! The third argument is the pointer type that will be used internally in the hook
\r
42 //! and the iunordered_set/iunordered_multi_set configured from this hook.
\r
43 template<typename Tag, bool SafeMode = true, class VoidPointer = void*>
\r
44 class iunordered_set_base_hook
\r
46 typedef islist_base_hook<Tag, SafeMode, VoidPointer> IsListHook;
\r
47 IsListHook m_islisthook;
\r
48 typedef IsListHook implementation_defined;
\r
51 enum { linking_policy = SafeMode? safe_mode_link : normal_link};
\r
52 typedef typename implementation_defined::node_traits node_traits;
\r
53 typedef typename node_traits::node node;
\r
54 typedef typename boost::pointer_to_other
\r
55 <VoidPointer, node>::type node_ptr;
\r
56 typedef typename boost::pointer_to_other
\r
57 <VoidPointer, const node>::type const_node_ptr;
\r
58 typedef iunordered_set_base_hook
\r
59 <Tag, SafeMode, VoidPointer> this_type;
\r
60 typedef typename boost::pointer_to_other
\r
61 <VoidPointer, this_type>::type this_type_ptr;
\r
62 typedef typename boost::pointer_to_other
\r
63 <VoidPointer, const this_type>::type const_this_type_ptr;
\r
65 //! <b>Effects</b>: If SafeMode is true initializes the node
\r
66 //! to an unlinked state.
\r
68 //! <b>Throws</b>: Nothing.
\r
69 iunordered_set_base_hook()
\r
73 //! <b>Effects</b>: If SafeMode is true initializes the node
\r
74 //! to an unlinked state. The argument is ignored.
\r
76 //! <b>Throws</b>: Nothing.
\r
78 //! <b>Rationale</b>: Providing a copy-constructor
\r
79 //! makes classes using iunordered_set_base_hook STL-compliant without forcing the
\r
80 //! user to do some additional work. "swap" can be used to emulate
\r
82 iunordered_set_base_hook(const iunordered_set_base_hook &other)
\r
83 : m_islisthook(other.m_islisthook)
\r
86 //! <b>Effects</b>: If SafeMode is true, an assertion is raised
\r
87 //! if the node is still linked. After that, the node is initialized
\r
88 //! to an unlinked state. The argument is ignored.
\r
90 //! <b>Throws</b>: Nothing.
\r
92 //! <b>Rationale</b>: Providing an assignment operator
\r
93 //! makes classes using iunordered_set_base_hook STL-compliant without forcing the
\r
94 //! user to do some additional work. "swap" can be used to emulate
\r
96 iunordered_set_base_hook& operator=(const iunordered_set_base_hook &other)
\r
97 { m_islisthook = other.m_islisthook; return *this; }
\r
99 //! <b>Effects</b>: If SafeMode is set to false, the destructor does
\r
100 //! nothing (ie. no code is generated). If SafeMode is true and the
\r
101 //! object is stored in an iunordered_set/iunordered_multiset an assertion is raised.
\r
103 //! <b>Throws</b>: Nothing.
\r
104 ~iunordered_set_base_hook()
\r
107 //! <b>Precondition</b>: The hook must be in safe-mode.
\r
109 //! <b>Returns</b>: true, if the node belongs to a container, false
\r
110 //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current
\r
111 //! will return a valid iterator.
\r
113 //! <b>Complexity</b>: Constant
\r
114 bool linked() const
\r
115 { return m_islisthook.linked(); }
\r
117 //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset.
\r
118 //! The template argument T defines the class type stored in iunordered_set/iunordered_multiset. Objects
\r
119 //! of type T and of types derived from T can be stored. T doesn't need to be
\r
120 //! copy-constructible or assignable.
\r
122 struct value_traits
\r
123 : detail::derivation_value_traits<T, this_type, Tag>
\r
126 //! <b>Effects</b>: Converts a pointer to a node into
\r
127 //! a pointer to the hook that holds that node.
\r
129 //! <b>Throws</b>: Nothing.
\r
130 static this_type_ptr to_hook_ptr(node_ptr p)
\r
132 using boost::get_pointer;
\r
133 return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
136 //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
\r
137 //! a const pointer to the hook that holds that node.
\r
139 //! <b>Throws</b>: Nothing.
\r
140 static const_this_type_ptr to_hook_ptr(const_node_ptr p)
\r
142 using boost::get_pointer;
\r
143 return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
146 //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
\r
148 //! <b>Throws</b>: Nothing.
\r
149 node_ptr to_node_ptr()
\r
150 { return m_islisthook.to_node_ptr(); }
\r
152 //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
\r
154 //! <b>Throws</b>: Nothing.
\r
155 const_node_ptr to_node_ptr() const
\r
156 { return m_islisthook.to_node_ptr(); }
\r
160 //! Derive a class from iunordered_set_auto_base_hook in order to store objects in an
\r
161 //! iunordered_set/iunordered_multi_set. iunordered_set_auto_base_hook holds the data necessary to maintain the
\r
162 //! unordered_set and provides an appropriate value_traits class for iunordered_set/iunordered_multi_set.
\r
164 //! The difference between iunordered_set_auto_base_hook and iunordered_set_base_hook is that
\r
165 //! iunordered_set_auto_base_hook removes itself automatically from the container
\r
166 //! in the assignment operator and the destructor. It also provides a new
\r
167 //! "unlink" method so that the user can unlink its class without using
\r
170 //! iunordered_set_auto_base_hook can only be used with non constant-time iunordered_set/iunordered_multi_sets.
\r
172 //! The first integer template argument defines a tag to identify the node.
\r
173 //! The same tag value can be used in different classes, but if a class is
\r
174 //! derived from more than one iunordered_set_auto_base_hook, then each iunordered_set_auto_base_hook needs its
\r
177 //! The second argument is the pointer type that will be used internally in the hook
\r
178 //! and the iunordered_set/unordered_multi_set configured from this hook.
\r
179 template<typename Tag, class VoidPointer = void*>
\r
180 class iunordered_set_auto_base_hook
\r
182 typedef islist_auto_base_hook<Tag, VoidPointer> IsListHook;
\r
183 IsListHook m_islisthook;
\r
184 typedef IsListHook implementation_defined;
\r
187 enum { linking_policy = auto_unlink };
\r
188 typedef typename implementation_defined::node_traits node_traits;
\r
189 typedef typename node_traits::node node;
\r
190 typedef typename boost::pointer_to_other
\r
191 <VoidPointer, node>::type node_ptr;
\r
192 typedef typename boost::pointer_to_other
\r
193 <VoidPointer, const node>::type const_node_ptr;
\r
194 typedef iunordered_set_auto_base_hook
\r
195 <Tag,VoidPointer> this_type;
\r
196 typedef typename boost::pointer_to_other
\r
197 <VoidPointer, this_type>::type this_type_ptr;
\r
198 typedef typename boost::pointer_to_other
\r
199 <VoidPointer, const this_type>::type const_this_type_ptr;
\r
203 //! <b>Effects</b>: Initializes the node
\r
204 //! to an unlinked state.
\r
206 //! <b>Throws</b>: Nothing.
\r
207 iunordered_set_auto_base_hook()
\r
211 //! <b>Effects</b>: Initializes the node
\r
212 //! to an unlinked state. The argument is ignored.
\r
214 //! <b>Throws</b>: Nothing.
\r
216 //! <b>Rationale</b>: Providing a copy-constructor
\r
217 //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the
\r
218 //! user to do some additional work.
\r
219 iunordered_set_auto_base_hook(const iunordered_set_auto_base_hook &other)
\r
220 : m_islisthook(other.m_islisthook)
\r
223 //! <b>Effects</b>: Removes the node if it's inserted in a container.
\r
224 //! The argument is ignored.
\r
226 //! <b>Throws</b>: Nothing.
\r
228 //! <b>Rationale</b>: Providing an assignment operator
\r
229 //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the
\r
230 //! user to do some additional work.
\r
231 iunordered_set_auto_base_hook& operator=(const iunordered_set_auto_base_hook &other)
\r
232 { m_islisthook = other.m_islisthook; return *this; }
\r
234 //! <b>Effects</b>: Removes the node if it's inserted in a container.
\r
236 //! <b>Throws</b>: Nothing.
\r
237 ~iunordered_set_auto_base_hook()
\r
240 //! <b>Returns</b>: true, if the node belongs to a container, false
\r
241 //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current
\r
242 //! will return a valid iterator.
\r
244 //! <b>Complexity</b>: Constant
\r
245 bool linked() const
\r
246 { return m_islisthook.linked(); }
\r
248 //! <b>Effects</b>: Removes the node if it's inserted in a container.
\r
250 //! <b>Throws</b>: Nothing.
\r
252 { return m_islisthook.unlink(); }
\r
254 //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset.
\r
255 //! The template argument T defines the class type stored in iunordered_set/iunordered_multiset. Objects
\r
256 //! of type T and of types derived from T can be stored. T doesn't need to be
\r
257 //! copy-constructible or assignable.
\r
259 struct value_traits
\r
260 : detail::derivation_value_traits<T, this_type, Tag>
\r
263 //! <b>Effects</b>: Converts a pointer to a node into
\r
264 //! a pointer to the hook that holds that node.
\r
266 //! <b>Throws</b>: Nothing.
\r
267 static this_type_ptr to_hook_ptr(node_ptr p)
\r
269 using boost::get_pointer;
\r
270 return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
273 //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
\r
274 //! a const pointer to the hook that holds that node.
\r
276 //! <b>Throws</b>: Nothing.
\r
277 static const_this_type_ptr to_hook_ptr(const_node_ptr p)
\r
279 using boost::get_pointer;
\r
280 return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
283 //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
\r
285 //! <b>Throws</b>: Nothing.
\r
286 node_ptr to_node_ptr()
\r
287 { return m_islisthook.to_node_ptr(); }
\r
289 //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
\r
291 //! <b>Throws</b>: Nothing.
\r
292 const_node_ptr to_node_ptr() const
\r
293 { return m_islisthook.to_node_ptr(); }
\r
297 //! Put a public data member iunordered_set_member_hook in order to store objects of this class in
\r
298 //! an iunordered_set/iunordered_multi_set. iunordered_set_member_hook holds the data necessary for maintaining the
\r
299 //! unordered_set/unordered_multi_set and provides an appropriate value_traits class for iunordered_set/iunordered_multi_set.
\r
301 //! The template argument T defines the class type stored in iunordered_set/iunordered_multi_set. Objects of
\r
302 //! type T and of types derived from T can be stored. T doesn't need to be
\r
303 //! copy-constructible or assignable.
\r
305 //! The second boolean template argument SafeMode controls initializes
\r
306 //! the node to a safe state in the constructor and asserts if the node is destroyed
\r
307 //! or it's assigned but it's still inserted in a iunordered_set/iunordered_multi_set.
\r
309 //! The third argument is the pointer type that will be used internally in the hook
\r
310 //! and the iunordered_set/iunordered_multi_set configured from this hook.
\r
311 template<class T, bool SafeMode = true, class VoidPointer = void*>
\r
312 class iunordered_set_member_hook
\r
314 typedef islist_member_hook<T, SafeMode, VoidPointer> IsListHook;
\r
315 IsListHook m_islisthook;
\r
316 typedef IsListHook implementation_defined;
\r
319 enum { linking_policy = SafeMode? safe_mode_link : normal_link};
\r
320 typedef typename implementation_defined::node_traits node_traits;
\r
321 typedef typename node_traits::node node;
\r
322 typedef typename boost::pointer_to_other
\r
323 <VoidPointer, node>::type node_ptr;
\r
324 typedef typename boost::pointer_to_other
\r
325 <VoidPointer, const node>::type const_node_ptr;
\r
326 typedef iunordered_set_member_hook
\r
327 <T, SafeMode, VoidPointer> this_type;
\r
328 typedef typename boost::pointer_to_other
\r
329 <VoidPointer, this_type>::type this_type_ptr;
\r
330 typedef typename boost::pointer_to_other
\r
331 <VoidPointer, const this_type>::type const_this_type_ptr;
\r
334 //! <b>Effects</b>: If SafeMode is true initializes the node
\r
335 //! to an unlinked state.
\r
337 //! <b>Throws</b>: Nothing.
\r
338 iunordered_set_member_hook()
\r
342 //! <b>Effects</b>: If SafeMode is true initializes the node
\r
343 //! to an unlinked state. The argument is ignored.
\r
345 //! <b>Throws</b>: Nothing.
\r
347 //! <b>Rationale</b>: Providing a copy-constructor
\r
348 //! makes classes using iunordered_set_member_hook STL-compliant without forcing the
\r
349 //! user to do some additional work.
\r
350 iunordered_set_member_hook(const iunordered_set_member_hook &other)
\r
351 : m_islisthook(other.m_islisthook)
\r
354 //! <b>Effects</b>: If SafeMode is true, an assertion is raised
\r
355 //! if the node is still linked. After that, the node is initialized
\r
356 //! to an unlinked state. The argument is ignored.
\r
358 //! <b>Throws</b>: Nothing.
\r
360 //! <b>Rationale</b>: Providing an assignment operator
\r
361 //! makes classes using iunordered_set_member_hook STL-compliant without forcing the
\r
362 //! user to do some additional work.
\r
363 iunordered_set_member_hook& operator=(const iunordered_set_member_hook &other)
\r
364 { m_islisthook = other.m_islisthook; return *this; }
\r
366 //! <b>Effects</b>: If SafeMode is set to false, the destructor does
\r
367 //! nothing (ie. no code is generated). If SafeMode is true and the
\r
368 //! object is stored in an iunordered_set/iunordered_multiset an assertion is raised.
\r
370 //! <b>Throws</b>: Nothing.
\r
371 ~iunordered_set_member_hook()
\r
374 //! <b>Returns</b>: true, if the node belongs to a container, false
\r
375 //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current
\r
376 //! will return a valid iterator.
\r
378 //! <b>Complexity</b>: Constant
\r
379 bool linked() const
\r
380 { return m_islisthook.linked(); }
\r
382 //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset.
\r
383 //! The template argument is a pointer to member pointing to the node in
\r
384 //! the class. Objects of type T and of types derived from T can be stored.
\r
385 //! T doesn't need to be copy-constructible or assignable.
\r
386 template<this_type T::* M>
\r
387 struct value_traits
\r
388 : detail::member_value_traits<T, this_type, M>
\r
391 //! <b>Effects</b>: Removes the node if it's inserted in a container.
\r
393 //! <b>Throws</b>: Nothing.
\r
395 { m_islisthook.unlink(); }
\r
397 //! <b>Effects</b>: Converts a pointer to a node into
\r
398 //! a pointer to the hook that holds that node.
\r
400 //! <b>Throws</b>: Nothing.
\r
401 static this_type_ptr to_hook_ptr(node_ptr p)
\r
403 using boost::get_pointer;
\r
404 return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
407 //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
\r
408 //! a const pointer to the hook that holds that node.
\r
410 //! <b>Throws</b>: Nothing.
\r
411 static const_this_type_ptr to_hook_ptr(const_node_ptr p)
\r
413 using boost::get_pointer;
\r
414 return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
417 //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
\r
419 //! <b>Throws</b>: Nothing.
\r
420 node_ptr to_node_ptr()
\r
421 { return m_islisthook.to_node_ptr(); }
\r
423 //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
\r
425 //! <b>Throws</b>: Nothing.
\r
426 const_node_ptr to_node_ptr() const
\r
427 { return m_islisthook.to_node_ptr(); }
\r
430 //! Put a public data member iunordered_set_auto_member_hook in order to store objects of this class in
\r
431 //! an iunordered_set/iunordered_multiset. iunordered_set_auto_member_hook holds the data necessary for maintaining the list and
\r
432 //! provides an appropriate value_traits class for iunordered_set/iunordered_multiset.
\r
434 //! The difference between iunordered_set_auto_member_hook and iunordered_set_member_hook is that
\r
435 //! iunordered_set_auto_member_hook removes itself automatically from the container
\r
436 //! in the assignment operator and the destructor. It also provides a new
\r
437 //! "unlink" method so that the user can unlink its class without using
\r
440 //! iunordered_set_auto_member_hook can only be used with non constant-time iunordered_sets/iunordered_multisets.
\r
442 //! The first template argument T defines the class type stored in iunordered_set/iunordered_multiset. Objects of
\r
443 //! type T and of types derived from T can be stored. T doesn't need to be
\r
444 //! copy-constructible or assignable.
\r
446 //! The second argument is the pointer type that will be used internally in the hook
\r
447 //! and the iunordered_set/iunordered_multiset configured from this hook.
\r
448 template<class T, class VoidPointer = void*>
\r
449 class iunordered_set_auto_member_hook
\r
451 typedef islist_auto_member_hook<T, VoidPointer> IsListHook;
\r
452 IsListHook m_islisthook;
\r
453 typedef IsListHook implementation_defined;
\r
456 enum { linking_policy = auto_unlink };
\r
457 typedef typename implementation_defined::node_traits node_traits;
\r
458 typedef typename node_traits::node node;
\r
459 typedef iunordered_set_auto_member_hook
\r
460 <T, VoidPointer> this_type;
\r
461 typedef typename boost::pointer_to_other
\r
462 <VoidPointer, node>::type node_ptr;
\r
463 typedef typename boost::pointer_to_other
\r
464 <VoidPointer, const node>::type const_node_ptr;
\r
465 typedef typename boost::pointer_to_other
\r
466 <VoidPointer, this_type>::type this_type_ptr;
\r
467 typedef typename boost::pointer_to_other
\r
468 <VoidPointer, const this_type>::type const_this_type_ptr;
\r
472 //! <b>Effects</b>: Initializes the node
\r
473 //! to an unlinked state.
\r
475 //! <b>Throws</b>: Nothing.
\r
476 iunordered_set_auto_member_hook()
\r
480 //! <b>Effects</b>: Initializes the node
\r
481 //! to an unlinked state. The argument is ignored.
\r
483 //! <b>Throws</b>: Nothing.
\r
485 //! <b>Rationale</b>: Providing a copy-constructor
\r
486 //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the
\r
487 //! user to do some additional work.
\r
488 iunordered_set_auto_member_hook(const iunordered_set_auto_member_hook &other)
\r
489 : m_islisthook(other.m_islisthook)
\r
492 //! <b>Effects</b>: Removes the node if it's inserted in a container.
\r
493 //! The argument is ignored.
\r
495 //! <b>Throws</b>: Nothing.
\r
497 //! <b>Rationale</b>: Providing an assignment operator
\r
498 //! makes classes using iunordered_set_auto_base_hook STL-compliant without forcing the
\r
499 //! user to do some additional work.
\r
500 iunordered_set_auto_member_hook& operator=(const iunordered_set_auto_member_hook &other)
\r
501 { m_islisthook = other.m_islisthook; return *this; }
\r
503 //! <b>Effects</b>: Removes the node if it's inserted in a container.
\r
505 //! <b>Throws</b>: Nothing.
\r
506 ~iunordered_set_auto_member_hook()
\r
509 //! <b>Returns</b>: true, if the node belongs to a container, false
\r
510 //! otherwise. This function can be used to test whether iunordered_set/iunordered_multiset::current
\r
511 //! will return a valid iterator.
\r
513 //! <b>Complexity</b>: Constant
\r
514 bool linked() const
\r
515 { return m_islisthook.linked(); }
\r
517 //! <b>Effects</b>: Removes the node if it's inserted in a container.
\r
519 //! <b>Throws</b>: Nothing.
\r
521 { return m_islisthook.unlink(); }
\r
523 //! The value_traits class is used as the first template argument for iunordered_set/iunordered_multiset.
\r
524 //! The template argument is a pointer to member pointing to the node in
\r
525 //! the class. Objects of type T and of types derived from T can be stored.
\r
526 //! T doesn't need to be copy-constructible or assignable.
\r
527 template<this_type T::* M>
\r
528 struct value_traits
\r
529 : detail::member_value_traits<T, this_type, M>
\r
532 //! <b>Effects</b>: Converts a pointer to a node into
\r
533 //! a pointer to the hook that holds that node.
\r
535 //! <b>Throws</b>: Nothing.
\r
536 static this_type_ptr to_hook_ptr(node_ptr p)
\r
538 using boost::get_pointer;
\r
539 return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
542 //! <b>Effects</b>: Converts a const pointer to a node stored in a container into
\r
543 //! a const pointer to the hook that holds that node.
\r
545 //! <b>Throws</b>: Nothing.
\r
546 static const_this_type_ptr to_hook_ptr(const_node_ptr p)
\r
548 using boost::get_pointer;
\r
549 return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p)));
\r
552 //! <b>Effects</b>: Returns a pointer to the node that this hook holds.
\r
554 //! <b>Throws</b>: Nothing.
\r
555 node_ptr to_node_ptr()
\r
556 { return m_islisthook.to_node_ptr(); }
\r
558 //! <b>Effects</b>: Returns a const pointer to the node that this hook holds.
\r
560 //! <b>Throws</b>: Nothing.
\r
561 const_node_ptr to_node_ptr() const
\r
562 { return m_islisthook.to_node_ptr(); }
\r
565 } //namespace intrusive
\r
566 } //namespace boost
\r
568 #include "detail/config_end.hpp"
\r
570 #endif //BOOST_INTRUSIVE_IHASHSET_HOOK_HPP
\r