Chris@16
|
1 // boost heap: heap node helper classes
|
Chris@16
|
2 //
|
Chris@16
|
3 // Copyright (C) 2010 Tim Blechmann
|
Chris@16
|
4 //
|
Chris@16
|
5 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
6 // 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 #ifndef BOOST_HEAP_DETAIL_HEAP_NODE_HPP
|
Chris@16
|
10 #define BOOST_HEAP_DETAIL_HEAP_NODE_HPP
|
Chris@16
|
11
|
Chris@16
|
12 #include <boost/assert.hpp>
|
Chris@16
|
13 #include <boost/static_assert.hpp>
|
Chris@16
|
14 #include <boost/intrusive/list.hpp>
|
Chris@16
|
15 #include <boost/mpl/if.hpp>
|
Chris@16
|
16
|
Chris@16
|
17 #ifdef BOOST_HEAP_SANITYCHECKS
|
Chris@16
|
18 #define BOOST_HEAP_ASSERT BOOST_ASSERT
|
Chris@16
|
19 #else
|
Chris@16
|
20 #define BOOST_HEAP_ASSERT(expression)
|
Chris@16
|
21 #endif
|
Chris@16
|
22
|
Chris@16
|
23
|
Chris@16
|
24 namespace boost {
|
Chris@16
|
25 namespace heap {
|
Chris@16
|
26 namespace detail {
|
Chris@16
|
27
|
Chris@16
|
28 namespace bi = boost::intrusive;
|
Chris@16
|
29 namespace mpl = boost::mpl;
|
Chris@16
|
30
|
Chris@16
|
31 template <bool auto_unlink = false>
|
Chris@16
|
32 struct heap_node_base:
|
Chris@16
|
33 bi::list_base_hook<typename mpl::if_c<auto_unlink,
|
Chris@16
|
34 bi::link_mode<bi::auto_unlink>,
|
Chris@16
|
35 bi::link_mode<bi::safe_link>
|
Chris@16
|
36 >::type
|
Chris@16
|
37 >
|
Chris@16
|
38 {};
|
Chris@16
|
39
|
Chris@16
|
40 typedef bi::list<heap_node_base<false> > heap_node_list;
|
Chris@16
|
41
|
Chris@16
|
42 struct nop_disposer
|
Chris@16
|
43 {
|
Chris@16
|
44 template <typename T>
|
Chris@16
|
45 void operator()(T * n)
|
Chris@16
|
46 {
|
Chris@16
|
47 BOOST_HEAP_ASSERT(false);
|
Chris@16
|
48 }
|
Chris@16
|
49 };
|
Chris@16
|
50
|
Chris@16
|
51 template <typename Node, typename HeapBase>
|
Chris@16
|
52 bool is_heap(const Node * n, typename HeapBase::value_compare const & cmp)
|
Chris@16
|
53 {
|
Chris@16
|
54 for (typename Node::const_child_iterator it = n->children.begin(); it != n->children.end(); ++it) {
|
Chris@16
|
55 Node const & this_node = static_cast<Node const &>(*it);
|
Chris@16
|
56 const Node * child = static_cast<const Node*>(&this_node);
|
Chris@16
|
57
|
Chris@16
|
58 if (cmp(HeapBase::get_value(n->value), HeapBase::get_value(child->value)) ||
|
Chris@16
|
59 !is_heap<Node, HeapBase>(child, cmp))
|
Chris@16
|
60 return false;
|
Chris@16
|
61 }
|
Chris@16
|
62 return true;
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 template <typename Node>
|
Chris@16
|
66 std::size_t count_nodes(const Node * n);
|
Chris@16
|
67
|
Chris@16
|
68 template <typename Node, typename List>
|
Chris@16
|
69 std::size_t count_list_nodes(List const & node_list)
|
Chris@16
|
70 {
|
Chris@16
|
71 std::size_t ret = 0;
|
Chris@16
|
72
|
Chris@16
|
73 for (typename List::const_iterator it = node_list.begin(); it != node_list.end(); ++it) {
|
Chris@16
|
74 const Node * child = static_cast<const Node*>(&*it);
|
Chris@16
|
75 ret += count_nodes<Node>(child);
|
Chris@16
|
76 }
|
Chris@16
|
77 return ret;
|
Chris@16
|
78 }
|
Chris@16
|
79
|
Chris@16
|
80 template <typename Node>
|
Chris@16
|
81 std::size_t count_nodes(const Node * n)
|
Chris@16
|
82 {
|
Chris@16
|
83 return 1 + count_list_nodes<Node, typename Node::child_list>(n->children);
|
Chris@16
|
84 }
|
Chris@16
|
85
|
Chris@16
|
86
|
Chris@16
|
87 /* node cloner
|
Chris@16
|
88 *
|
Chris@16
|
89 * Requires `Clone Constructor':
|
Chris@16
|
90 * template <typename Alloc>
|
Chris@16
|
91 * Node::Node(Node const &, Alloc &)
|
Chris@16
|
92 *
|
Chris@16
|
93 * template <typename Alloc>
|
Chris@16
|
94 * Node::Node(Node const &, Alloc &, Node * parent)
|
Chris@16
|
95 *
|
Chris@16
|
96 * */
|
Chris@16
|
97 template <typename Node,
|
Chris@16
|
98 typename NodeBase,
|
Chris@16
|
99 typename Alloc>
|
Chris@16
|
100 struct node_cloner
|
Chris@16
|
101 {
|
Chris@16
|
102 node_cloner(Alloc & allocator):
|
Chris@16
|
103 allocator(allocator)
|
Chris@16
|
104 {}
|
Chris@16
|
105
|
Chris@16
|
106 Node * operator() (NodeBase const & node)
|
Chris@16
|
107 {
|
Chris@16
|
108 Node * ret = allocator.allocate(1);
|
Chris@16
|
109 new (ret) Node(static_cast<Node const &>(node), allocator);
|
Chris@16
|
110 return ret;
|
Chris@16
|
111 }
|
Chris@16
|
112
|
Chris@16
|
113 Node * operator() (NodeBase const & node, Node * parent)
|
Chris@16
|
114 {
|
Chris@16
|
115 Node * ret = allocator.allocate(1);
|
Chris@16
|
116 new (ret) Node(static_cast<Node const &>(node), allocator, parent);
|
Chris@16
|
117 return ret;
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 private:
|
Chris@16
|
121 Alloc & allocator;
|
Chris@16
|
122 };
|
Chris@16
|
123
|
Chris@16
|
124 /* node disposer
|
Chris@16
|
125 *
|
Chris@16
|
126 * Requirements:
|
Chris@16
|
127 * Node::clear_subtree(Alloc &) clears the subtree via allocator
|
Chris@16
|
128 *
|
Chris@16
|
129 * */
|
Chris@16
|
130 template <typename Node,
|
Chris@16
|
131 typename NodeBase,
|
Chris@16
|
132 typename Alloc>
|
Chris@16
|
133 struct node_disposer
|
Chris@16
|
134 {
|
Chris@16
|
135 typedef typename Alloc::pointer node_pointer;
|
Chris@16
|
136
|
Chris@16
|
137 node_disposer(Alloc & alloc):
|
Chris@16
|
138 alloc_(alloc)
|
Chris@16
|
139 {}
|
Chris@16
|
140
|
Chris@16
|
141 void operator()(NodeBase * base)
|
Chris@16
|
142 {
|
Chris@16
|
143 node_pointer n = static_cast<node_pointer>(base);
|
Chris@16
|
144 n->clear_subtree(alloc_);
|
Chris@16
|
145 alloc_.destroy(n);
|
Chris@16
|
146 alloc_.deallocate(n, 1);
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 Alloc & alloc_;
|
Chris@16
|
150 };
|
Chris@16
|
151
|
Chris@16
|
152
|
Chris@16
|
153 template <typename ValueType,
|
Chris@16
|
154 bool constant_time_child_size = true
|
Chris@16
|
155 >
|
Chris@16
|
156 struct heap_node:
|
Chris@16
|
157 heap_node_base<!constant_time_child_size>
|
Chris@16
|
158 {
|
Chris@16
|
159 typedef heap_node_base<!constant_time_child_size> node_base;
|
Chris@16
|
160
|
Chris@16
|
161 public:
|
Chris@16
|
162 typedef ValueType value_type;
|
Chris@16
|
163
|
Chris@16
|
164 typedef bi::list<node_base,
|
Chris@16
|
165 bi::constant_time_size<constant_time_child_size> > child_list;
|
Chris@16
|
166
|
Chris@16
|
167 typedef typename child_list::iterator child_iterator;
|
Chris@16
|
168 typedef typename child_list::const_iterator const_child_iterator;
|
Chris@16
|
169 typedef typename child_list::size_type size_type;
|
Chris@16
|
170
|
Chris@16
|
171 heap_node(ValueType const & v):
|
Chris@16
|
172 value(v)
|
Chris@16
|
173 {}
|
Chris@16
|
174
|
Chris@16
|
175 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
176 template <class... Args>
|
Chris@16
|
177 heap_node(Args&&... args):
|
Chris@16
|
178 value(std::forward<Args>(args)...)
|
Chris@16
|
179 {}
|
Chris@16
|
180 #endif
|
Chris@16
|
181
|
Chris@16
|
182 /* protected: */
|
Chris@16
|
183 heap_node(heap_node const & rhs):
|
Chris@16
|
184 value(rhs.value)
|
Chris@16
|
185 {
|
Chris@16
|
186 /* we don't copy the child list, but clone it later */
|
Chris@16
|
187 }
|
Chris@16
|
188
|
Chris@16
|
189 public:
|
Chris@16
|
190
|
Chris@16
|
191 template <typename Alloc>
|
Chris@16
|
192 heap_node (heap_node const & rhs, Alloc & allocator):
|
Chris@16
|
193 value(rhs.value)
|
Chris@16
|
194 {
|
Chris@16
|
195 children.clone_from(rhs.children, node_cloner<heap_node, node_base, Alloc>(allocator), nop_disposer());
|
Chris@16
|
196 }
|
Chris@16
|
197
|
Chris@16
|
198 size_type child_count(void) const
|
Chris@16
|
199 {
|
Chris@16
|
200 BOOST_STATIC_ASSERT(constant_time_child_size);
|
Chris@16
|
201 return children.size();
|
Chris@16
|
202 }
|
Chris@16
|
203
|
Chris@16
|
204 void add_child(heap_node * n)
|
Chris@16
|
205 {
|
Chris@16
|
206 children.push_back(*n);
|
Chris@16
|
207 }
|
Chris@16
|
208
|
Chris@16
|
209 template <typename Alloc>
|
Chris@16
|
210 void clear_subtree(Alloc & alloc)
|
Chris@16
|
211 {
|
Chris@16
|
212 children.clear_and_dispose(node_disposer<heap_node, node_base, Alloc>(alloc));
|
Chris@16
|
213 }
|
Chris@16
|
214
|
Chris@16
|
215 void swap_children(heap_node * rhs)
|
Chris@16
|
216 {
|
Chris@16
|
217 children.swap(rhs->children);
|
Chris@16
|
218 }
|
Chris@16
|
219
|
Chris@16
|
220 ValueType value;
|
Chris@16
|
221 child_list children;
|
Chris@16
|
222 };
|
Chris@16
|
223
|
Chris@16
|
224 template <typename value_type>
|
Chris@16
|
225 struct parent_pointing_heap_node:
|
Chris@16
|
226 heap_node<value_type>
|
Chris@16
|
227 {
|
Chris@16
|
228 typedef heap_node<value_type> super_t;
|
Chris@16
|
229
|
Chris@16
|
230 parent_pointing_heap_node(value_type const & v):
|
Chris@16
|
231 super_t(v), parent(NULL)
|
Chris@16
|
232 {}
|
Chris@16
|
233
|
Chris@16
|
234 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
235 template <class... Args>
|
Chris@16
|
236 parent_pointing_heap_node(Args&&... args):
|
Chris@16
|
237 super_t(std::forward<Args>(args)...), parent(NULL)
|
Chris@16
|
238 {}
|
Chris@16
|
239 #endif
|
Chris@16
|
240
|
Chris@16
|
241 template <typename Alloc>
|
Chris@16
|
242 struct node_cloner
|
Chris@16
|
243 {
|
Chris@16
|
244 node_cloner(Alloc & allocator, parent_pointing_heap_node * parent):
|
Chris@16
|
245 allocator(allocator), parent_(parent)
|
Chris@16
|
246 {}
|
Chris@16
|
247
|
Chris@16
|
248 parent_pointing_heap_node * operator() (typename super_t::node_base const & node)
|
Chris@16
|
249 {
|
Chris@16
|
250 parent_pointing_heap_node * ret = allocator.allocate(1);
|
Chris@16
|
251 new (ret) parent_pointing_heap_node(static_cast<parent_pointing_heap_node const &>(node), allocator, parent_);
|
Chris@16
|
252 return ret;
|
Chris@16
|
253 }
|
Chris@16
|
254
|
Chris@16
|
255 private:
|
Chris@16
|
256 Alloc & allocator;
|
Chris@16
|
257 parent_pointing_heap_node * parent_;
|
Chris@16
|
258 };
|
Chris@16
|
259
|
Chris@16
|
260 template <typename Alloc>
|
Chris@16
|
261 parent_pointing_heap_node (parent_pointing_heap_node const & rhs, Alloc & allocator, parent_pointing_heap_node * parent):
|
Chris@16
|
262 super_t(static_cast<super_t const &>(rhs)), parent(parent)
|
Chris@16
|
263 {
|
Chris@16
|
264 super_t::children.clone_from(rhs.children, node_cloner<Alloc>(allocator, this), nop_disposer());
|
Chris@16
|
265 }
|
Chris@16
|
266
|
Chris@16
|
267 void update_children(void)
|
Chris@16
|
268 {
|
Chris@16
|
269 typedef heap_node_list::iterator node_list_iterator;
|
Chris@16
|
270 for (node_list_iterator it = super_t::children.begin(); it != super_t::children.end(); ++it) {
|
Chris@16
|
271 parent_pointing_heap_node * child = static_cast<parent_pointing_heap_node*>(&*it);
|
Chris@16
|
272 child->parent = this;
|
Chris@16
|
273 }
|
Chris@16
|
274 }
|
Chris@16
|
275
|
Chris@16
|
276 void remove_from_parent(void)
|
Chris@16
|
277 {
|
Chris@16
|
278 BOOST_HEAP_ASSERT(parent);
|
Chris@16
|
279 parent->children.erase(heap_node_list::s_iterator_to(*this));
|
Chris@16
|
280 parent = NULL;
|
Chris@16
|
281 }
|
Chris@16
|
282
|
Chris@16
|
283 void add_child(parent_pointing_heap_node * n)
|
Chris@16
|
284 {
|
Chris@16
|
285 BOOST_HEAP_ASSERT(n->parent == NULL);
|
Chris@16
|
286 n->parent = this;
|
Chris@16
|
287 super_t::add_child(n);
|
Chris@16
|
288 }
|
Chris@16
|
289
|
Chris@16
|
290 parent_pointing_heap_node * get_parent(void)
|
Chris@16
|
291 {
|
Chris@16
|
292 return parent;
|
Chris@16
|
293 }
|
Chris@16
|
294
|
Chris@16
|
295 const parent_pointing_heap_node * get_parent(void) const
|
Chris@16
|
296 {
|
Chris@16
|
297 return parent;
|
Chris@16
|
298 }
|
Chris@16
|
299
|
Chris@16
|
300 parent_pointing_heap_node * parent;
|
Chris@16
|
301 };
|
Chris@16
|
302
|
Chris@16
|
303
|
Chris@16
|
304 template <typename value_type>
|
Chris@16
|
305 struct marked_heap_node:
|
Chris@16
|
306 parent_pointing_heap_node<value_type>
|
Chris@16
|
307 {
|
Chris@16
|
308 typedef parent_pointing_heap_node<value_type> super_t;
|
Chris@16
|
309
|
Chris@16
|
310 marked_heap_node(value_type const & v):
|
Chris@16
|
311 super_t(v), mark(false)
|
Chris@16
|
312 {}
|
Chris@16
|
313
|
Chris@16
|
314 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
315 template <class... Args>
|
Chris@16
|
316 marked_heap_node(Args&&... args):
|
Chris@16
|
317 super_t(std::forward<Args>(args)...), mark(false)
|
Chris@16
|
318 {}
|
Chris@16
|
319 #endif
|
Chris@16
|
320
|
Chris@16
|
321 marked_heap_node * get_parent(void)
|
Chris@16
|
322 {
|
Chris@16
|
323 return static_cast<marked_heap_node*>(super_t::parent);
|
Chris@16
|
324 }
|
Chris@16
|
325
|
Chris@16
|
326 const marked_heap_node * get_parent(void) const
|
Chris@16
|
327 {
|
Chris@16
|
328 return static_cast<marked_heap_node*>(super_t::parent);
|
Chris@16
|
329 }
|
Chris@16
|
330
|
Chris@16
|
331 bool mark;
|
Chris@16
|
332 };
|
Chris@16
|
333
|
Chris@16
|
334
|
Chris@16
|
335 template <typename Node>
|
Chris@16
|
336 struct cmp_by_degree
|
Chris@16
|
337 {
|
Chris@16
|
338 template <typename NodeBase>
|
Chris@16
|
339 bool operator()(NodeBase const & left,
|
Chris@16
|
340 NodeBase const & right)
|
Chris@16
|
341 {
|
Chris@16
|
342 return static_cast<const Node*>(&left)->child_count() < static_cast<const Node*>(&right)->child_count();
|
Chris@16
|
343 }
|
Chris@16
|
344 };
|
Chris@16
|
345
|
Chris@16
|
346 template <typename List, typename Node, typename Cmp>
|
Chris@16
|
347 Node * find_max_child(List const & list, Cmp const & cmp)
|
Chris@16
|
348 {
|
Chris@16
|
349 BOOST_HEAP_ASSERT(!list.empty());
|
Chris@16
|
350
|
Chris@16
|
351 const Node * ret = static_cast<const Node *> (&list.front());
|
Chris@16
|
352 for (typename List::const_iterator it = list.begin(); it != list.end(); ++it) {
|
Chris@16
|
353 const Node * current = static_cast<const Node *> (&*it);
|
Chris@16
|
354
|
Chris@16
|
355 if (cmp(ret->value, current->value))
|
Chris@16
|
356 ret = current;
|
Chris@16
|
357 }
|
Chris@16
|
358
|
Chris@16
|
359 return const_cast<Node*>(ret);
|
Chris@16
|
360 }
|
Chris@16
|
361
|
Chris@16
|
362 } /* namespace detail */
|
Chris@16
|
363 } /* namespace heap */
|
Chris@16
|
364 } /* namespace boost */
|
Chris@16
|
365
|
Chris@16
|
366 #undef BOOST_HEAP_ASSERT
|
Chris@16
|
367 #endif /* BOOST_HEAP_DETAIL_HEAP_NODE_HPP */
|