Chris@16
|
1 /////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 //
|
Chris@101
|
3 // (C) Copyright Ion Gaztanaga 2007-2014
|
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_BSTREE_ALGORITHMS_HPP
|
Chris@16
|
14 #define BOOST_INTRUSIVE_BSTREE_ALGORITHMS_HPP
|
Chris@16
|
15
|
Chris@101
|
16 #include <cstddef>
|
Chris@16
|
17 #include <boost/intrusive/detail/config_begin.hpp>
|
Chris@101
|
18 #include <boost/intrusive/intrusive_fwd.hpp>
|
Chris@101
|
19 #include <boost/intrusive/detail/bstree_algorithms_base.hpp>
|
Chris@16
|
20 #include <boost/intrusive/detail/assert.hpp>
|
Chris@101
|
21 #include <boost/intrusive/detail/uncast.hpp>
|
Chris@101
|
22 #include <boost/intrusive/detail/math.hpp>
|
Chris@101
|
23 #include <boost/intrusive/detail/algo_type.hpp>
|
Chris@101
|
24
|
Chris@101
|
25 #include <boost/intrusive/detail/minimal_pair_header.hpp>
|
Chris@101
|
26
|
Chris@101
|
27 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@101
|
28 # pragma once
|
Chris@101
|
29 #endif
|
Chris@16
|
30
|
Chris@16
|
31 namespace boost {
|
Chris@16
|
32 namespace intrusive {
|
Chris@16
|
33
|
Chris@16
|
34 /// @cond
|
Chris@16
|
35
|
Chris@16
|
36 //! This type is the information that will be filled by insert_unique_check
|
Chris@16
|
37 template <class NodePtr>
|
Chris@16
|
38 struct insert_commit_data_t
|
Chris@16
|
39 {
|
Chris@16
|
40 insert_commit_data_t()
|
Chris@16
|
41 : link_left(false)
|
Chris@16
|
42 , node()
|
Chris@16
|
43 {}
|
Chris@16
|
44 bool link_left;
|
Chris@16
|
45 NodePtr node;
|
Chris@16
|
46 };
|
Chris@16
|
47
|
Chris@16
|
48 template <class NodePtr>
|
Chris@16
|
49 struct data_for_rebalance_t
|
Chris@16
|
50 {
|
Chris@16
|
51 NodePtr x;
|
Chris@16
|
52 NodePtr x_parent;
|
Chris@16
|
53 NodePtr y;
|
Chris@16
|
54 };
|
Chris@16
|
55
|
Chris@101
|
56 namespace detail {
|
Chris@101
|
57
|
Chris@101
|
58 template<class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
Chris@101
|
59 struct bstree_node_checker
|
Chris@101
|
60 : public ExtraChecker
|
Chris@101
|
61 {
|
Chris@101
|
62 typedef ExtraChecker base_checker_t;
|
Chris@101
|
63 typedef ValueTraits value_traits;
|
Chris@101
|
64 typedef typename value_traits::node_traits node_traits;
|
Chris@101
|
65 typedef typename node_traits::const_node_ptr const_node_ptr;
|
Chris@101
|
66
|
Chris@101
|
67 struct return_type
|
Chris@101
|
68 : public base_checker_t::return_type
|
Chris@101
|
69 {
|
Chris@101
|
70 return_type() : min_key_node_ptr(const_node_ptr()), max_key_node_ptr(const_node_ptr()), node_count(0) {}
|
Chris@101
|
71
|
Chris@101
|
72 const_node_ptr min_key_node_ptr;
|
Chris@101
|
73 const_node_ptr max_key_node_ptr;
|
Chris@101
|
74 size_t node_count;
|
Chris@101
|
75 };
|
Chris@101
|
76
|
Chris@101
|
77 bstree_node_checker(const NodePtrCompare& comp, ExtraChecker extra_checker)
|
Chris@101
|
78 : base_checker_t(extra_checker), comp_(comp)
|
Chris@101
|
79 {}
|
Chris@101
|
80
|
Chris@101
|
81 void operator () (const const_node_ptr& p,
|
Chris@101
|
82 const return_type& check_return_left, const return_type& check_return_right,
|
Chris@101
|
83 return_type& check_return)
|
Chris@101
|
84 {
|
Chris@101
|
85 if (check_return_left.max_key_node_ptr)
|
Chris@101
|
86 BOOST_INTRUSIVE_INVARIANT_ASSERT(!comp_(p, check_return_left.max_key_node_ptr));
|
Chris@101
|
87 if (check_return_right.min_key_node_ptr)
|
Chris@101
|
88 BOOST_INTRUSIVE_INVARIANT_ASSERT(!comp_(check_return_right.min_key_node_ptr, p));
|
Chris@101
|
89 check_return.min_key_node_ptr = node_traits::get_left(p)? check_return_left.min_key_node_ptr : p;
|
Chris@101
|
90 check_return.max_key_node_ptr = node_traits::get_right(p)? check_return_right.max_key_node_ptr : p;
|
Chris@101
|
91 check_return.node_count = check_return_left.node_count + check_return_right.node_count + 1;
|
Chris@101
|
92 base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
|
Chris@101
|
93 }
|
Chris@101
|
94
|
Chris@101
|
95 const NodePtrCompare comp_;
|
Chris@101
|
96 };
|
Chris@101
|
97
|
Chris@101
|
98 } // namespace detail
|
Chris@101
|
99
|
Chris@16
|
100 /// @endcond
|
Chris@16
|
101
|
Chris@16
|
102
|
Chris@16
|
103
|
Chris@16
|
104 //! This is an implementation of a binary search tree.
|
Chris@16
|
105 //! A node in the search tree has references to its children and its parent. This
|
Chris@16
|
106 //! is to allow traversal of the whole tree from a given node making the
|
Chris@16
|
107 //! implementation of iterator a pointer to a node.
|
Chris@16
|
108 //! At the top of the tree a node is used specially. This node's parent pointer
|
Chris@16
|
109 //! is pointing to the root of the tree. Its left pointer points to the
|
Chris@16
|
110 //! leftmost node in the tree and the right pointer to the rightmost one.
|
Chris@16
|
111 //! This node is used to represent the end-iterator.
|
Chris@16
|
112 //!
|
Chris@16
|
113 //! +---------+
|
Chris@16
|
114 //! header------------------------------>| |
|
Chris@16
|
115 //! | |
|
Chris@16
|
116 //! +----------(left)--------| |--------(right)---------+
|
Chris@16
|
117 //! | +---------+ |
|
Chris@16
|
118 //! | | |
|
Chris@16
|
119 //! | | (parent) |
|
Chris@16
|
120 //! | | |
|
Chris@16
|
121 //! | | |
|
Chris@16
|
122 //! | +---------+ |
|
Chris@16
|
123 //! root of tree ..|......................> | | |
|
Chris@16
|
124 //! | | D | |
|
Chris@16
|
125 //! | | | |
|
Chris@16
|
126 //! | +-------+---------+-------+ |
|
Chris@16
|
127 //! | | | |
|
Chris@16
|
128 //! | | | |
|
Chris@16
|
129 //! | | | |
|
Chris@16
|
130 //! | | | |
|
Chris@16
|
131 //! | | | |
|
Chris@16
|
132 //! | +---------+ +---------+ |
|
Chris@16
|
133 //! | | | | | |
|
Chris@16
|
134 //! | | B | | F | |
|
Chris@16
|
135 //! | | | | | |
|
Chris@16
|
136 //! | +--+---------+--+ +--+---------+--+ |
|
Chris@16
|
137 //! | | | | | |
|
Chris@16
|
138 //! | | | | | |
|
Chris@16
|
139 //! | | | | | |
|
Chris@16
|
140 //! | +---+-----+ +-----+---+ +---+-----+ +-----+---+ |
|
Chris@16
|
141 //! +-->| | | | | | | |<--+
|
Chris@16
|
142 //! | A | | C | | E | | G |
|
Chris@16
|
143 //! | | | | | | | |
|
Chris@16
|
144 //! +---------+ +---------+ +---------+ +---------+
|
Chris@16
|
145 //!
|
Chris@16
|
146 //! bstree_algorithms is configured with a NodeTraits class, which encapsulates the
|
Chris@16
|
147 //! information about the node to be manipulated. NodeTraits must support the
|
Chris@16
|
148 //! following interface:
|
Chris@16
|
149 //!
|
Chris@16
|
150 //! <b>Typedefs</b>:
|
Chris@16
|
151 //!
|
Chris@16
|
152 //! <tt>node</tt>: The type of the node that forms the binary search tree
|
Chris@16
|
153 //!
|
Chris@16
|
154 //! <tt>node_ptr</tt>: A pointer to a node
|
Chris@16
|
155 //!
|
Chris@16
|
156 //! <tt>const_node_ptr</tt>: A pointer to a const node
|
Chris@16
|
157 //!
|
Chris@16
|
158 //! <b>Static functions</b>:
|
Chris@16
|
159 //!
|
Chris@16
|
160 //! <tt>static node_ptr get_parent(const_node_ptr n);</tt>
|
Chris@16
|
161 //!
|
Chris@16
|
162 //! <tt>static void set_parent(node_ptr n, node_ptr parent);</tt>
|
Chris@16
|
163 //!
|
Chris@16
|
164 //! <tt>static node_ptr get_left(const_node_ptr n);</tt>
|
Chris@16
|
165 //!
|
Chris@16
|
166 //! <tt>static void set_left(node_ptr n, node_ptr left);</tt>
|
Chris@16
|
167 //!
|
Chris@16
|
168 //! <tt>static node_ptr get_right(const_node_ptr n);</tt>
|
Chris@16
|
169 //!
|
Chris@16
|
170 //! <tt>static void set_right(node_ptr n, node_ptr right);</tt>
|
Chris@16
|
171 template<class NodeTraits>
|
Chris@101
|
172 class bstree_algorithms : public bstree_algorithms_base<NodeTraits>
|
Chris@16
|
173 {
|
Chris@16
|
174 public:
|
Chris@16
|
175 typedef typename NodeTraits::node node;
|
Chris@16
|
176 typedef NodeTraits node_traits;
|
Chris@16
|
177 typedef typename NodeTraits::node_ptr node_ptr;
|
Chris@16
|
178 typedef typename NodeTraits::const_node_ptr const_node_ptr;
|
Chris@16
|
179 typedef insert_commit_data_t<node_ptr> insert_commit_data;
|
Chris@16
|
180 typedef data_for_rebalance_t<node_ptr> data_for_rebalance;
|
Chris@16
|
181
|
Chris@16
|
182 /// @cond
|
Chris@101
|
183 typedef bstree_algorithms<NodeTraits> this_type;
|
Chris@101
|
184 typedef bstree_algorithms_base<NodeTraits> base_type;
|
Chris@16
|
185 private:
|
Chris@16
|
186 template<class Disposer>
|
Chris@16
|
187 struct dispose_subtree_disposer
|
Chris@16
|
188 {
|
Chris@16
|
189 dispose_subtree_disposer(Disposer &disp, const node_ptr & subtree)
|
Chris@16
|
190 : disposer_(&disp), subtree_(subtree)
|
Chris@16
|
191 {}
|
Chris@16
|
192
|
Chris@16
|
193 void release()
|
Chris@16
|
194 { disposer_ = 0; }
|
Chris@16
|
195
|
Chris@16
|
196 ~dispose_subtree_disposer()
|
Chris@16
|
197 {
|
Chris@16
|
198 if(disposer_){
|
Chris@16
|
199 dispose_subtree(subtree_, *disposer_);
|
Chris@16
|
200 }
|
Chris@16
|
201 }
|
Chris@16
|
202 Disposer *disposer_;
|
Chris@16
|
203 const node_ptr subtree_;
|
Chris@16
|
204 };
|
Chris@16
|
205
|
Chris@16
|
206 /// @endcond
|
Chris@16
|
207
|
Chris@16
|
208 public:
|
Chris@16
|
209 //! <b>Requires</b>: 'header' is the header node of a tree.
|
Chris@16
|
210 //!
|
Chris@16
|
211 //! <b>Effects</b>: Returns the first node of the tree, the header if the tree is empty.
|
Chris@16
|
212 //!
|
Chris@16
|
213 //! <b>Complexity</b>: Constant time.
|
Chris@16
|
214 //!
|
Chris@16
|
215 //! <b>Throws</b>: Nothing.
|
Chris@16
|
216 static node_ptr begin_node(const const_node_ptr & header)
|
Chris@16
|
217 { return node_traits::get_left(header); }
|
Chris@16
|
218
|
Chris@16
|
219 //! <b>Requires</b>: 'header' is the header node of a tree.
|
Chris@16
|
220 //!
|
Chris@16
|
221 //! <b>Effects</b>: Returns the header of the tree.
|
Chris@16
|
222 //!
|
Chris@16
|
223 //! <b>Complexity</b>: Constant time.
|
Chris@16
|
224 //!
|
Chris@16
|
225 //! <b>Throws</b>: Nothing.
|
Chris@16
|
226 static node_ptr end_node(const const_node_ptr & header)
|
Chris@16
|
227 { return detail::uncast(header); }
|
Chris@16
|
228
|
Chris@101
|
229 //! <b>Requires</b>: 'header' is the header node of a tree.
|
Chris@101
|
230 //!
|
Chris@101
|
231 //! <b>Effects</b>: Returns the root of the tree if any, header otherwise
|
Chris@101
|
232 //!
|
Chris@101
|
233 //! <b>Complexity</b>: Constant time.
|
Chris@101
|
234 //!
|
Chris@101
|
235 //! <b>Throws</b>: Nothing.
|
Chris@101
|
236 static node_ptr root_node(const const_node_ptr & header)
|
Chris@101
|
237 {
|
Chris@101
|
238 node_ptr p = node_traits::get_parent(header);
|
Chris@101
|
239 return p ? p : detail::uncast(header);
|
Chris@101
|
240 }
|
Chris@101
|
241
|
Chris@101
|
242 //! <b>Requires</b>: 'node' is a node of the tree or a node initialized
|
Chris@16
|
243 //! by init(...) or init_node.
|
Chris@16
|
244 //!
|
Chris@16
|
245 //! <b>Effects</b>: Returns true if the node is initialized by init() or init_node().
|
Chris@16
|
246 //!
|
Chris@16
|
247 //! <b>Complexity</b>: Constant time.
|
Chris@16
|
248 //!
|
Chris@16
|
249 //! <b>Throws</b>: Nothing.
|
Chris@16
|
250 static bool unique(const const_node_ptr & node)
|
Chris@16
|
251 { return !NodeTraits::get_parent(node); }
|
Chris@16
|
252
|
Chris@101
|
253 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
|
Chris@16
|
254 //! <b>Requires</b>: 'node' is a node of the tree or a header node.
|
Chris@16
|
255 //!
|
Chris@16
|
256 //! <b>Effects</b>: Returns the header of the tree.
|
Chris@16
|
257 //!
|
Chris@16
|
258 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
259 //!
|
Chris@16
|
260 //! <b>Throws</b>: Nothing.
|
Chris@101
|
261 static node_ptr get_header(const const_node_ptr & node);
|
Chris@101
|
262 #endif
|
Chris@16
|
263
|
Chris@16
|
264 //! <b>Requires</b>: node1 and node2 can't be header nodes
|
Chris@16
|
265 //! of two trees.
|
Chris@16
|
266 //!
|
Chris@16
|
267 //! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted
|
Chris@16
|
268 //! in the position node2 before the function. node2 will be inserted in the
|
Chris@16
|
269 //! position node1 had before the function.
|
Chris@16
|
270 //!
|
Chris@16
|
271 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
272 //!
|
Chris@16
|
273 //! <b>Throws</b>: Nothing.
|
Chris@16
|
274 //!
|
Chris@16
|
275 //! <b>Note</b>: This function will break container ordering invariants if
|
Chris@16
|
276 //! node1 and node2 are not equivalent according to the ordering rules.
|
Chris@16
|
277 //!
|
Chris@16
|
278 //!Experimental function
|
Chris@16
|
279 static void swap_nodes(const node_ptr & node1, const node_ptr & node2)
|
Chris@16
|
280 {
|
Chris@16
|
281 if(node1 == node2)
|
Chris@16
|
282 return;
|
Chris@16
|
283
|
Chris@101
|
284 node_ptr header1(base_type::get_header(node1)), header2(base_type::get_header(node2));
|
Chris@16
|
285 swap_nodes(node1, header1, node2, header2);
|
Chris@16
|
286 }
|
Chris@16
|
287
|
Chris@16
|
288 //! <b>Requires</b>: node1 and node2 can't be header nodes
|
Chris@16
|
289 //! of two trees with header header1 and header2.
|
Chris@16
|
290 //!
|
Chris@16
|
291 //! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted
|
Chris@16
|
292 //! in the position node2 before the function. node2 will be inserted in the
|
Chris@16
|
293 //! position node1 had before the function.
|
Chris@16
|
294 //!
|
Chris@16
|
295 //! <b>Complexity</b>: Constant.
|
Chris@16
|
296 //!
|
Chris@16
|
297 //! <b>Throws</b>: Nothing.
|
Chris@16
|
298 //!
|
Chris@16
|
299 //! <b>Note</b>: This function will break container ordering invariants if
|
Chris@16
|
300 //! node1 and node2 are not equivalent according to the ordering rules.
|
Chris@16
|
301 //!
|
Chris@16
|
302 //!Experimental function
|
Chris@16
|
303 static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const node_ptr & header2)
|
Chris@16
|
304 {
|
Chris@16
|
305 if(node1 == node2)
|
Chris@16
|
306 return;
|
Chris@16
|
307
|
Chris@16
|
308 //node1 and node2 must not be header nodes
|
Chris@16
|
309 //BOOST_INTRUSIVE_INVARIANT_ASSERT((header1 != node1 && header2 != node2));
|
Chris@16
|
310 if(header1 != header2){
|
Chris@16
|
311 //Update header1 if necessary
|
Chris@16
|
312 if(node1 == NodeTraits::get_left(header1)){
|
Chris@16
|
313 NodeTraits::set_left(header1, node2);
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 if(node1 == NodeTraits::get_right(header1)){
|
Chris@16
|
317 NodeTraits::set_right(header1, node2);
|
Chris@16
|
318 }
|
Chris@16
|
319
|
Chris@16
|
320 if(node1 == NodeTraits::get_parent(header1)){
|
Chris@16
|
321 NodeTraits::set_parent(header1, node2);
|
Chris@16
|
322 }
|
Chris@16
|
323
|
Chris@16
|
324 //Update header2 if necessary
|
Chris@16
|
325 if(node2 == NodeTraits::get_left(header2)){
|
Chris@16
|
326 NodeTraits::set_left(header2, node1);
|
Chris@16
|
327 }
|
Chris@16
|
328
|
Chris@16
|
329 if(node2 == NodeTraits::get_right(header2)){
|
Chris@16
|
330 NodeTraits::set_right(header2, node1);
|
Chris@16
|
331 }
|
Chris@16
|
332
|
Chris@16
|
333 if(node2 == NodeTraits::get_parent(header2)){
|
Chris@16
|
334 NodeTraits::set_parent(header2, node1);
|
Chris@16
|
335 }
|
Chris@16
|
336 }
|
Chris@16
|
337 else{
|
Chris@16
|
338 //If both nodes are from the same tree
|
Chris@16
|
339 //Update header if necessary
|
Chris@16
|
340 if(node1 == NodeTraits::get_left(header1)){
|
Chris@16
|
341 NodeTraits::set_left(header1, node2);
|
Chris@16
|
342 }
|
Chris@16
|
343 else if(node2 == NodeTraits::get_left(header2)){
|
Chris@16
|
344 NodeTraits::set_left(header2, node1);
|
Chris@16
|
345 }
|
Chris@16
|
346
|
Chris@16
|
347 if(node1 == NodeTraits::get_right(header1)){
|
Chris@16
|
348 NodeTraits::set_right(header1, node2);
|
Chris@16
|
349 }
|
Chris@16
|
350 else if(node2 == NodeTraits::get_right(header2)){
|
Chris@16
|
351 NodeTraits::set_right(header2, node1);
|
Chris@16
|
352 }
|
Chris@16
|
353
|
Chris@16
|
354 if(node1 == NodeTraits::get_parent(header1)){
|
Chris@16
|
355 NodeTraits::set_parent(header1, node2);
|
Chris@16
|
356 }
|
Chris@16
|
357 else if(node2 == NodeTraits::get_parent(header2)){
|
Chris@16
|
358 NodeTraits::set_parent(header2, node1);
|
Chris@16
|
359 }
|
Chris@16
|
360
|
Chris@16
|
361 //Adjust data in nodes to be swapped
|
Chris@16
|
362 //so that final link swap works as expected
|
Chris@16
|
363 if(node1 == NodeTraits::get_parent(node2)){
|
Chris@16
|
364 NodeTraits::set_parent(node2, node2);
|
Chris@16
|
365
|
Chris@16
|
366 if(node2 == NodeTraits::get_right(node1)){
|
Chris@16
|
367 NodeTraits::set_right(node1, node1);
|
Chris@16
|
368 }
|
Chris@16
|
369 else{
|
Chris@16
|
370 NodeTraits::set_left(node1, node1);
|
Chris@16
|
371 }
|
Chris@16
|
372 }
|
Chris@16
|
373 else if(node2 == NodeTraits::get_parent(node1)){
|
Chris@16
|
374 NodeTraits::set_parent(node1, node1);
|
Chris@16
|
375
|
Chris@16
|
376 if(node1 == NodeTraits::get_right(node2)){
|
Chris@16
|
377 NodeTraits::set_right(node2, node2);
|
Chris@16
|
378 }
|
Chris@16
|
379 else{
|
Chris@16
|
380 NodeTraits::set_left(node2, node2);
|
Chris@16
|
381 }
|
Chris@16
|
382 }
|
Chris@16
|
383 }
|
Chris@16
|
384
|
Chris@16
|
385 //Now swap all the links
|
Chris@16
|
386 node_ptr temp;
|
Chris@16
|
387 //swap left link
|
Chris@16
|
388 temp = NodeTraits::get_left(node1);
|
Chris@16
|
389 NodeTraits::set_left(node1, NodeTraits::get_left(node2));
|
Chris@16
|
390 NodeTraits::set_left(node2, temp);
|
Chris@16
|
391 //swap right link
|
Chris@16
|
392 temp = NodeTraits::get_right(node1);
|
Chris@16
|
393 NodeTraits::set_right(node1, NodeTraits::get_right(node2));
|
Chris@16
|
394 NodeTraits::set_right(node2, temp);
|
Chris@16
|
395 //swap parent link
|
Chris@16
|
396 temp = NodeTraits::get_parent(node1);
|
Chris@16
|
397 NodeTraits::set_parent(node1, NodeTraits::get_parent(node2));
|
Chris@16
|
398 NodeTraits::set_parent(node2, temp);
|
Chris@16
|
399
|
Chris@16
|
400 //Now adjust adjacent nodes for newly inserted node 1
|
Chris@16
|
401 if((temp = NodeTraits::get_left(node1))){
|
Chris@16
|
402 NodeTraits::set_parent(temp, node1);
|
Chris@16
|
403 }
|
Chris@16
|
404 if((temp = NodeTraits::get_right(node1))){
|
Chris@16
|
405 NodeTraits::set_parent(temp, node1);
|
Chris@16
|
406 }
|
Chris@16
|
407 if((temp = NodeTraits::get_parent(node1)) &&
|
Chris@16
|
408 //The header has been already updated so avoid it
|
Chris@16
|
409 temp != header2){
|
Chris@16
|
410 if(NodeTraits::get_left(temp) == node2){
|
Chris@16
|
411 NodeTraits::set_left(temp, node1);
|
Chris@16
|
412 }
|
Chris@16
|
413 if(NodeTraits::get_right(temp) == node2){
|
Chris@16
|
414 NodeTraits::set_right(temp, node1);
|
Chris@16
|
415 }
|
Chris@16
|
416 }
|
Chris@16
|
417 //Now adjust adjacent nodes for newly inserted node 2
|
Chris@16
|
418 if((temp = NodeTraits::get_left(node2))){
|
Chris@16
|
419 NodeTraits::set_parent(temp, node2);
|
Chris@16
|
420 }
|
Chris@16
|
421 if((temp = NodeTraits::get_right(node2))){
|
Chris@16
|
422 NodeTraits::set_parent(temp, node2);
|
Chris@16
|
423 }
|
Chris@16
|
424 if((temp = NodeTraits::get_parent(node2)) &&
|
Chris@16
|
425 //The header has been already updated so avoid it
|
Chris@16
|
426 temp != header1){
|
Chris@16
|
427 if(NodeTraits::get_left(temp) == node1){
|
Chris@16
|
428 NodeTraits::set_left(temp, node2);
|
Chris@16
|
429 }
|
Chris@16
|
430 if(NodeTraits::get_right(temp) == node1){
|
Chris@16
|
431 NodeTraits::set_right(temp, node2);
|
Chris@16
|
432 }
|
Chris@16
|
433 }
|
Chris@16
|
434 }
|
Chris@16
|
435
|
Chris@16
|
436 //! <b>Requires</b>: node_to_be_replaced must be inserted in a tree
|
Chris@16
|
437 //! and new_node must not be inserted in a tree.
|
Chris@16
|
438 //!
|
Chris@16
|
439 //! <b>Effects</b>: Replaces node_to_be_replaced in its position in the
|
Chris@16
|
440 //! tree with new_node. The tree does not need to be rebalanced
|
Chris@16
|
441 //!
|
Chris@16
|
442 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
443 //!
|
Chris@16
|
444 //! <b>Throws</b>: Nothing.
|
Chris@16
|
445 //!
|
Chris@16
|
446 //! <b>Note</b>: This function will break container ordering invariants if
|
Chris@16
|
447 //! new_node is not equivalent to node_to_be_replaced according to the
|
Chris@16
|
448 //! ordering rules. This function is faster than erasing and inserting
|
Chris@16
|
449 //! the node, since no rebalancing and comparison is needed. Experimental function
|
Chris@16
|
450 static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & new_node)
|
Chris@16
|
451 {
|
Chris@16
|
452 if(node_to_be_replaced == new_node)
|
Chris@16
|
453 return;
|
Chris@101
|
454 replace_node(node_to_be_replaced, base_type::get_header(node_to_be_replaced), new_node);
|
Chris@16
|
455 }
|
Chris@16
|
456
|
Chris@16
|
457 //! <b>Requires</b>: node_to_be_replaced must be inserted in a tree
|
Chris@16
|
458 //! with header "header" and new_node must not be inserted in a tree.
|
Chris@16
|
459 //!
|
Chris@16
|
460 //! <b>Effects</b>: Replaces node_to_be_replaced in its position in the
|
Chris@16
|
461 //! tree with new_node. The tree does not need to be rebalanced
|
Chris@16
|
462 //!
|
Chris@16
|
463 //! <b>Complexity</b>: Constant.
|
Chris@16
|
464 //!
|
Chris@16
|
465 //! <b>Throws</b>: Nothing.
|
Chris@16
|
466 //!
|
Chris@16
|
467 //! <b>Note</b>: This function will break container ordering invariants if
|
Chris@16
|
468 //! new_node is not equivalent to node_to_be_replaced according to the
|
Chris@16
|
469 //! ordering rules. This function is faster than erasing and inserting
|
Chris@16
|
470 //! the node, since no rebalancing or comparison is needed. Experimental function
|
Chris@16
|
471 static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const node_ptr & new_node)
|
Chris@16
|
472 {
|
Chris@16
|
473 if(node_to_be_replaced == new_node)
|
Chris@16
|
474 return;
|
Chris@16
|
475
|
Chris@16
|
476 //Update header if necessary
|
Chris@16
|
477 if(node_to_be_replaced == NodeTraits::get_left(header)){
|
Chris@16
|
478 NodeTraits::set_left(header, new_node);
|
Chris@16
|
479 }
|
Chris@16
|
480
|
Chris@16
|
481 if(node_to_be_replaced == NodeTraits::get_right(header)){
|
Chris@16
|
482 NodeTraits::set_right(header, new_node);
|
Chris@16
|
483 }
|
Chris@16
|
484
|
Chris@16
|
485 if(node_to_be_replaced == NodeTraits::get_parent(header)){
|
Chris@16
|
486 NodeTraits::set_parent(header, new_node);
|
Chris@16
|
487 }
|
Chris@16
|
488
|
Chris@16
|
489 //Now set data from the original node
|
Chris@16
|
490 node_ptr temp;
|
Chris@16
|
491 NodeTraits::set_left(new_node, NodeTraits::get_left(node_to_be_replaced));
|
Chris@16
|
492 NodeTraits::set_right(new_node, NodeTraits::get_right(node_to_be_replaced));
|
Chris@16
|
493 NodeTraits::set_parent(new_node, NodeTraits::get_parent(node_to_be_replaced));
|
Chris@16
|
494
|
Chris@16
|
495 //Now adjust adjacent nodes for newly inserted node
|
Chris@16
|
496 if((temp = NodeTraits::get_left(new_node))){
|
Chris@16
|
497 NodeTraits::set_parent(temp, new_node);
|
Chris@16
|
498 }
|
Chris@16
|
499 if((temp = NodeTraits::get_right(new_node))){
|
Chris@16
|
500 NodeTraits::set_parent(temp, new_node);
|
Chris@16
|
501 }
|
Chris@16
|
502 if((temp = NodeTraits::get_parent(new_node)) &&
|
Chris@16
|
503 //The header has been already updated so avoid it
|
Chris@16
|
504 temp != header){
|
Chris@16
|
505 if(NodeTraits::get_left(temp) == node_to_be_replaced){
|
Chris@16
|
506 NodeTraits::set_left(temp, new_node);
|
Chris@16
|
507 }
|
Chris@16
|
508 if(NodeTraits::get_right(temp) == node_to_be_replaced){
|
Chris@16
|
509 NodeTraits::set_right(temp, new_node);
|
Chris@16
|
510 }
|
Chris@16
|
511 }
|
Chris@16
|
512 }
|
Chris@16
|
513
|
Chris@101
|
514 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
|
Chris@16
|
515 //! <b>Requires</b>: 'node' is a node from the tree except the header.
|
Chris@16
|
516 //!
|
Chris@16
|
517 //! <b>Effects</b>: Returns the next node of the tree.
|
Chris@16
|
518 //!
|
Chris@16
|
519 //! <b>Complexity</b>: Average constant time.
|
Chris@16
|
520 //!
|
Chris@16
|
521 //! <b>Throws</b>: Nothing.
|
Chris@101
|
522 static node_ptr next_node(const node_ptr & node);
|
Chris@16
|
523
|
Chris@16
|
524 //! <b>Requires</b>: 'node' is a node from the tree except the leftmost node.
|
Chris@16
|
525 //!
|
Chris@16
|
526 //! <b>Effects</b>: Returns the previous node of the tree.
|
Chris@16
|
527 //!
|
Chris@16
|
528 //! <b>Complexity</b>: Average constant time.
|
Chris@16
|
529 //!
|
Chris@16
|
530 //! <b>Throws</b>: Nothing.
|
Chris@101
|
531 static node_ptr prev_node(const node_ptr & node);
|
Chris@16
|
532
|
Chris@16
|
533 //! <b>Requires</b>: 'node' is a node of a tree but not the header.
|
Chris@16
|
534 //!
|
Chris@16
|
535 //! <b>Effects</b>: Returns the minimum node of the subtree starting at p.
|
Chris@16
|
536 //!
|
Chris@16
|
537 //! <b>Complexity</b>: Logarithmic to the size of the subtree.
|
Chris@16
|
538 //!
|
Chris@16
|
539 //! <b>Throws</b>: Nothing.
|
Chris@101
|
540 static node_ptr minimum(node_ptr node);
|
Chris@16
|
541
|
Chris@16
|
542 //! <b>Requires</b>: 'node' is a node of a tree but not the header.
|
Chris@16
|
543 //!
|
Chris@16
|
544 //! <b>Effects</b>: Returns the maximum node of the subtree starting at p.
|
Chris@16
|
545 //!
|
Chris@16
|
546 //! <b>Complexity</b>: Logarithmic to the size of the subtree.
|
Chris@16
|
547 //!
|
Chris@16
|
548 //! <b>Throws</b>: Nothing.
|
Chris@101
|
549 static node_ptr maximum(node_ptr node);
|
Chris@101
|
550 #endif
|
Chris@16
|
551
|
Chris@16
|
552 //! <b>Requires</b>: 'node' must not be part of any tree.
|
Chris@16
|
553 //!
|
Chris@16
|
554 //! <b>Effects</b>: After the function unique(node) == true.
|
Chris@16
|
555 //!
|
Chris@16
|
556 //! <b>Complexity</b>: Constant.
|
Chris@16
|
557 //!
|
Chris@16
|
558 //! <b>Throws</b>: Nothing.
|
Chris@16
|
559 //!
|
Chris@16
|
560 //! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.
|
Chris@16
|
561 static void init(const node_ptr & node)
|
Chris@16
|
562 {
|
Chris@16
|
563 NodeTraits::set_parent(node, node_ptr());
|
Chris@16
|
564 NodeTraits::set_left(node, node_ptr());
|
Chris@16
|
565 NodeTraits::set_right(node, node_ptr());
|
Chris@16
|
566 };
|
Chris@16
|
567
|
Chris@16
|
568 //! <b>Effects</b>: Returns true if node is in the same state as if called init(node)
|
Chris@16
|
569 //!
|
Chris@16
|
570 //! <b>Complexity</b>: Constant.
|
Chris@16
|
571 //!
|
Chris@16
|
572 //! <b>Throws</b>: Nothing.
|
Chris@16
|
573 static bool inited(const const_node_ptr & node)
|
Chris@16
|
574 {
|
Chris@16
|
575 return !NodeTraits::get_parent(node) &&
|
Chris@16
|
576 !NodeTraits::get_left(node) &&
|
Chris@16
|
577 !NodeTraits::get_right(node) ;
|
Chris@16
|
578 };
|
Chris@16
|
579
|
Chris@16
|
580 //! <b>Requires</b>: node must not be part of any tree.
|
Chris@16
|
581 //!
|
Chris@16
|
582 //! <b>Effects</b>: Initializes the header to represent an empty tree.
|
Chris@16
|
583 //! unique(header) == true.
|
Chris@16
|
584 //!
|
Chris@16
|
585 //! <b>Complexity</b>: Constant.
|
Chris@16
|
586 //!
|
Chris@16
|
587 //! <b>Throws</b>: Nothing.
|
Chris@16
|
588 //!
|
Chris@16
|
589 //! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.
|
Chris@16
|
590 static void init_header(const node_ptr & header)
|
Chris@16
|
591 {
|
Chris@16
|
592 NodeTraits::set_parent(header, node_ptr());
|
Chris@16
|
593 NodeTraits::set_left(header, header);
|
Chris@16
|
594 NodeTraits::set_right(header, header);
|
Chris@16
|
595 }
|
Chris@16
|
596
|
Chris@16
|
597 //! <b>Requires</b>: "disposer" must be an object function
|
Chris@16
|
598 //! taking a node_ptr parameter and shouldn't throw.
|
Chris@16
|
599 //!
|
Chris@16
|
600 //! <b>Effects</b>: Empties the target tree calling
|
Chris@16
|
601 //! <tt>void disposer::operator()(const node_ptr &)</tt> for every node of the tree
|
Chris@16
|
602 //! except the header.
|
Chris@16
|
603 //!
|
Chris@16
|
604 //! <b>Complexity</b>: Linear to the number of element of the source tree plus the.
|
Chris@16
|
605 //! number of elements of tree target tree when calling this function.
|
Chris@16
|
606 //!
|
Chris@16
|
607 //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.
|
Chris@16
|
608 template<class Disposer>
|
Chris@16
|
609 static void clear_and_dispose(const node_ptr & header, Disposer disposer)
|
Chris@16
|
610 {
|
Chris@16
|
611 node_ptr source_root = NodeTraits::get_parent(header);
|
Chris@16
|
612 if(!source_root)
|
Chris@16
|
613 return;
|
Chris@16
|
614 dispose_subtree(source_root, disposer);
|
Chris@16
|
615 init_header(header);
|
Chris@16
|
616 }
|
Chris@16
|
617
|
Chris@16
|
618 //! <b>Requires</b>: header is the header of a tree.
|
Chris@16
|
619 //!
|
Chris@16
|
620 //! <b>Effects</b>: Unlinks the leftmost node from the tree, and
|
Chris@16
|
621 //! updates the header link to the new leftmost node.
|
Chris@16
|
622 //!
|
Chris@16
|
623 //! <b>Complexity</b>: Average complexity is constant time.
|
Chris@16
|
624 //!
|
Chris@16
|
625 //! <b>Throws</b>: Nothing.
|
Chris@16
|
626 //!
|
Chris@16
|
627 //! <b>Notes</b>: This function breaks the tree and the tree can
|
Chris@16
|
628 //! only be used for more unlink_leftmost_without_rebalance calls.
|
Chris@16
|
629 //! This function is normally used to achieve a step by step
|
Chris@16
|
630 //! controlled destruction of the tree.
|
Chris@16
|
631 static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header)
|
Chris@16
|
632 {
|
Chris@16
|
633 node_ptr leftmost = NodeTraits::get_left(header);
|
Chris@16
|
634 if (leftmost == header)
|
Chris@16
|
635 return node_ptr();
|
Chris@16
|
636 node_ptr leftmost_parent(NodeTraits::get_parent(leftmost));
|
Chris@16
|
637 node_ptr leftmost_right (NodeTraits::get_right(leftmost));
|
Chris@16
|
638 bool is_root = leftmost_parent == header;
|
Chris@16
|
639
|
Chris@16
|
640 if (leftmost_right){
|
Chris@16
|
641 NodeTraits::set_parent(leftmost_right, leftmost_parent);
|
Chris@101
|
642 NodeTraits::set_left(header, base_type::minimum(leftmost_right));
|
Chris@16
|
643
|
Chris@16
|
644 if (is_root)
|
Chris@16
|
645 NodeTraits::set_parent(header, leftmost_right);
|
Chris@16
|
646 else
|
Chris@16
|
647 NodeTraits::set_left(NodeTraits::get_parent(header), leftmost_right);
|
Chris@16
|
648 }
|
Chris@16
|
649 else if (is_root){
|
Chris@16
|
650 NodeTraits::set_parent(header, node_ptr());
|
Chris@16
|
651 NodeTraits::set_left(header, header);
|
Chris@16
|
652 NodeTraits::set_right(header, header);
|
Chris@16
|
653 }
|
Chris@16
|
654 else{
|
Chris@16
|
655 NodeTraits::set_left(leftmost_parent, node_ptr());
|
Chris@16
|
656 NodeTraits::set_left(header, leftmost_parent);
|
Chris@16
|
657 }
|
Chris@16
|
658 return leftmost;
|
Chris@16
|
659 }
|
Chris@16
|
660
|
Chris@16
|
661 //! <b>Requires</b>: node is a node of the tree but it's not the header.
|
Chris@16
|
662 //!
|
Chris@16
|
663 //! <b>Effects</b>: Returns the number of nodes of the subtree.
|
Chris@16
|
664 //!
|
Chris@16
|
665 //! <b>Complexity</b>: Linear time.
|
Chris@16
|
666 //!
|
Chris@16
|
667 //! <b>Throws</b>: Nothing.
|
Chris@16
|
668 static std::size_t size(const const_node_ptr & header)
|
Chris@16
|
669 {
|
Chris@16
|
670 node_ptr beg(begin_node(header));
|
Chris@16
|
671 node_ptr end(end_node(header));
|
Chris@16
|
672 std::size_t i = 0;
|
Chris@101
|
673 for(;beg != end; beg = base_type::next_node(beg)) ++i;
|
Chris@16
|
674 return i;
|
Chris@16
|
675 }
|
Chris@16
|
676
|
Chris@16
|
677 //! <b>Requires</b>: header1 and header2 must be the header nodes
|
Chris@16
|
678 //! of two trees.
|
Chris@16
|
679 //!
|
Chris@16
|
680 //! <b>Effects</b>: Swaps two trees. After the function header1 will contain
|
Chris@16
|
681 //! links to the second tree and header2 will have links to the first tree.
|
Chris@16
|
682 //!
|
Chris@16
|
683 //! <b>Complexity</b>: Constant.
|
Chris@16
|
684 //!
|
Chris@16
|
685 //! <b>Throws</b>: Nothing.
|
Chris@16
|
686 static void swap_tree(const node_ptr & header1, const node_ptr & header2)
|
Chris@16
|
687 {
|
Chris@16
|
688 if(header1 == header2)
|
Chris@16
|
689 return;
|
Chris@16
|
690
|
Chris@16
|
691 node_ptr tmp;
|
Chris@16
|
692
|
Chris@16
|
693 //Parent swap
|
Chris@16
|
694 tmp = NodeTraits::get_parent(header1);
|
Chris@16
|
695 NodeTraits::set_parent(header1, NodeTraits::get_parent(header2));
|
Chris@16
|
696 NodeTraits::set_parent(header2, tmp);
|
Chris@16
|
697 //Left swap
|
Chris@16
|
698 tmp = NodeTraits::get_left(header1);
|
Chris@16
|
699 NodeTraits::set_left(header1, NodeTraits::get_left(header2));
|
Chris@16
|
700 NodeTraits::set_left(header2, tmp);
|
Chris@16
|
701 //Right swap
|
Chris@16
|
702 tmp = NodeTraits::get_right(header1);
|
Chris@16
|
703 NodeTraits::set_right(header1, NodeTraits::get_right(header2));
|
Chris@16
|
704 NodeTraits::set_right(header2, tmp);
|
Chris@16
|
705
|
Chris@16
|
706 //Now test parent
|
Chris@16
|
707 node_ptr h1_parent(NodeTraits::get_parent(header1));
|
Chris@16
|
708 if(h1_parent){
|
Chris@16
|
709 NodeTraits::set_parent(h1_parent, header1);
|
Chris@16
|
710 }
|
Chris@16
|
711 else{
|
Chris@16
|
712 NodeTraits::set_left(header1, header1);
|
Chris@16
|
713 NodeTraits::set_right(header1, header1);
|
Chris@16
|
714 }
|
Chris@16
|
715
|
Chris@16
|
716 node_ptr h2_parent(NodeTraits::get_parent(header2));
|
Chris@16
|
717 if(h2_parent){
|
Chris@16
|
718 NodeTraits::set_parent(h2_parent, header2);
|
Chris@16
|
719 }
|
Chris@16
|
720 else{
|
Chris@16
|
721 NodeTraits::set_left(header2, header2);
|
Chris@16
|
722 NodeTraits::set_right(header2, header2);
|
Chris@16
|
723 }
|
Chris@16
|
724 }
|
Chris@16
|
725
|
Chris@101
|
726 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
|
Chris@16
|
727 //! <b>Requires</b>: p is a node of a tree.
|
Chris@16
|
728 //!
|
Chris@16
|
729 //! <b>Effects</b>: Returns true if p is the header of the tree.
|
Chris@16
|
730 //!
|
Chris@16
|
731 //! <b>Complexity</b>: Constant.
|
Chris@16
|
732 //!
|
Chris@16
|
733 //! <b>Throws</b>: Nothing.
|
Chris@101
|
734 static bool is_header(const const_node_ptr & p);
|
Chris@101
|
735 #endif
|
Chris@16
|
736
|
Chris@16
|
737 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
738 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
739 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
740 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.
|
Chris@16
|
741 //!
|
Chris@101
|
742 //! <b>Effects</b>: Returns a node_ptr to the first element that is equivalent to
|
Chris@16
|
743 //! "key" according to "comp" or "header" if that element does not exist.
|
Chris@16
|
744 //!
|
Chris@16
|
745 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
746 //!
|
Chris@16
|
747 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
748 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
749 static node_ptr find
|
Chris@16
|
750 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@16
|
751 {
|
Chris@16
|
752 node_ptr end = detail::uncast(header);
|
Chris@16
|
753 node_ptr y = lower_bound(header, key, comp);
|
Chris@16
|
754 return (y == end || comp(key, y)) ? end : y;
|
Chris@16
|
755 }
|
Chris@16
|
756
|
Chris@16
|
757 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
758 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
759 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
760 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.
|
Chris@16
|
761 //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If
|
Chris@101
|
762 //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be true.
|
Chris@16
|
763 //!
|
Chris@16
|
764 //! <b>Effects</b>: Returns an a pair with the following criteria:
|
Chris@16
|
765 //!
|
Chris@16
|
766 //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise
|
Chris@16
|
767 //!
|
Chris@16
|
768 //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise
|
Chris@16
|
769 //!
|
Chris@16
|
770 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
771 //!
|
Chris@16
|
772 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
773 //!
|
Chris@16
|
774 //! <b>Note</b>: This function can be more efficient than calling upper_bound
|
Chris@16
|
775 //! and lower_bound for lower_key and upper_key.
|
Chris@16
|
776 //!
|
Chris@16
|
777 //! <b>Note</b>: Experimental function, the interface might change.
|
Chris@16
|
778 template< class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
779 static std::pair<node_ptr, node_ptr> bounded_range
|
Chris@16
|
780 ( const const_node_ptr & header
|
Chris@16
|
781 , const KeyType &lower_key
|
Chris@16
|
782 , const KeyType &upper_key
|
Chris@16
|
783 , KeyNodePtrCompare comp
|
Chris@16
|
784 , bool left_closed
|
Chris@16
|
785 , bool right_closed)
|
Chris@16
|
786 {
|
Chris@16
|
787 node_ptr y = detail::uncast(header);
|
Chris@16
|
788 node_ptr x = NodeTraits::get_parent(header);
|
Chris@16
|
789
|
Chris@16
|
790 while(x){
|
Chris@16
|
791 //If x is less than lower_key the target
|
Chris@16
|
792 //range is on the right part
|
Chris@16
|
793 if(comp(x, lower_key)){
|
Chris@16
|
794 //Check for invalid input range
|
Chris@16
|
795 BOOST_INTRUSIVE_INVARIANT_ASSERT(comp(x, upper_key));
|
Chris@16
|
796 x = NodeTraits::get_right(x);
|
Chris@16
|
797 }
|
Chris@16
|
798 //If the upper_key is less than x, the target
|
Chris@16
|
799 //range is on the left part
|
Chris@16
|
800 else if(comp(upper_key, x)){
|
Chris@16
|
801 y = x;
|
Chris@16
|
802 x = NodeTraits::get_left(x);
|
Chris@16
|
803 }
|
Chris@16
|
804 else{
|
Chris@101
|
805 //x is inside the bounded range(lower_key <= x <= upper_key),
|
Chris@16
|
806 //so we must split lower and upper searches
|
Chris@16
|
807 //
|
Chris@16
|
808 //Sanity check: if lower_key and upper_key are equal, then both left_closed and right_closed can't be false
|
Chris@16
|
809 BOOST_INTRUSIVE_INVARIANT_ASSERT(left_closed || right_closed || comp(lower_key, x) || comp(x, upper_key));
|
Chris@16
|
810 return std::pair<node_ptr,node_ptr>(
|
Chris@16
|
811 left_closed
|
Chris@16
|
812 //If left_closed, then comp(x, lower_key) is already the lower_bound
|
Chris@16
|
813 //condition so we save one comparison and go to the next level
|
Chris@16
|
814 //following traditional lower_bound algo
|
Chris@16
|
815 ? lower_bound_loop(NodeTraits::get_left(x), x, lower_key, comp)
|
Chris@16
|
816 //If left-open, comp(x, lower_key) is not the upper_bound algo
|
Chris@16
|
817 //condition so we must recheck current 'x' node with upper_bound algo
|
Chris@16
|
818 : upper_bound_loop(x, y, lower_key, comp)
|
Chris@16
|
819 ,
|
Chris@16
|
820 right_closed
|
Chris@16
|
821 //If right_closed, then comp(upper_key, x) is already the upper_bound
|
Chris@16
|
822 //condition so we can save one comparison and go to the next level
|
Chris@16
|
823 //following lower_bound algo
|
Chris@16
|
824 ? upper_bound_loop(NodeTraits::get_right(x), y, upper_key, comp)
|
Chris@16
|
825 //If right-open, comp(upper_key, x) is not the lower_bound algo
|
Chris@16
|
826 //condition so we must recheck current 'x' node with lower_bound algo
|
Chris@16
|
827 : lower_bound_loop(x, y, upper_key, comp)
|
Chris@16
|
828 );
|
Chris@16
|
829 }
|
Chris@16
|
830 }
|
Chris@16
|
831 return std::pair<node_ptr,node_ptr> (y, y);
|
Chris@16
|
832 }
|
Chris@16
|
833
|
Chris@16
|
834 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
835 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
836 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
837 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.
|
Chris@16
|
838 //!
|
Chris@101
|
839 //! <b>Effects</b>: Returns the number of elements with a key equivalent to "key"
|
Chris@16
|
840 //! according to "comp".
|
Chris@16
|
841 //!
|
Chris@16
|
842 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
843 //!
|
Chris@16
|
844 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
845 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
846 static std::size_t count
|
Chris@16
|
847 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@16
|
848 {
|
Chris@16
|
849 std::pair<node_ptr, node_ptr> ret = equal_range(header, key, comp);
|
Chris@16
|
850 std::size_t n = 0;
|
Chris@16
|
851 while(ret.first != ret.second){
|
Chris@16
|
852 ++n;
|
Chris@101
|
853 ret.first = base_type::next_node(ret.first);
|
Chris@16
|
854 }
|
Chris@16
|
855 return n;
|
Chris@16
|
856 }
|
Chris@16
|
857
|
Chris@16
|
858 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
859 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
860 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
861 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.
|
Chris@16
|
862 //!
|
Chris@16
|
863 //! <b>Effects</b>: Returns an a pair of node_ptr delimiting a range containing
|
Chris@16
|
864 //! all elements that are equivalent to "key" according to "comp" or an
|
Chris@16
|
865 //! empty range that indicates the position where those elements would be
|
Chris@16
|
866 //! if there are no equivalent elements.
|
Chris@16
|
867 //!
|
Chris@16
|
868 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
869 //!
|
Chris@16
|
870 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
871 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
872 static std::pair<node_ptr, node_ptr> equal_range
|
Chris@16
|
873 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@16
|
874 {
|
Chris@16
|
875 return bounded_range(header, key, key, comp, true, true);
|
Chris@16
|
876 }
|
Chris@16
|
877
|
Chris@16
|
878 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
879 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
880 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
881 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.
|
Chris@16
|
882 //!
|
Chris@101
|
883 //! <b>Effects</b>: Returns an a pair of node_ptr delimiting a range containing
|
Chris@101
|
884 //! the first element that is equivalent to "key" according to "comp" or an
|
Chris@101
|
885 //! empty range that indicates the position where that element would be
|
Chris@101
|
886 //! if there are no equivalent elements.
|
Chris@101
|
887 //!
|
Chris@101
|
888 //! <b>Complexity</b>: Logarithmic.
|
Chris@101
|
889 //!
|
Chris@101
|
890 //! <b>Throws</b>: If "comp" throws.
|
Chris@101
|
891 template<class KeyType, class KeyNodePtrCompare>
|
Chris@101
|
892 static std::pair<node_ptr, node_ptr> lower_bound_range
|
Chris@101
|
893 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@101
|
894 {
|
Chris@101
|
895 node_ptr const lb(lower_bound(header, key, comp));
|
Chris@101
|
896 std::pair<node_ptr, node_ptr> ret_ii(lb, lb);
|
Chris@101
|
897 if(lb != header && !comp(key, lb)){
|
Chris@101
|
898 ret_ii.second = base_type::next_node(ret_ii.second);
|
Chris@101
|
899 }
|
Chris@101
|
900 return ret_ii;
|
Chris@101
|
901 }
|
Chris@101
|
902
|
Chris@101
|
903 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@101
|
904 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@101
|
905 //! ordering compatible with the strict weak ordering used to create the
|
Chris@101
|
906 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.
|
Chris@101
|
907 //!
|
Chris@101
|
908 //! <b>Effects</b>: Returns a node_ptr to the first element that is
|
Chris@16
|
909 //! not less than "key" according to "comp" or "header" if that element does
|
Chris@16
|
910 //! not exist.
|
Chris@16
|
911 //!
|
Chris@16
|
912 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
913 //!
|
Chris@16
|
914 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
915 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
916 static node_ptr lower_bound
|
Chris@16
|
917 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@16
|
918 {
|
Chris@16
|
919 return lower_bound_loop(NodeTraits::get_parent(header), detail::uncast(header), key, comp);
|
Chris@16
|
920 }
|
Chris@16
|
921
|
Chris@16
|
922 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
923 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
924 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
925 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs.
|
Chris@16
|
926 //!
|
Chris@101
|
927 //! <b>Effects</b>: Returns a node_ptr to the first element that is greater
|
Chris@16
|
928 //! than "key" according to "comp" or "header" if that element does not exist.
|
Chris@16
|
929 //!
|
Chris@16
|
930 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
931 //!
|
Chris@16
|
932 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
933 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
934 static node_ptr upper_bound
|
Chris@16
|
935 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@16
|
936 {
|
Chris@16
|
937 return upper_bound_loop(NodeTraits::get_parent(header), detail::uncast(header), key, comp);
|
Chris@16
|
938 }
|
Chris@16
|
939
|
Chris@16
|
940 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
941 //! "commit_data" must have been obtained from a previous call to
|
Chris@16
|
942 //! "insert_unique_check". No objects should have been inserted or erased
|
Chris@16
|
943 //! from the set between the "insert_unique_check" that filled "commit_data"
|
Chris@16
|
944 //! and the call to "insert_commit".
|
Chris@16
|
945 //!
|
Chris@16
|
946 //!
|
Chris@16
|
947 //! <b>Effects</b>: Inserts new_node in the set using the information obtained
|
Chris@16
|
948 //! from the "commit_data" that a previous "insert_check" filled.
|
Chris@16
|
949 //!
|
Chris@16
|
950 //! <b>Complexity</b>: Constant time.
|
Chris@16
|
951 //!
|
Chris@16
|
952 //! <b>Throws</b>: Nothing.
|
Chris@16
|
953 //!
|
Chris@16
|
954 //! <b>Notes</b>: This function has only sense if a "insert_unique_check" has been
|
Chris@16
|
955 //! previously executed to fill "commit_data". No value should be inserted or
|
Chris@16
|
956 //! erased between the "insert_check" and "insert_commit" calls.
|
Chris@16
|
957 static void insert_unique_commit
|
Chris@16
|
958 (const node_ptr & header, const node_ptr & new_value, const insert_commit_data &commit_data)
|
Chris@16
|
959 { return insert_commit(header, new_value, commit_data); }
|
Chris@16
|
960
|
Chris@16
|
961 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
962 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
963 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
964 //! the tree. NodePtrCompare compares KeyType with a node_ptr.
|
Chris@16
|
965 //!
|
Chris@16
|
966 //! <b>Effects</b>: Checks if there is an equivalent node to "key" in the
|
Chris@16
|
967 //! tree according to "comp" and obtains the needed information to realize
|
Chris@16
|
968 //! a constant-time node insertion if there is no equivalent node.
|
Chris@16
|
969 //!
|
Chris@16
|
970 //! <b>Returns</b>: If there is an equivalent value
|
Chris@16
|
971 //! returns a pair containing a node_ptr to the already present node
|
Chris@16
|
972 //! and false. If there is not equivalent key can be inserted returns true
|
Chris@16
|
973 //! in the returned pair's boolean and fills "commit_data" that is meant to
|
Chris@16
|
974 //! be used with the "insert_commit" function to achieve a constant-time
|
Chris@16
|
975 //! insertion function.
|
Chris@16
|
976 //!
|
Chris@16
|
977 //! <b>Complexity</b>: Average complexity is at most logarithmic.
|
Chris@16
|
978 //!
|
Chris@16
|
979 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
980 //!
|
Chris@16
|
981 //! <b>Notes</b>: This function is used to improve performance when constructing
|
Chris@16
|
982 //! a node is expensive and the user does not want to have two equivalent nodes
|
Chris@16
|
983 //! in the tree: if there is an equivalent value
|
Chris@16
|
984 //! the constructed object must be discarded. Many times, the part of the
|
Chris@16
|
985 //! node that is used to impose the order is much cheaper to construct
|
Chris@16
|
986 //! than the node and this function offers the possibility to use that part
|
Chris@16
|
987 //! to check if the insertion will be successful.
|
Chris@16
|
988 //!
|
Chris@16
|
989 //! If the check is successful, the user can construct the node and use
|
Chris@16
|
990 //! "insert_commit" to insert the node in constant-time. This gives a total
|
Chris@16
|
991 //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).
|
Chris@16
|
992 //!
|
Chris@16
|
993 //! "commit_data" remains valid for a subsequent "insert_unique_commit" only
|
Chris@16
|
994 //! if no more objects are inserted or erased from the set.
|
Chris@16
|
995 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
996 static std::pair<node_ptr, bool> insert_unique_check
|
Chris@16
|
997 (const const_node_ptr & header, const KeyType &key
|
Chris@16
|
998 ,KeyNodePtrCompare comp, insert_commit_data &commit_data
|
Chris@16
|
999 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1000 , std::size_t *pdepth = 0
|
Chris@16
|
1001 #endif
|
Chris@16
|
1002 )
|
Chris@16
|
1003 {
|
Chris@16
|
1004 std::size_t depth = 0;
|
Chris@16
|
1005 node_ptr h(detail::uncast(header));
|
Chris@16
|
1006 node_ptr y(h);
|
Chris@16
|
1007 node_ptr x(NodeTraits::get_parent(y));
|
Chris@16
|
1008 node_ptr prev = node_ptr();
|
Chris@16
|
1009
|
Chris@16
|
1010 //Find the upper bound, cache the previous value and if we should
|
Chris@16
|
1011 //store it in the left or right node
|
Chris@16
|
1012 bool left_child = true;
|
Chris@16
|
1013 while(x){
|
Chris@16
|
1014 ++depth;
|
Chris@16
|
1015 y = x;
|
Chris@16
|
1016 x = (left_child = comp(key, x)) ?
|
Chris@16
|
1017 NodeTraits::get_left(x) : (prev = y, NodeTraits::get_right(x));
|
Chris@16
|
1018 }
|
Chris@16
|
1019
|
Chris@16
|
1020 if(pdepth) *pdepth = depth;
|
Chris@16
|
1021
|
Chris@16
|
1022 //Since we've found the upper bound there is no other value with the same key if:
|
Chris@16
|
1023 // - There is no previous node
|
Chris@16
|
1024 // - The previous node is less than the key
|
Chris@101
|
1025 const bool not_present = !prev || comp(prev, key);
|
Chris@101
|
1026 if(not_present){
|
Chris@16
|
1027 commit_data.link_left = left_child;
|
Chris@16
|
1028 commit_data.node = y;
|
Chris@16
|
1029 }
|
Chris@101
|
1030 return std::pair<node_ptr, bool>(prev, not_present);
|
Chris@16
|
1031 }
|
Chris@16
|
1032
|
Chris@16
|
1033 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
1034 //! KeyNodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
1035 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
1036 //! the tree. NodePtrCompare compares KeyType with a node_ptr.
|
Chris@16
|
1037 //! "hint" is node from the "header"'s tree.
|
Chris@16
|
1038 //!
|
Chris@16
|
1039 //! <b>Effects</b>: Checks if there is an equivalent node to "key" in the
|
Chris@16
|
1040 //! tree according to "comp" using "hint" as a hint to where it should be
|
Chris@16
|
1041 //! inserted and obtains the needed information to realize
|
Chris@16
|
1042 //! a constant-time node insertion if there is no equivalent node.
|
Chris@16
|
1043 //! If "hint" is the upper_bound the function has constant time
|
Chris@16
|
1044 //! complexity (two comparisons in the worst case).
|
Chris@16
|
1045 //!
|
Chris@16
|
1046 //! <b>Returns</b>: If there is an equivalent value
|
Chris@16
|
1047 //! returns a pair containing a node_ptr to the already present node
|
Chris@16
|
1048 //! and false. If there is not equivalent key can be inserted returns true
|
Chris@16
|
1049 //! in the returned pair's boolean and fills "commit_data" that is meant to
|
Chris@16
|
1050 //! be used with the "insert_commit" function to achieve a constant-time
|
Chris@16
|
1051 //! insertion function.
|
Chris@16
|
1052 //!
|
Chris@16
|
1053 //! <b>Complexity</b>: Average complexity is at most logarithmic, but it is
|
Chris@16
|
1054 //! amortized constant time if new_node should be inserted immediately before "hint".
|
Chris@16
|
1055 //!
|
Chris@16
|
1056 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
1057 //!
|
Chris@16
|
1058 //! <b>Notes</b>: This function is used to improve performance when constructing
|
Chris@16
|
1059 //! a node is expensive and the user does not want to have two equivalent nodes
|
Chris@16
|
1060 //! in the tree: if there is an equivalent value
|
Chris@16
|
1061 //! the constructed object must be discarded. Many times, the part of the
|
Chris@16
|
1062 //! node that is used to impose the order is much cheaper to construct
|
Chris@16
|
1063 //! than the node and this function offers the possibility to use that part
|
Chris@16
|
1064 //! to check if the insertion will be successful.
|
Chris@16
|
1065 //!
|
Chris@16
|
1066 //! If the check is successful, the user can construct the node and use
|
Chris@16
|
1067 //! "insert_commit" to insert the node in constant-time. This gives a total
|
Chris@16
|
1068 //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).
|
Chris@16
|
1069 //!
|
Chris@16
|
1070 //! "commit_data" remains valid for a subsequent "insert_unique_commit" only
|
Chris@16
|
1071 //! if no more objects are inserted or erased from the set.
|
Chris@16
|
1072 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
1073 static std::pair<node_ptr, bool> insert_unique_check
|
Chris@16
|
1074 (const const_node_ptr & header, const node_ptr &hint, const KeyType &key
|
Chris@16
|
1075 ,KeyNodePtrCompare comp, insert_commit_data &commit_data
|
Chris@16
|
1076 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1077 , std::size_t *pdepth = 0
|
Chris@16
|
1078 #endif
|
Chris@16
|
1079 )
|
Chris@16
|
1080 {
|
Chris@16
|
1081 //hint must be bigger than the key
|
Chris@16
|
1082 if(hint == header || comp(key, hint)){
|
Chris@16
|
1083 node_ptr prev(hint);
|
Chris@16
|
1084 //Previous value should be less than the key
|
Chris@101
|
1085 if(hint == begin_node(header) || comp((prev = base_type::prev_node(hint)), key)){
|
Chris@16
|
1086 commit_data.link_left = unique(header) || !NodeTraits::get_left(hint);
|
Chris@16
|
1087 commit_data.node = commit_data.link_left ? hint : prev;
|
Chris@16
|
1088 if(pdepth){
|
Chris@16
|
1089 *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1;
|
Chris@16
|
1090 }
|
Chris@16
|
1091 return std::pair<node_ptr, bool>(node_ptr(), true);
|
Chris@16
|
1092 }
|
Chris@16
|
1093 }
|
Chris@16
|
1094 //Hint was wrong, use hintless insertion
|
Chris@16
|
1095 return insert_unique_check(header, key, comp, commit_data, pdepth);
|
Chris@16
|
1096 }
|
Chris@16
|
1097
|
Chris@16
|
1098 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
1099 //! NodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
1100 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
1101 //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from
|
Chris@16
|
1102 //! the "header"'s tree.
|
Chris@16
|
1103 //!
|
Chris@16
|
1104 //! <b>Effects</b>: Inserts new_node into the tree, using "hint" as a hint to
|
Chris@16
|
1105 //! where it will be inserted. If "hint" is the upper_bound
|
Chris@16
|
1106 //! the insertion takes constant time (two comparisons in the worst case).
|
Chris@16
|
1107 //!
|
Chris@16
|
1108 //! <b>Complexity</b>: Logarithmic in general, but it is amortized
|
Chris@16
|
1109 //! constant time if new_node is inserted immediately before "hint".
|
Chris@16
|
1110 //!
|
Chris@16
|
1111 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
1112 template<class NodePtrCompare>
|
Chris@16
|
1113 static node_ptr insert_equal
|
Chris@16
|
1114 (const node_ptr & h, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp
|
Chris@16
|
1115 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1116 , std::size_t *pdepth = 0
|
Chris@16
|
1117 #endif
|
Chris@16
|
1118 )
|
Chris@16
|
1119 {
|
Chris@16
|
1120 insert_commit_data commit_data;
|
Chris@16
|
1121 insert_equal_check(h, hint, new_node, comp, commit_data, pdepth);
|
Chris@16
|
1122 insert_commit(h, new_node, commit_data);
|
Chris@16
|
1123 return new_node;
|
Chris@16
|
1124 }
|
Chris@16
|
1125
|
Chris@16
|
1126 //! <b>Requires</b>: "h" must be the header node of a tree.
|
Chris@16
|
1127 //! NodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
1128 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
1129 //! the tree. NodePtrCompare compares two node_ptrs.
|
Chris@16
|
1130 //!
|
Chris@16
|
1131 //! <b>Effects</b>: Inserts new_node into the tree before the upper bound
|
Chris@16
|
1132 //! according to "comp".
|
Chris@16
|
1133 //!
|
Chris@16
|
1134 //! <b>Complexity</b>: Average complexity for insert element is at
|
Chris@16
|
1135 //! most logarithmic.
|
Chris@16
|
1136 //!
|
Chris@16
|
1137 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
1138 template<class NodePtrCompare>
|
Chris@16
|
1139 static node_ptr insert_equal_upper_bound
|
Chris@16
|
1140 (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp
|
Chris@16
|
1141 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1142 , std::size_t *pdepth = 0
|
Chris@16
|
1143 #endif
|
Chris@16
|
1144 )
|
Chris@16
|
1145 {
|
Chris@16
|
1146 insert_commit_data commit_data;
|
Chris@16
|
1147 insert_equal_upper_bound_check(h, new_node, comp, commit_data, pdepth);
|
Chris@16
|
1148 insert_commit(h, new_node, commit_data);
|
Chris@16
|
1149 return new_node;
|
Chris@16
|
1150 }
|
Chris@16
|
1151
|
Chris@16
|
1152 //! <b>Requires</b>: "h" must be the header node of a tree.
|
Chris@16
|
1153 //! NodePtrCompare is a function object that induces a strict weak
|
Chris@16
|
1154 //! ordering compatible with the strict weak ordering used to create the
|
Chris@16
|
1155 //! the tree. NodePtrCompare compares two node_ptrs.
|
Chris@16
|
1156 //!
|
Chris@16
|
1157 //! <b>Effects</b>: Inserts new_node into the tree before the lower bound
|
Chris@16
|
1158 //! according to "comp".
|
Chris@16
|
1159 //!
|
Chris@16
|
1160 //! <b>Complexity</b>: Average complexity for insert element is at
|
Chris@16
|
1161 //! most logarithmic.
|
Chris@16
|
1162 //!
|
Chris@16
|
1163 //! <b>Throws</b>: If "comp" throws.
|
Chris@16
|
1164 template<class NodePtrCompare>
|
Chris@16
|
1165 static node_ptr insert_equal_lower_bound
|
Chris@16
|
1166 (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp
|
Chris@16
|
1167 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1168 , std::size_t *pdepth = 0
|
Chris@16
|
1169 #endif
|
Chris@16
|
1170 )
|
Chris@16
|
1171 {
|
Chris@16
|
1172 insert_commit_data commit_data;
|
Chris@16
|
1173 insert_equal_lower_bound_check(h, new_node, comp, commit_data, pdepth);
|
Chris@16
|
1174 insert_commit(h, new_node, commit_data);
|
Chris@16
|
1175 return new_node;
|
Chris@16
|
1176 }
|
Chris@16
|
1177
|
Chris@16
|
1178 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
1179 //! "pos" must be a valid iterator or header (end) node.
|
Chris@16
|
1180 //! "pos" must be an iterator pointing to the successor to "new_node"
|
Chris@16
|
1181 //! once inserted according to the order of already inserted nodes. This function does not
|
Chris@16
|
1182 //! check "pos" and this precondition must be guaranteed by the caller.
|
Chris@16
|
1183 //!
|
Chris@16
|
1184 //! <b>Effects</b>: Inserts new_node into the tree before "pos".
|
Chris@16
|
1185 //!
|
Chris@16
|
1186 //! <b>Complexity</b>: Constant-time.
|
Chris@16
|
1187 //!
|
Chris@16
|
1188 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1189 //!
|
Chris@16
|
1190 //! <b>Note</b>: If "pos" is not the successor of the newly inserted "new_node"
|
Chris@16
|
1191 //! tree invariants might be broken.
|
Chris@16
|
1192 static node_ptr insert_before
|
Chris@16
|
1193 (const node_ptr & header, const node_ptr & pos, const node_ptr & new_node
|
Chris@16
|
1194 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1195 , std::size_t *pdepth = 0
|
Chris@16
|
1196 #endif
|
Chris@16
|
1197 )
|
Chris@16
|
1198 {
|
Chris@16
|
1199 insert_commit_data commit_data;
|
Chris@16
|
1200 insert_before_check(header, pos, commit_data, pdepth);
|
Chris@16
|
1201 insert_commit(header, new_node, commit_data);
|
Chris@16
|
1202 return new_node;
|
Chris@16
|
1203 }
|
Chris@16
|
1204
|
Chris@16
|
1205 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
1206 //! "new_node" must be, according to the used ordering no less than the
|
Chris@16
|
1207 //! greatest inserted key.
|
Chris@16
|
1208 //!
|
Chris@16
|
1209 //! <b>Effects</b>: Inserts new_node into the tree before "pos".
|
Chris@16
|
1210 //!
|
Chris@16
|
1211 //! <b>Complexity</b>: Constant-time.
|
Chris@16
|
1212 //!
|
Chris@16
|
1213 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1214 //!
|
Chris@16
|
1215 //! <b>Note</b>: If "new_node" is less than the greatest inserted key
|
Chris@16
|
1216 //! tree invariants are broken. This function is slightly faster than
|
Chris@16
|
1217 //! using "insert_before".
|
Chris@16
|
1218 static void push_back
|
Chris@16
|
1219 (const node_ptr & header, const node_ptr & new_node
|
Chris@16
|
1220 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1221 , std::size_t *pdepth = 0
|
Chris@16
|
1222 #endif
|
Chris@16
|
1223 )
|
Chris@16
|
1224 {
|
Chris@16
|
1225 insert_commit_data commit_data;
|
Chris@16
|
1226 push_back_check(header, commit_data, pdepth);
|
Chris@16
|
1227 insert_commit(header, new_node, commit_data);
|
Chris@16
|
1228 }
|
Chris@16
|
1229
|
Chris@16
|
1230 //! <b>Requires</b>: "header" must be the header node of a tree.
|
Chris@16
|
1231 //! "new_node" must be, according to the used ordering, no greater than the
|
Chris@16
|
1232 //! lowest inserted key.
|
Chris@16
|
1233 //!
|
Chris@16
|
1234 //! <b>Effects</b>: Inserts new_node into the tree before "pos".
|
Chris@16
|
1235 //!
|
Chris@16
|
1236 //! <b>Complexity</b>: Constant-time.
|
Chris@16
|
1237 //!
|
Chris@16
|
1238 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1239 //!
|
Chris@16
|
1240 //! <b>Note</b>: If "new_node" is greater than the lowest inserted key
|
Chris@16
|
1241 //! tree invariants are broken. This function is slightly faster than
|
Chris@16
|
1242 //! using "insert_before".
|
Chris@16
|
1243 static void push_front
|
Chris@16
|
1244 (const node_ptr & header, const node_ptr & new_node
|
Chris@16
|
1245 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1246 , std::size_t *pdepth = 0
|
Chris@16
|
1247 #endif
|
Chris@16
|
1248 )
|
Chris@16
|
1249 {
|
Chris@16
|
1250 insert_commit_data commit_data;
|
Chris@16
|
1251 push_front_check(header, commit_data, pdepth);
|
Chris@16
|
1252 insert_commit(header, new_node, commit_data);
|
Chris@16
|
1253 }
|
Chris@16
|
1254
|
Chris@16
|
1255 //! <b>Requires</b>: 'node' can't be a header node.
|
Chris@16
|
1256 //!
|
Chris@16
|
1257 //! <b>Effects</b>: Calculates the depth of a node: the depth of a
|
Chris@16
|
1258 //! node is the length (number of edges) of the path from the root
|
Chris@16
|
1259 //! to that node. (The root node is at depth 0.)
|
Chris@16
|
1260 //!
|
Chris@16
|
1261 //! <b>Complexity</b>: Logarithmic to the number of nodes in the tree.
|
Chris@16
|
1262 //!
|
Chris@16
|
1263 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1264 static std::size_t depth(const_node_ptr node)
|
Chris@16
|
1265 {
|
Chris@16
|
1266 std::size_t depth = 0;
|
Chris@16
|
1267 node_ptr p_parent;
|
Chris@16
|
1268 while(node != NodeTraits::get_parent(p_parent = NodeTraits::get_parent(node))){
|
Chris@16
|
1269 ++depth;
|
Chris@16
|
1270 node = p_parent;
|
Chris@16
|
1271 }
|
Chris@16
|
1272 return depth;
|
Chris@16
|
1273 }
|
Chris@16
|
1274
|
Chris@16
|
1275 //! <b>Requires</b>: "cloner" must be a function
|
Chris@16
|
1276 //! object taking a node_ptr and returning a new cloned node of it. "disposer" must
|
Chris@16
|
1277 //! take a node_ptr and shouldn't throw.
|
Chris@16
|
1278 //!
|
Chris@16
|
1279 //! <b>Effects</b>: First empties target tree calling
|
Chris@16
|
1280 //! <tt>void disposer::operator()(const node_ptr &)</tt> for every node of the tree
|
Chris@16
|
1281 //! except the header.
|
Chris@16
|
1282 //!
|
Chris@16
|
1283 //! Then, duplicates the entire tree pointed by "source_header" cloning each
|
Chris@16
|
1284 //! source node with <tt>node_ptr Cloner::operator()(const node_ptr &)</tt> to obtain
|
Chris@16
|
1285 //! the nodes of the target tree. If "cloner" throws, the cloned target nodes
|
Chris@16
|
1286 //! are disposed using <tt>void disposer(const node_ptr &)</tt>.
|
Chris@16
|
1287 //!
|
Chris@101
|
1288 //! <b>Complexity</b>: Linear to the number of element of the source tree plus the
|
Chris@16
|
1289 //! number of elements of tree target tree when calling this function.
|
Chris@16
|
1290 //!
|
Chris@16
|
1291 //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed.
|
Chris@16
|
1292 template <class Cloner, class Disposer>
|
Chris@16
|
1293 static void clone
|
Chris@16
|
1294 (const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer)
|
Chris@16
|
1295 {
|
Chris@16
|
1296 if(!unique(target_header)){
|
Chris@16
|
1297 clear_and_dispose(target_header, disposer);
|
Chris@16
|
1298 }
|
Chris@16
|
1299
|
Chris@16
|
1300 node_ptr leftmost, rightmost;
|
Chris@16
|
1301 node_ptr new_root = clone_subtree
|
Chris@16
|
1302 (source_header, target_header, cloner, disposer, leftmost, rightmost);
|
Chris@16
|
1303
|
Chris@16
|
1304 //Now update header node
|
Chris@16
|
1305 NodeTraits::set_parent(target_header, new_root);
|
Chris@16
|
1306 NodeTraits::set_left (target_header, leftmost);
|
Chris@16
|
1307 NodeTraits::set_right (target_header, rightmost);
|
Chris@16
|
1308 }
|
Chris@16
|
1309
|
Chris@16
|
1310 //! <b>Requires</b>: header must be the header of a tree, z a node
|
Chris@16
|
1311 //! of that tree and z != header.
|
Chris@16
|
1312 //!
|
Chris@16
|
1313 //! <b>Effects</b>: Erases node "z" from the tree with header "header".
|
Chris@16
|
1314 //!
|
Chris@16
|
1315 //! <b>Complexity</b>: Amortized constant time.
|
Chris@16
|
1316 //!
|
Chris@16
|
1317 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1318 static void erase(const node_ptr & header, const node_ptr & z)
|
Chris@16
|
1319 {
|
Chris@16
|
1320 data_for_rebalance ignored;
|
Chris@101
|
1321 erase(header, z, ignored);
|
Chris@16
|
1322 }
|
Chris@16
|
1323
|
Chris@16
|
1324 //! <b>Requires</b>: node is a tree node but not the header.
|
Chris@16
|
1325 //!
|
Chris@16
|
1326 //! <b>Effects</b>: Unlinks the node and rebalances the tree.
|
Chris@16
|
1327 //!
|
Chris@16
|
1328 //! <b>Complexity</b>: Average complexity is constant time.
|
Chris@16
|
1329 //!
|
Chris@16
|
1330 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1331 static void unlink(const node_ptr & node)
|
Chris@16
|
1332 {
|
Chris@16
|
1333 node_ptr x = NodeTraits::get_parent(node);
|
Chris@16
|
1334 if(x){
|
Chris@101
|
1335 while(!base_type::is_header(x))
|
Chris@16
|
1336 x = NodeTraits::get_parent(x);
|
Chris@16
|
1337 erase(x, node);
|
Chris@16
|
1338 }
|
Chris@16
|
1339 }
|
Chris@16
|
1340
|
Chris@16
|
1341 //! <b>Requires</b>: header must be the header of a tree.
|
Chris@16
|
1342 //!
|
Chris@16
|
1343 //! <b>Effects</b>: Rebalances the tree.
|
Chris@16
|
1344 //!
|
Chris@16
|
1345 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1346 //!
|
Chris@16
|
1347 //! <b>Complexity</b>: Linear.
|
Chris@16
|
1348 static void rebalance(const node_ptr & header)
|
Chris@16
|
1349 {
|
Chris@16
|
1350 node_ptr root = NodeTraits::get_parent(header);
|
Chris@16
|
1351 if(root){
|
Chris@16
|
1352 rebalance_subtree(root);
|
Chris@16
|
1353 }
|
Chris@16
|
1354 }
|
Chris@16
|
1355
|
Chris@16
|
1356 //! <b>Requires</b>: old_root is a node of a tree. It shall not be null.
|
Chris@16
|
1357 //!
|
Chris@16
|
1358 //! <b>Effects</b>: Rebalances the subtree rooted at old_root.
|
Chris@16
|
1359 //!
|
Chris@16
|
1360 //! <b>Returns</b>: The new root of the subtree.
|
Chris@16
|
1361 //!
|
Chris@16
|
1362 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1363 //!
|
Chris@16
|
1364 //! <b>Complexity</b>: Linear.
|
Chris@16
|
1365 static node_ptr rebalance_subtree(const node_ptr & old_root)
|
Chris@16
|
1366 {
|
Chris@16
|
1367 //Taken from:
|
Chris@16
|
1368 //"Tree rebalancing in optimal time and space"
|
Chris@16
|
1369 //Quentin F. Stout and Bette L. Warren
|
Chris@16
|
1370
|
Chris@16
|
1371 //To avoid irregularities in the algorithm (old_root can be a
|
Chris@16
|
1372 //left or right child or even the root of the tree) just put the
|
Chris@16
|
1373 //root as the right child of its parent. Before doing this backup
|
Chris@16
|
1374 //information to restore the original relationship after
|
Chris@16
|
1375 //the algorithm is applied.
|
Chris@16
|
1376 node_ptr super_root = NodeTraits::get_parent(old_root);
|
Chris@16
|
1377 BOOST_INTRUSIVE_INVARIANT_ASSERT(super_root);
|
Chris@16
|
1378
|
Chris@16
|
1379 //Get root info
|
Chris@16
|
1380 node_ptr super_root_right_backup = NodeTraits::get_right(super_root);
|
Chris@16
|
1381 bool super_root_is_header = NodeTraits::get_parent(super_root) == old_root;
|
Chris@16
|
1382 bool old_root_is_right = is_right_child(old_root);
|
Chris@16
|
1383 NodeTraits::set_right(super_root, old_root);
|
Chris@16
|
1384
|
Chris@16
|
1385 std::size_t size;
|
Chris@16
|
1386 subtree_to_vine(super_root, size);
|
Chris@16
|
1387 vine_to_subtree(super_root, size);
|
Chris@16
|
1388 node_ptr new_root = NodeTraits::get_right(super_root);
|
Chris@16
|
1389
|
Chris@16
|
1390 //Recover root
|
Chris@16
|
1391 if(super_root_is_header){
|
Chris@16
|
1392 NodeTraits::set_right(super_root, super_root_right_backup);
|
Chris@16
|
1393 NodeTraits::set_parent(super_root, new_root);
|
Chris@16
|
1394 }
|
Chris@16
|
1395 else if(old_root_is_right){
|
Chris@16
|
1396 NodeTraits::set_right(super_root, new_root);
|
Chris@16
|
1397 }
|
Chris@16
|
1398 else{
|
Chris@16
|
1399 NodeTraits::set_right(super_root, super_root_right_backup);
|
Chris@16
|
1400 NodeTraits::set_left(super_root, new_root);
|
Chris@16
|
1401 }
|
Chris@16
|
1402 return new_root;
|
Chris@16
|
1403 }
|
Chris@16
|
1404
|
Chris@101
|
1405 //! <b>Effects</b>: Asserts the integrity of the container with additional checks provided by the user.
|
Chris@101
|
1406 //!
|
Chris@101
|
1407 //! <b>Requires</b>: header must be the header of a tree.
|
Chris@101
|
1408 //!
|
Chris@101
|
1409 //! <b>Complexity</b>: Linear time.
|
Chris@101
|
1410 //!
|
Chris@101
|
1411 //! <b>Note</b>: The method might not have effect when asserts are turned off (e.g., with NDEBUG).
|
Chris@101
|
1412 //! Experimental function, interface might change in future versions.
|
Chris@101
|
1413 template<class Checker>
|
Chris@101
|
1414 static void check(const const_node_ptr& header, Checker checker, typename Checker::return_type& checker_return)
|
Chris@101
|
1415 {
|
Chris@101
|
1416 const_node_ptr root_node_ptr = NodeTraits::get_parent(header);
|
Chris@101
|
1417 if (!root_node_ptr){
|
Chris@101
|
1418 // check left&right header pointers
|
Chris@101
|
1419 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(header) == header);
|
Chris@101
|
1420 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(header) == header);
|
Chris@101
|
1421 }
|
Chris@101
|
1422 else{
|
Chris@101
|
1423 // check parent pointer of root node
|
Chris@101
|
1424 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(root_node_ptr) == header);
|
Chris@101
|
1425 // check subtree from root
|
Chris@101
|
1426 check_subtree(root_node_ptr, checker, checker_return);
|
Chris@101
|
1427 // check left&right header pointers
|
Chris@101
|
1428 const_node_ptr p = root_node_ptr;
|
Chris@101
|
1429 while (NodeTraits::get_left(p)) { p = NodeTraits::get_left(p); }
|
Chris@101
|
1430 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(header) == p);
|
Chris@101
|
1431 p = root_node_ptr;
|
Chris@101
|
1432 while (NodeTraits::get_right(p)) { p = NodeTraits::get_right(p); }
|
Chris@101
|
1433 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(header) == p);
|
Chris@101
|
1434 }
|
Chris@101
|
1435 }
|
Chris@101
|
1436
|
Chris@16
|
1437 protected:
|
Chris@101
|
1438 static void erase(const node_ptr & header, const node_ptr & z, data_for_rebalance &info)
|
Chris@101
|
1439 {
|
Chris@101
|
1440 node_ptr y(z);
|
Chris@101
|
1441 node_ptr x;
|
Chris@101
|
1442 const node_ptr z_left(NodeTraits::get_left(z));
|
Chris@101
|
1443 const node_ptr z_right(NodeTraits::get_right(z));
|
Chris@101
|
1444
|
Chris@101
|
1445 if(!z_left){
|
Chris@101
|
1446 x = z_right; // x might be null.
|
Chris@101
|
1447 }
|
Chris@101
|
1448 else if(!z_right){ // z has exactly one non-null child. y == z.
|
Chris@101
|
1449 x = z_left; // x is not null.
|
Chris@101
|
1450 BOOST_ASSERT(x);
|
Chris@101
|
1451 }
|
Chris@101
|
1452 else{ //make y != z
|
Chris@101
|
1453 // y = find z's successor
|
Chris@101
|
1454 y = base_type::minimum(z_right);
|
Chris@101
|
1455 x = NodeTraits::get_right(y); // x might be null.
|
Chris@101
|
1456 }
|
Chris@101
|
1457
|
Chris@101
|
1458 node_ptr x_parent;
|
Chris@101
|
1459 const node_ptr z_parent(NodeTraits::get_parent(z));
|
Chris@101
|
1460 const bool z_is_leftchild(NodeTraits::get_left(z_parent) == z);
|
Chris@101
|
1461
|
Chris@101
|
1462 if(y != z){ //has two children and y is the minimum of z
|
Chris@101
|
1463 //y is z's successor and it has a null left child.
|
Chris@101
|
1464 //x is the right child of y (it can be null)
|
Chris@101
|
1465 //Relink y in place of z and link x with y's old parent
|
Chris@101
|
1466 NodeTraits::set_parent(z_left, y);
|
Chris@101
|
1467 NodeTraits::set_left(y, z_left);
|
Chris@101
|
1468 if(y != z_right){
|
Chris@101
|
1469 //Link y with the right tree of z
|
Chris@101
|
1470 NodeTraits::set_right(y, z_right);
|
Chris@101
|
1471 NodeTraits::set_parent(z_right, y);
|
Chris@101
|
1472 //Link x with y's old parent (y must be a left child)
|
Chris@101
|
1473 x_parent = NodeTraits::get_parent(y);
|
Chris@101
|
1474 BOOST_ASSERT(NodeTraits::get_left(x_parent) == y);
|
Chris@101
|
1475 if(x)
|
Chris@101
|
1476 NodeTraits::set_parent(x, x_parent);
|
Chris@101
|
1477 //Since y was the successor and not the right child of z, it must be a left child
|
Chris@101
|
1478 NodeTraits::set_left(x_parent, x);
|
Chris@101
|
1479 }
|
Chris@101
|
1480 else{ //y was the right child of y so no need to fix x's position
|
Chris@101
|
1481 x_parent = y;
|
Chris@101
|
1482 }
|
Chris@101
|
1483 NodeTraits::set_parent(y, z_parent);
|
Chris@101
|
1484 this_type::set_child(header, y, z_parent, z_is_leftchild);
|
Chris@101
|
1485 }
|
Chris@101
|
1486 else { // z has zero or one child, x is one child (it can be null)
|
Chris@101
|
1487 //Just link x to z's parent
|
Chris@101
|
1488 x_parent = z_parent;
|
Chris@101
|
1489 if(x)
|
Chris@101
|
1490 NodeTraits::set_parent(x, z_parent);
|
Chris@101
|
1491 this_type::set_child(header, x, z_parent, z_is_leftchild);
|
Chris@101
|
1492
|
Chris@101
|
1493 //Now update leftmost/rightmost in case z was one of them
|
Chris@101
|
1494 if(NodeTraits::get_left(header) == z){
|
Chris@101
|
1495 //z_left must be null because z is the leftmost
|
Chris@101
|
1496 BOOST_ASSERT(!z_left);
|
Chris@101
|
1497 NodeTraits::set_left(header, !z_right ?
|
Chris@101
|
1498 z_parent : // makes leftmost == header if z == root
|
Chris@101
|
1499 base_type::minimum(z_right));
|
Chris@101
|
1500 }
|
Chris@101
|
1501 if(NodeTraits::get_right(header) == z){
|
Chris@101
|
1502 //z_right must be null because z is the rightmost
|
Chris@101
|
1503 BOOST_ASSERT(!z_right);
|
Chris@101
|
1504 NodeTraits::set_right(header, !z_left ?
|
Chris@101
|
1505 z_parent : // makes rightmost == header if z == root
|
Chris@101
|
1506 base_type::maximum(z_left));
|
Chris@101
|
1507 }
|
Chris@101
|
1508 }
|
Chris@101
|
1509
|
Chris@101
|
1510 //If z had 0/1 child, y == z and one of its children (and maybe null)
|
Chris@101
|
1511 //If z had 2 children, y is the successor of z and x is the right child of y
|
Chris@101
|
1512 info.x = x;
|
Chris@101
|
1513 info.y = y;
|
Chris@101
|
1514 //If z had 0/1 child, x_parent is the new parent of the old right child of y (z's successor)
|
Chris@101
|
1515 //If z had 2 children, x_parent is the new parent of y (z_parent)
|
Chris@101
|
1516 BOOST_ASSERT(!x || NodeTraits::get_parent(x) == x_parent);
|
Chris@101
|
1517 info.x_parent = x_parent;
|
Chris@101
|
1518 }
|
Chris@101
|
1519
|
Chris@16
|
1520 //! <b>Requires</b>: node is a node of the tree but it's not the header.
|
Chris@16
|
1521 //!
|
Chris@16
|
1522 //! <b>Effects</b>: Returns the number of nodes of the subtree.
|
Chris@16
|
1523 //!
|
Chris@16
|
1524 //! <b>Complexity</b>: Linear time.
|
Chris@16
|
1525 //!
|
Chris@16
|
1526 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1527 static std::size_t subtree_size(const const_node_ptr & subtree)
|
Chris@16
|
1528 {
|
Chris@16
|
1529 std::size_t count = 0;
|
Chris@16
|
1530 if (subtree){
|
Chris@16
|
1531 node_ptr n = detail::uncast(subtree);
|
Chris@16
|
1532 node_ptr m = NodeTraits::get_left(n);
|
Chris@16
|
1533 while(m){
|
Chris@16
|
1534 n = m;
|
Chris@16
|
1535 m = NodeTraits::get_left(n);
|
Chris@16
|
1536 }
|
Chris@16
|
1537
|
Chris@16
|
1538 while(1){
|
Chris@16
|
1539 ++count;
|
Chris@16
|
1540 node_ptr n_right(NodeTraits::get_right(n));
|
Chris@16
|
1541 if(n_right){
|
Chris@16
|
1542 n = n_right;
|
Chris@16
|
1543 m = NodeTraits::get_left(n);
|
Chris@16
|
1544 while(m){
|
Chris@16
|
1545 n = m;
|
Chris@16
|
1546 m = NodeTraits::get_left(n);
|
Chris@16
|
1547 }
|
Chris@16
|
1548 }
|
Chris@16
|
1549 else {
|
Chris@16
|
1550 do{
|
Chris@16
|
1551 if (n == subtree){
|
Chris@16
|
1552 return count;
|
Chris@16
|
1553 }
|
Chris@16
|
1554 m = n;
|
Chris@16
|
1555 n = NodeTraits::get_parent(n);
|
Chris@16
|
1556 }while(NodeTraits::get_left(n) != m);
|
Chris@16
|
1557 }
|
Chris@16
|
1558 }
|
Chris@16
|
1559 }
|
Chris@16
|
1560 return count;
|
Chris@16
|
1561 }
|
Chris@16
|
1562
|
Chris@16
|
1563 //! <b>Requires</b>: p is a node of a tree.
|
Chris@16
|
1564 //!
|
Chris@16
|
1565 //! <b>Effects</b>: Returns true if p is a left child.
|
Chris@16
|
1566 //!
|
Chris@16
|
1567 //! <b>Complexity</b>: Constant.
|
Chris@16
|
1568 //!
|
Chris@16
|
1569 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1570 static bool is_left_child(const node_ptr & p)
|
Chris@16
|
1571 { return NodeTraits::get_left(NodeTraits::get_parent(p)) == p; }
|
Chris@16
|
1572
|
Chris@16
|
1573 //! <b>Requires</b>: p is a node of a tree.
|
Chris@16
|
1574 //!
|
Chris@16
|
1575 //! <b>Effects</b>: Returns true if p is a right child.
|
Chris@16
|
1576 //!
|
Chris@16
|
1577 //! <b>Complexity</b>: Constant.
|
Chris@16
|
1578 //!
|
Chris@16
|
1579 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1580 static bool is_right_child(const node_ptr & p)
|
Chris@16
|
1581 { return NodeTraits::get_right(NodeTraits::get_parent(p)) == p; }
|
Chris@16
|
1582
|
Chris@16
|
1583 static void insert_before_check
|
Chris@16
|
1584 (const node_ptr &header, const node_ptr & pos
|
Chris@16
|
1585 , insert_commit_data &commit_data
|
Chris@16
|
1586 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1587 , std::size_t *pdepth = 0
|
Chris@16
|
1588 #endif
|
Chris@16
|
1589 )
|
Chris@16
|
1590 {
|
Chris@16
|
1591 node_ptr prev(pos);
|
Chris@16
|
1592 if(pos != NodeTraits::get_left(header))
|
Chris@101
|
1593 prev = base_type::prev_node(pos);
|
Chris@16
|
1594 bool link_left = unique(header) || !NodeTraits::get_left(pos);
|
Chris@16
|
1595 commit_data.link_left = link_left;
|
Chris@16
|
1596 commit_data.node = link_left ? pos : prev;
|
Chris@16
|
1597 if(pdepth){
|
Chris@16
|
1598 *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1;
|
Chris@16
|
1599 }
|
Chris@16
|
1600 }
|
Chris@16
|
1601
|
Chris@16
|
1602 static void push_back_check
|
Chris@16
|
1603 (const node_ptr & header, insert_commit_data &commit_data
|
Chris@16
|
1604 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1605 , std::size_t *pdepth = 0
|
Chris@16
|
1606 #endif
|
Chris@16
|
1607 )
|
Chris@16
|
1608 {
|
Chris@16
|
1609 node_ptr prev(NodeTraits::get_right(header));
|
Chris@16
|
1610 if(pdepth){
|
Chris@16
|
1611 *pdepth = prev == header ? 0 : depth(prev) + 1;
|
Chris@16
|
1612 }
|
Chris@16
|
1613 commit_data.link_left = false;
|
Chris@16
|
1614 commit_data.node = prev;
|
Chris@16
|
1615 }
|
Chris@16
|
1616
|
Chris@16
|
1617 static void push_front_check
|
Chris@16
|
1618 (const node_ptr & header, insert_commit_data &commit_data
|
Chris@16
|
1619 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
|
Chris@101
|
1620 , std::size_t *pdepth = 0
|
Chris@16
|
1621 #endif
|
Chris@16
|
1622 )
|
Chris@16
|
1623 {
|
Chris@16
|
1624 node_ptr pos(NodeTraits::get_left(header));
|
Chris@16
|
1625 if(pdepth){
|
Chris@16
|
1626 *pdepth = pos == header ? 0 : depth(pos) + 1;
|
Chris@16
|
1627 }
|
Chris@16
|
1628 commit_data.link_left = true;
|
Chris@16
|
1629 commit_data.node = pos;
|
Chris@16
|
1630 }
|
Chris@16
|
1631
|
Chris@16
|
1632 template<class NodePtrCompare>
|
Chris@16
|
1633 static void insert_equal_check
|
Chris@16
|
1634 (const node_ptr &header, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp
|
Chris@16
|
1635 , insert_commit_data &commit_data
|
Chris@16
|
1636 /// @cond
|
Chris@16
|
1637 , std::size_t *pdepth = 0
|
Chris@16
|
1638 /// @endcond
|
Chris@16
|
1639 )
|
Chris@16
|
1640 {
|
Chris@16
|
1641 if(hint == header || !comp(hint, new_node)){
|
Chris@16
|
1642 node_ptr prev(hint);
|
Chris@16
|
1643 if(hint == NodeTraits::get_left(header) ||
|
Chris@101
|
1644 !comp(new_node, (prev = base_type::prev_node(hint)))){
|
Chris@16
|
1645 bool link_left = unique(header) || !NodeTraits::get_left(hint);
|
Chris@16
|
1646 commit_data.link_left = link_left;
|
Chris@16
|
1647 commit_data.node = link_left ? hint : prev;
|
Chris@16
|
1648 if(pdepth){
|
Chris@16
|
1649 *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1;
|
Chris@16
|
1650 }
|
Chris@16
|
1651 }
|
Chris@16
|
1652 else{
|
Chris@16
|
1653 insert_equal_upper_bound_check(header, new_node, comp, commit_data, pdepth);
|
Chris@16
|
1654 }
|
Chris@16
|
1655 }
|
Chris@16
|
1656 else{
|
Chris@16
|
1657 insert_equal_lower_bound_check(header, new_node, comp, commit_data, pdepth);
|
Chris@16
|
1658 }
|
Chris@16
|
1659 }
|
Chris@16
|
1660
|
Chris@16
|
1661 template<class NodePtrCompare>
|
Chris@16
|
1662 static void insert_equal_upper_bound_check
|
Chris@16
|
1663 (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0)
|
Chris@101
|
1664 {
|
Chris@101
|
1665 std::size_t depth = 0;
|
Chris@101
|
1666 node_ptr y(h);
|
Chris@101
|
1667 node_ptr x(NodeTraits::get_parent(y));
|
Chris@101
|
1668
|
Chris@101
|
1669 while(x){
|
Chris@101
|
1670 ++depth;
|
Chris@101
|
1671 y = x;
|
Chris@101
|
1672 x = comp(new_node, x) ?
|
Chris@101
|
1673 NodeTraits::get_left(x) : NodeTraits::get_right(x);
|
Chris@101
|
1674 }
|
Chris@101
|
1675 if(pdepth) *pdepth = depth;
|
Chris@101
|
1676 commit_data.link_left = (y == h) || comp(new_node, y);
|
Chris@101
|
1677 commit_data.node = y;
|
Chris@101
|
1678 }
|
Chris@16
|
1679
|
Chris@16
|
1680 template<class NodePtrCompare>
|
Chris@16
|
1681 static void insert_equal_lower_bound_check
|
Chris@16
|
1682 (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0)
|
Chris@101
|
1683 {
|
Chris@101
|
1684 std::size_t depth = 0;
|
Chris@101
|
1685 node_ptr y(h);
|
Chris@101
|
1686 node_ptr x(NodeTraits::get_parent(y));
|
Chris@101
|
1687
|
Chris@101
|
1688 while(x){
|
Chris@101
|
1689 ++depth;
|
Chris@101
|
1690 y = x;
|
Chris@101
|
1691 x = !comp(x, new_node) ?
|
Chris@101
|
1692 NodeTraits::get_left(x) : NodeTraits::get_right(x);
|
Chris@101
|
1693 }
|
Chris@101
|
1694 if(pdepth) *pdepth = depth;
|
Chris@101
|
1695 commit_data.link_left = (y == h) || !comp(y, new_node);
|
Chris@101
|
1696 commit_data.node = y;
|
Chris@101
|
1697 }
|
Chris@16
|
1698
|
Chris@16
|
1699 static void insert_commit
|
Chris@16
|
1700 (const node_ptr & header, const node_ptr & new_node, const insert_commit_data &commit_data)
|
Chris@16
|
1701 {
|
Chris@16
|
1702 //Check if commit_data has not been initialized by a insert_unique_check call.
|
Chris@16
|
1703 BOOST_INTRUSIVE_INVARIANT_ASSERT(commit_data.node != node_ptr());
|
Chris@16
|
1704 node_ptr parent_node(commit_data.node);
|
Chris@16
|
1705 if(parent_node == header){
|
Chris@16
|
1706 NodeTraits::set_parent(header, new_node);
|
Chris@16
|
1707 NodeTraits::set_right(header, new_node);
|
Chris@16
|
1708 NodeTraits::set_left(header, new_node);
|
Chris@16
|
1709 }
|
Chris@16
|
1710 else if(commit_data.link_left){
|
Chris@16
|
1711 NodeTraits::set_left(parent_node, new_node);
|
Chris@16
|
1712 if(parent_node == NodeTraits::get_left(header))
|
Chris@16
|
1713 NodeTraits::set_left(header, new_node);
|
Chris@16
|
1714 }
|
Chris@16
|
1715 else{
|
Chris@16
|
1716 NodeTraits::set_right(parent_node, new_node);
|
Chris@16
|
1717 if(parent_node == NodeTraits::get_right(header))
|
Chris@16
|
1718 NodeTraits::set_right(header, new_node);
|
Chris@16
|
1719 }
|
Chris@16
|
1720 NodeTraits::set_parent(new_node, parent_node);
|
Chris@16
|
1721 NodeTraits::set_right(new_node, node_ptr());
|
Chris@16
|
1722 NodeTraits::set_left(new_node, node_ptr());
|
Chris@16
|
1723 }
|
Chris@16
|
1724
|
Chris@101
|
1725 //Fix header and own's parent data when replacing x with own, providing own's old data with parent
|
Chris@101
|
1726 static void set_child(const node_ptr & header, const node_ptr & new_child, const node_ptr & new_parent, const bool link_left)
|
Chris@101
|
1727 {
|
Chris@101
|
1728 if(new_parent == header)
|
Chris@101
|
1729 NodeTraits::set_parent(header, new_child);
|
Chris@101
|
1730 else if(link_left)
|
Chris@101
|
1731 NodeTraits::set_left(new_parent, new_child);
|
Chris@101
|
1732 else
|
Chris@101
|
1733 NodeTraits::set_right(new_parent, new_child);
|
Chris@101
|
1734 }
|
Chris@101
|
1735
|
Chris@101
|
1736 // rotate p to left (no header and p's parent fixup)
|
Chris@101
|
1737 static void rotate_left_no_parent_fix(const node_ptr & p, const node_ptr &p_right)
|
Chris@101
|
1738 {
|
Chris@101
|
1739 node_ptr p_right_left(NodeTraits::get_left(p_right));
|
Chris@101
|
1740 NodeTraits::set_right(p, p_right_left);
|
Chris@101
|
1741 if(p_right_left){
|
Chris@101
|
1742 NodeTraits::set_parent(p_right_left, p);
|
Chris@101
|
1743 }
|
Chris@101
|
1744 NodeTraits::set_left(p_right, p);
|
Chris@101
|
1745 NodeTraits::set_parent(p, p_right);
|
Chris@101
|
1746 }
|
Chris@101
|
1747
|
Chris@101
|
1748 // rotate p to left (with header and p's parent fixup)
|
Chris@101
|
1749 static void rotate_left(const node_ptr & p, const node_ptr & p_right, const node_ptr & p_parent, const node_ptr & header)
|
Chris@101
|
1750 {
|
Chris@101
|
1751 const bool p_was_left(NodeTraits::get_left(p_parent) == p);
|
Chris@101
|
1752 rotate_left_no_parent_fix(p, p_right);
|
Chris@101
|
1753 NodeTraits::set_parent(p_right, p_parent);
|
Chris@101
|
1754 set_child(header, p_right, p_parent, p_was_left);
|
Chris@101
|
1755 }
|
Chris@101
|
1756
|
Chris@101
|
1757 // rotate p to right (no header and p's parent fixup)
|
Chris@101
|
1758 static void rotate_right_no_parent_fix(const node_ptr & p, const node_ptr &p_left)
|
Chris@101
|
1759 {
|
Chris@101
|
1760 node_ptr p_left_right(NodeTraits::get_right(p_left));
|
Chris@101
|
1761 NodeTraits::set_left(p, p_left_right);
|
Chris@101
|
1762 if(p_left_right){
|
Chris@101
|
1763 NodeTraits::set_parent(p_left_right, p);
|
Chris@101
|
1764 }
|
Chris@101
|
1765 NodeTraits::set_right(p_left, p);
|
Chris@101
|
1766 NodeTraits::set_parent(p, p_left);
|
Chris@101
|
1767 }
|
Chris@101
|
1768
|
Chris@101
|
1769 // rotate p to right (with header and p's parent fixup)
|
Chris@101
|
1770 static void rotate_right(const node_ptr & p, const node_ptr & p_left, const node_ptr & p_parent, const node_ptr & header)
|
Chris@101
|
1771 {
|
Chris@101
|
1772 const bool p_was_left(NodeTraits::get_left(p_parent) == p);
|
Chris@101
|
1773 rotate_right_no_parent_fix(p, p_left);
|
Chris@101
|
1774 NodeTraits::set_parent(p_left, p_parent);
|
Chris@101
|
1775 set_child(header, p_left, p_parent, p_was_left);
|
Chris@101
|
1776 }
|
Chris@101
|
1777
|
Chris@16
|
1778 private:
|
Chris@101
|
1779
|
Chris@16
|
1780 static void subtree_to_vine(node_ptr vine_tail, std::size_t &size)
|
Chris@16
|
1781 {
|
Chris@16
|
1782 //Inspired by LibAVL:
|
Chris@16
|
1783 //It uses a clever optimization for trees with parent pointers.
|
Chris@16
|
1784 //No parent pointer is updated when transforming a tree to a vine as
|
Chris@16
|
1785 //most of them will be overriten during compression rotations.
|
Chris@16
|
1786 //A final pass must be made after the rebalancing to updated those
|
Chris@16
|
1787 //pointers not updated by tree_to_vine + compression calls
|
Chris@16
|
1788 std::size_t len = 0;
|
Chris@16
|
1789 node_ptr remainder = NodeTraits::get_right(vine_tail);
|
Chris@16
|
1790 while(remainder){
|
Chris@16
|
1791 node_ptr tempptr = NodeTraits::get_left(remainder);
|
Chris@16
|
1792 if(!tempptr){ //move vine-tail down one
|
Chris@16
|
1793 vine_tail = remainder;
|
Chris@16
|
1794 remainder = NodeTraits::get_right(remainder);
|
Chris@16
|
1795 ++len;
|
Chris@16
|
1796 }
|
Chris@16
|
1797 else{ //rotate
|
Chris@16
|
1798 NodeTraits::set_left(remainder, NodeTraits::get_right(tempptr));
|
Chris@16
|
1799 NodeTraits::set_right(tempptr, remainder);
|
Chris@16
|
1800 remainder = tempptr;
|
Chris@16
|
1801 NodeTraits::set_right(vine_tail, tempptr);
|
Chris@16
|
1802 }
|
Chris@16
|
1803 }
|
Chris@16
|
1804 size = len;
|
Chris@101
|
1805 }
|
Chris@16
|
1806
|
Chris@16
|
1807 static void compress_subtree(node_ptr scanner, std::size_t count)
|
Chris@16
|
1808 {
|
Chris@16
|
1809 while(count--){ //compress "count" spine nodes in the tree with pseudo-root scanner
|
Chris@16
|
1810 node_ptr child = NodeTraits::get_right(scanner);
|
Chris@16
|
1811 node_ptr child_right = NodeTraits::get_right(child);
|
Chris@16
|
1812 NodeTraits::set_right(scanner, child_right);
|
Chris@16
|
1813 //Avoid setting the parent of child_right
|
Chris@16
|
1814 scanner = child_right;
|
Chris@16
|
1815 node_ptr scanner_left = NodeTraits::get_left(scanner);
|
Chris@16
|
1816 NodeTraits::set_right(child, scanner_left);
|
Chris@16
|
1817 if(scanner_left)
|
Chris@16
|
1818 NodeTraits::set_parent(scanner_left, child);
|
Chris@16
|
1819 NodeTraits::set_left(scanner, child);
|
Chris@16
|
1820 NodeTraits::set_parent(child, scanner);
|
Chris@16
|
1821 }
|
Chris@16
|
1822 }
|
Chris@16
|
1823
|
Chris@16
|
1824 static void vine_to_subtree(const node_ptr & super_root, std::size_t count)
|
Chris@16
|
1825 {
|
Chris@101
|
1826 const std::size_t one_szt = 1u;
|
Chris@101
|
1827 std::size_t leaf_nodes = count + one_szt - std::size_t(one_szt << detail::floor_log2(count + one_szt));
|
Chris@16
|
1828 compress_subtree(super_root, leaf_nodes); //create deepest leaves
|
Chris@16
|
1829 std::size_t vine_nodes = count - leaf_nodes;
|
Chris@16
|
1830 while(vine_nodes > 1){
|
Chris@16
|
1831 vine_nodes /= 2;
|
Chris@16
|
1832 compress_subtree(super_root, vine_nodes);
|
Chris@16
|
1833 }
|
Chris@16
|
1834
|
Chris@16
|
1835 //Update parents of nodes still in the in the original vine line
|
Chris@16
|
1836 //as those have not been updated by subtree_to_vine or compress_subtree
|
Chris@16
|
1837 for ( node_ptr q = super_root, p = NodeTraits::get_right(super_root)
|
Chris@16
|
1838 ; p
|
Chris@16
|
1839 ; q = p, p = NodeTraits::get_right(p)){
|
Chris@16
|
1840 NodeTraits::set_parent(p, q);
|
Chris@16
|
1841 }
|
Chris@16
|
1842 }
|
Chris@16
|
1843
|
Chris@16
|
1844 //! <b>Requires</b>: "n" must be a node inserted in a tree.
|
Chris@16
|
1845 //!
|
Chris@16
|
1846 //! <b>Effects</b>: Returns a pointer to the header node of the tree.
|
Chris@16
|
1847 //!
|
Chris@16
|
1848 //! <b>Complexity</b>: Logarithmic.
|
Chris@16
|
1849 //!
|
Chris@16
|
1850 //! <b>Throws</b>: Nothing.
|
Chris@16
|
1851 static node_ptr get_root(const node_ptr & node)
|
Chris@16
|
1852 {
|
Chris@16
|
1853 BOOST_INTRUSIVE_INVARIANT_ASSERT((!inited(node)));
|
Chris@16
|
1854 node_ptr x = NodeTraits::get_parent(node);
|
Chris@16
|
1855 if(x){
|
Chris@101
|
1856 while(!base_type::is_header(x)){
|
Chris@16
|
1857 x = NodeTraits::get_parent(x);
|
Chris@16
|
1858 }
|
Chris@16
|
1859 return x;
|
Chris@16
|
1860 }
|
Chris@16
|
1861 else{
|
Chris@16
|
1862 return node;
|
Chris@16
|
1863 }
|
Chris@16
|
1864 }
|
Chris@16
|
1865
|
Chris@16
|
1866 template <class Cloner, class Disposer>
|
Chris@16
|
1867 static node_ptr clone_subtree
|
Chris@16
|
1868 (const const_node_ptr &source_parent, const node_ptr &target_parent
|
Chris@16
|
1869 , Cloner cloner, Disposer disposer
|
Chris@16
|
1870 , node_ptr &leftmost_out, node_ptr &rightmost_out
|
Chris@16
|
1871 )
|
Chris@16
|
1872 {
|
Chris@16
|
1873 node_ptr target_sub_root = target_parent;
|
Chris@16
|
1874 node_ptr source_root = NodeTraits::get_parent(source_parent);
|
Chris@16
|
1875 if(!source_root){
|
Chris@16
|
1876 leftmost_out = rightmost_out = source_root;
|
Chris@16
|
1877 }
|
Chris@16
|
1878 else{
|
Chris@16
|
1879 //We'll calculate leftmost and rightmost nodes while iterating
|
Chris@16
|
1880 node_ptr current = source_root;
|
Chris@16
|
1881 node_ptr insertion_point = target_sub_root = cloner(current);
|
Chris@16
|
1882
|
Chris@16
|
1883 //We'll calculate leftmost and rightmost nodes while iterating
|
Chris@16
|
1884 node_ptr leftmost = target_sub_root;
|
Chris@16
|
1885 node_ptr rightmost = target_sub_root;
|
Chris@16
|
1886
|
Chris@16
|
1887 //First set the subroot
|
Chris@16
|
1888 NodeTraits::set_left(target_sub_root, node_ptr());
|
Chris@16
|
1889 NodeTraits::set_right(target_sub_root, node_ptr());
|
Chris@16
|
1890 NodeTraits::set_parent(target_sub_root, target_parent);
|
Chris@16
|
1891
|
Chris@16
|
1892 dispose_subtree_disposer<Disposer> rollback(disposer, target_sub_root);
|
Chris@16
|
1893 while(true) {
|
Chris@16
|
1894 //First clone left nodes
|
Chris@16
|
1895 if( NodeTraits::get_left(current) &&
|
Chris@16
|
1896 !NodeTraits::get_left(insertion_point)) {
|
Chris@16
|
1897 current = NodeTraits::get_left(current);
|
Chris@16
|
1898 node_ptr temp = insertion_point;
|
Chris@16
|
1899 //Clone and mark as leaf
|
Chris@16
|
1900 insertion_point = cloner(current);
|
Chris@16
|
1901 NodeTraits::set_left (insertion_point, node_ptr());
|
Chris@16
|
1902 NodeTraits::set_right (insertion_point, node_ptr());
|
Chris@16
|
1903 //Insert left
|
Chris@16
|
1904 NodeTraits::set_parent(insertion_point, temp);
|
Chris@16
|
1905 NodeTraits::set_left (temp, insertion_point);
|
Chris@16
|
1906 //Update leftmost
|
Chris@16
|
1907 if(rightmost == target_sub_root)
|
Chris@16
|
1908 leftmost = insertion_point;
|
Chris@16
|
1909 }
|
Chris@16
|
1910 //Then clone right nodes
|
Chris@16
|
1911 else if( NodeTraits::get_right(current) &&
|
Chris@16
|
1912 !NodeTraits::get_right(insertion_point)){
|
Chris@16
|
1913 current = NodeTraits::get_right(current);
|
Chris@16
|
1914 node_ptr temp = insertion_point;
|
Chris@16
|
1915 //Clone and mark as leaf
|
Chris@16
|
1916 insertion_point = cloner(current);
|
Chris@16
|
1917 NodeTraits::set_left (insertion_point, node_ptr());
|
Chris@16
|
1918 NodeTraits::set_right (insertion_point, node_ptr());
|
Chris@16
|
1919 //Insert right
|
Chris@16
|
1920 NodeTraits::set_parent(insertion_point, temp);
|
Chris@16
|
1921 NodeTraits::set_right (temp, insertion_point);
|
Chris@16
|
1922 //Update rightmost
|
Chris@16
|
1923 rightmost = insertion_point;
|
Chris@16
|
1924 }
|
Chris@16
|
1925 //If not, go up
|
Chris@16
|
1926 else if(current == source_root){
|
Chris@16
|
1927 break;
|
Chris@16
|
1928 }
|
Chris@16
|
1929 else{
|
Chris@16
|
1930 //Branch completed, go up searching more nodes to clone
|
Chris@16
|
1931 current = NodeTraits::get_parent(current);
|
Chris@16
|
1932 insertion_point = NodeTraits::get_parent(insertion_point);
|
Chris@16
|
1933 }
|
Chris@16
|
1934 }
|
Chris@16
|
1935 rollback.release();
|
Chris@16
|
1936 leftmost_out = leftmost;
|
Chris@16
|
1937 rightmost_out = rightmost;
|
Chris@16
|
1938 }
|
Chris@16
|
1939 return target_sub_root;
|
Chris@16
|
1940 }
|
Chris@16
|
1941
|
Chris@16
|
1942 template<class Disposer>
|
Chris@16
|
1943 static void dispose_subtree(node_ptr x, Disposer disposer)
|
Chris@16
|
1944 {
|
Chris@16
|
1945 while (x){
|
Chris@16
|
1946 node_ptr save(NodeTraits::get_left(x));
|
Chris@16
|
1947 if (save) {
|
Chris@16
|
1948 // Right rotation
|
Chris@16
|
1949 NodeTraits::set_left(x, NodeTraits::get_right(save));
|
Chris@16
|
1950 NodeTraits::set_right(save, x);
|
Chris@16
|
1951 }
|
Chris@16
|
1952 else {
|
Chris@16
|
1953 save = NodeTraits::get_right(x);
|
Chris@16
|
1954 init(x);
|
Chris@16
|
1955 disposer(x);
|
Chris@16
|
1956 }
|
Chris@16
|
1957 x = save;
|
Chris@16
|
1958 }
|
Chris@16
|
1959 }
|
Chris@16
|
1960
|
Chris@16
|
1961 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
1962 static node_ptr lower_bound_loop
|
Chris@16
|
1963 (node_ptr x, node_ptr y, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@16
|
1964 {
|
Chris@16
|
1965 while(x){
|
Chris@16
|
1966 if(comp(x, key)){
|
Chris@16
|
1967 x = NodeTraits::get_right(x);
|
Chris@16
|
1968 }
|
Chris@16
|
1969 else{
|
Chris@16
|
1970 y = x;
|
Chris@16
|
1971 x = NodeTraits::get_left(x);
|
Chris@16
|
1972 }
|
Chris@16
|
1973 }
|
Chris@16
|
1974 return y;
|
Chris@16
|
1975 }
|
Chris@16
|
1976
|
Chris@16
|
1977 template<class KeyType, class KeyNodePtrCompare>
|
Chris@16
|
1978 static node_ptr upper_bound_loop
|
Chris@16
|
1979 (node_ptr x, node_ptr y, const KeyType &key, KeyNodePtrCompare comp)
|
Chris@16
|
1980 {
|
Chris@16
|
1981 while(x){
|
Chris@16
|
1982 if(comp(key, x)){
|
Chris@16
|
1983 y = x;
|
Chris@16
|
1984 x = NodeTraits::get_left(x);
|
Chris@16
|
1985 }
|
Chris@16
|
1986 else{
|
Chris@16
|
1987 x = NodeTraits::get_right(x);
|
Chris@16
|
1988 }
|
Chris@16
|
1989 }
|
Chris@16
|
1990 return y;
|
Chris@16
|
1991 }
|
Chris@16
|
1992
|
Chris@101
|
1993 template<class Checker>
|
Chris@101
|
1994 static void check_subtree(const const_node_ptr& node, Checker checker, typename Checker::return_type& check_return)
|
Chris@16
|
1995 {
|
Chris@101
|
1996 const_node_ptr left = NodeTraits::get_left(node);
|
Chris@101
|
1997 const_node_ptr right = NodeTraits::get_right(node);
|
Chris@101
|
1998 typename Checker::return_type check_return_left;
|
Chris@101
|
1999 typename Checker::return_type check_return_right;
|
Chris@101
|
2000 if (left)
|
Chris@101
|
2001 {
|
Chris@101
|
2002 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(left) == node);
|
Chris@101
|
2003 check_subtree(left, checker, check_return_left);
|
Chris@16
|
2004 }
|
Chris@101
|
2005 if (right)
|
Chris@101
|
2006 {
|
Chris@101
|
2007 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(right) == node);
|
Chris@101
|
2008 check_subtree(right, checker, check_return_right);
|
Chris@16
|
2009 }
|
Chris@101
|
2010 checker(node, check_return_left, check_return_right, check_return);
|
Chris@16
|
2011 }
|
Chris@16
|
2012 };
|
Chris@16
|
2013
|
Chris@16
|
2014 /// @cond
|
Chris@16
|
2015
|
Chris@16
|
2016 template<class NodeTraits>
|
Chris@16
|
2017 struct get_algo<BsTreeAlgorithms, NodeTraits>
|
Chris@16
|
2018 {
|
Chris@16
|
2019 typedef bstree_algorithms<NodeTraits> type;
|
Chris@16
|
2020 };
|
Chris@16
|
2021
|
Chris@101
|
2022 template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
|
Chris@101
|
2023 struct get_node_checker<BsTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
|
Chris@101
|
2024 {
|
Chris@101
|
2025 typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
|
Chris@101
|
2026 };
|
Chris@101
|
2027
|
Chris@16
|
2028 /// @endcond
|
Chris@16
|
2029
|
Chris@16
|
2030 } //namespace intrusive
|
Chris@16
|
2031 } //namespace boost
|
Chris@16
|
2032
|
Chris@16
|
2033 #include <boost/intrusive/detail/config_end.hpp>
|
Chris@16
|
2034
|
Chris@16
|
2035 #endif //BOOST_INTRUSIVE_BSTREE_ALGORITHMS_HPP
|