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