fix doc example typo
[boost.git] / boost / intrusive / circular_slist_algorithms.hpp
blobcb9cb3b19d097e1d520440bddda09de93668e11f
1 /////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Olaf Krzikalla 2004-2006.
4 // (C) Copyright Ion Gaztanaga 2006-2008
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 //
10 // See http://www.boost.org/libs/intrusive for documentation.
12 /////////////////////////////////////////////////////////////////////////////
14 #ifndef BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP
15 #define BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP
17 #include <boost/intrusive/detail/config_begin.hpp>
18 #include <boost/intrusive/intrusive_fwd.hpp>
19 #include <boost/intrusive/detail/common_slist_algorithms.hpp>
20 #include <boost/intrusive/detail/assert.hpp>
21 #include <cstddef>
23 namespace boost {
24 namespace intrusive {
26 //! circular_slist_algorithms provides basic algorithms to manipulate nodes
27 //! forming a circular singly linked list. An empty circular list is formed by a node
28 //! whose pointer to the next node points to itself.
29 //!
30 //! circular_slist_algorithms is configured with a NodeTraits class, which encapsulates the
31 //! information about the node to be manipulated. NodeTraits must support the
32 //! following interface:
33 //!
34 //! <b>Typedefs</b>:
35 //!
36 //! <tt>node</tt>: The type of the node that forms the circular list
37 //!
38 //! <tt>node_ptr</tt>: A pointer to a node
39 //!
40 //! <tt>const_node_ptr</tt>: A pointer to a const node
41 //!
42 //! <b>Static functions</b>:
43 //!
44 //! <tt>static node_ptr get_next(const_node_ptr n);</tt>
45 //!
46 //! <tt>static void set_next(node_ptr n, node_ptr next);</tt>
47 template<class NodeTraits>
48 class circular_slist_algorithms
49 /// @cond
50 : public detail::common_slist_algorithms<NodeTraits>
51 /// @endcond
53 /// @cond
54 typedef detail::common_slist_algorithms<NodeTraits> base_t;
55 /// @endcond
56 public:
57 typedef typename NodeTraits::node node;
58 typedef typename NodeTraits::node_ptr node_ptr;
59 typedef typename NodeTraits::const_node_ptr const_node_ptr;
60 typedef NodeTraits node_traits;
62 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
64 //! <b>Effects</b>: Constructs an non-used list element, putting the next
65 //! pointer to null:
66 //! <tt>NodeTraits::get_next(this_node) == 0
67 //!
68 //! <b>Complexity</b>: Constant
69 //!
70 //! <b>Throws</b>: Nothing.
71 static void init(node_ptr this_node);
73 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
74 //!
75 //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:
76 //! or it's a not inserted node:
77 //! <tt>return !NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node</tt>
78 //!
79 //! <b>Complexity</b>: Constant
80 //!
81 //! <b>Throws</b>: Nothing.
82 static bool unique(const_node_ptr this_node);
84 //! <b>Effects</b>: Returns true is "this_node" has the same state as
85 //! if it was inited using "init(node_ptr)"
86 //!
87 //! <b>Complexity</b>: Constant
88 //!
89 //! <b>Throws</b>: Nothing.
90 static bool inited(const_node_ptr this_node);
92 //! <b>Requires</b>: prev_node must be in a circular list or be an empty circular list.
93 //!
94 //! <b>Effects</b>: Unlinks the next node of prev_node from the circular list.
95 //!
96 //! <b>Complexity</b>: Constant
97 //!
98 //! <b>Throws</b>: Nothing.
99 static void unlink_after(node_ptr prev_node);
101 //! <b>Requires</b>: prev_node and last_node must be in a circular list
102 //! or be an empty circular list.
104 //! <b>Effects</b>: Unlinks the range (prev_node, last_node) from the circular list.
106 //! <b>Complexity</b>: Constant
108 //! <b>Throws</b>: Nothing.
109 static void unlink_after(node_ptr prev_node, node_ptr last_node);
111 //! <b>Requires</b>: prev_node must be a node of a circular list.
112 //!
113 //! <b>Effects</b>: Links this_node after prev_node in the circular list.
114 //!
115 //! <b>Complexity</b>: Constant
116 //!
117 //! <b>Throws</b>: Nothing.
118 static void link_after(node_ptr prev_node, node_ptr this_node);
120 //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
121 //! and p must be a node of a different circular list.
122 //!
123 //! <b>Effects</b>: Removes the nodes from (b, e] range from their circular list and inserts
124 //! them after p in p's circular list.
125 //!
126 //! <b>Complexity</b>: Constant
127 //!
128 //! <b>Throws</b>: Nothing.
129 static void transfer_after(node_ptr p, node_ptr b, node_ptr e);
131 #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
133 //! <b>Effects</b>: Constructs an empty list, making this_node the only
134 //! node of the circular list:
135 //! <tt>NodeTraits::get_next(this_node) == this_node</tt>.
136 //!
137 //! <b>Complexity</b>: Constant
138 //!
139 //! <b>Throws</b>: Nothing.
140 static void init_header(node_ptr this_node)
141 { NodeTraits::set_next(this_node, this_node); }
143 //! <b>Requires</b>: this_node and prev_init_node must be in the same circular list.
144 //!
145 //! <b>Effects</b>: Returns the previous node of this_node in the circular list starting.
146 //! the search from prev_init_node. The first node checked for equality
147 //! is NodeTraits::get_next(prev_init_node).
148 //!
149 //! <b>Complexity</b>: Linear to the number of elements between prev_init_node and this_node.
150 //!
151 //! <b>Throws</b>: Nothing.
152 static node_ptr get_previous_node(node_ptr prev_init_node, node_ptr this_node)
153 { return base_t::get_previous_node(prev_init_node, this_node); }
155 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
156 //!
157 //! <b>Effects</b>: Returns the previous node of this_node in the circular list.
158 //!
159 //! <b>Complexity</b>: Linear to the number of elements in the circular list.
160 //!
161 //! <b>Throws</b>: Nothing.
162 static node_ptr get_previous_node(node_ptr this_node)
163 { return base_t::get_previous_node(this_node, this_node); }
165 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
166 //!
167 //! <b>Effects</b>: Returns the previous node of the previous node of this_node in the circular list.
168 //!
169 //! <b>Complexity</b>: Linear to the number of elements in the circular list.
170 //!
171 //! <b>Throws</b>: Nothing.
172 static node_ptr get_previous_previous_node(node_ptr this_node)
173 { return get_previous_previous_node(this_node, this_node); }
175 //! <b>Requires</b>: this_node and prev_prev_init_node must be in the same circular list.
176 //!
177 //! <b>Effects</b>: Returns the previous node of the previous node of this_node in the
178 //! circular list starting. the search from prev_init_node. The first node checked
179 //! for equality is NodeTraits::get_next((NodeTraits::get_next(prev_prev_init_node)).
180 //!
181 //! <b>Complexity</b>: Linear to the number of elements in the circular list.
182 //!
183 //! <b>Throws</b>: Nothing.
184 static node_ptr get_previous_previous_node(node_ptr prev_prev_init_node, node_ptr this_node)
186 node_ptr p = prev_prev_init_node;
187 node_ptr p_next = NodeTraits::get_next(p);
188 node_ptr p_next_next = NodeTraits::get_next(p_next);
189 while (this_node != p_next_next){
190 p = p_next;
191 p_next = p_next_next;
192 p_next_next = NodeTraits::get_next(p_next);
194 return p;
197 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
198 //!
199 //! <b>Effects</b>: Returns the number of nodes in a circular list. If the circular list
200 //! is empty, returns 1.
201 //!
202 //! <b>Complexity</b>: Constant
203 //!
204 //! <b>Throws</b>: Nothing.
205 static std::size_t count(const_node_ptr this_node)
207 std::size_t result = 0;
208 const_node_ptr p = this_node;
210 p = NodeTraits::get_next(p);
211 ++result;
212 } while (p != this_node);
213 return result;
216 //! <b>Requires</b>: this_node must be in a circular list, be an empty circular list or be inited.
217 //!
218 //! <b>Effects</b>: Unlinks the node from the circular list.
219 //!
220 //! <b>Complexity</b>: Linear to the number of elements in the circular list
221 //!
222 //! <b>Throws</b>: Nothing.
223 static void unlink(node_ptr this_node)
225 if(NodeTraits::get_next(this_node))
226 base_t::unlink_after(get_previous_node(this_node));
229 //! <b>Requires</b>: nxt_node must be a node of a circular list.
230 //!
231 //! <b>Effects</b>: Links this_node before nxt_node in the circular list.
232 //!
233 //! <b>Complexity</b>: Linear to the number of elements in the circular list.
234 //!
235 //! <b>Throws</b>: Nothing.
236 static void link_before (node_ptr nxt_node, node_ptr this_node)
237 { base_t::link_after(get_previous_node(nxt_node), this_node); }
239 //! <b>Requires</b>: this_node and other_node must be nodes inserted
240 //! in circular lists or be empty circular lists.
241 //!
242 //! <b>Effects</b>: Swaps the position of the nodes: this_node is inserted in
243 //! other_nodes position in the second circular list and the other_node is inserted
244 //! in this_node's position in the first circular list.
245 //!
246 //! <b>Complexity</b>: Linear to number of elements of both lists
247 //!
248 //! <b>Throws</b>: Nothing.
249 static void swap_nodes(node_ptr this_node, node_ptr other_node)
251 if (other_node == this_node)
252 return;
253 bool this_inited = base_t::inited(this_node);
254 bool other_inited = base_t::inited(other_node);
255 if(this_inited){
256 base_t::init_header(this_node);
258 if(other_inited){
259 base_t::init_header(other_node);
262 bool empty1 = base_t::unique(this_node);
263 bool empty2 = base_t::unique(other_node);
264 node_ptr prev_this (get_previous_node(this_node));
265 node_ptr prev_other(get_previous_node(other_node));
267 node_ptr this_next (NodeTraits::get_next(this_node));
268 node_ptr other_next(NodeTraits::get_next(other_node));
269 NodeTraits::set_next(this_node, other_next);
270 NodeTraits::set_next(other_node, this_next);
271 NodeTraits::set_next(empty1 ? other_node : prev_this, other_node);
272 NodeTraits::set_next(empty2 ? this_node : prev_other, this_node);
274 if(this_inited){
275 base_t::init(other_node);
277 if(other_inited){
278 base_t::init(this_node);
282 //! <b>Effects</b>: Reverses the order of elements in the list.
283 //!
284 //! <b>Throws</b>: Nothing.
285 //!
286 //! <b>Complexity</b>: This function is linear to the contained elements.
287 static void reverse(node_ptr p)
289 node_ptr i = NodeTraits::get_next(p), e(p);
290 for (;;) {
291 node_ptr nxt(NodeTraits::get_next(i));
292 if (nxt == e)
293 break;
294 base_t::transfer_after(e, i, nxt);
298 //! <b>Effects</b>: Moves the node p n positions towards the end of the list.
300 //! <b>Returns</b>: The previous node of p after the function if there has been any movement,
301 //! Null if n leads to no movement.
303 //! <b>Throws</b>: Nothing.
304 //!
305 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
306 static node_ptr move_backwards(node_ptr p, std::size_t n)
308 //Null shift, nothing to do
309 if(!n) return node_ptr(0);
310 node_ptr first = NodeTraits::get_next(p);
312 //count() == 1 or 2, nothing to do
313 if(NodeTraits::get_next(first) == p)
314 return node_ptr(0);
316 bool end_found = false;
317 node_ptr new_last(0);
319 //Now find the new last node according to the shift count.
320 //If we find p before finding the new last node
321 //unlink p, shortcut the search now that we know the size of the list
322 //and continue.
323 for(std::size_t i = 1; i <= n; ++i){
324 new_last = first;
325 first = NodeTraits::get_next(first);
326 if(first == p){
327 //Shortcut the shift with the modulo of the size of the list
328 n %= i;
329 if(!n)
330 return node_ptr(0);
331 i = 0;
332 //Unlink p and continue the new first node search
333 first = NodeTraits::get_next(p);
334 base_t::unlink_after(new_last);
335 end_found = true;
339 //If the p has not been found in the previous loop, find it
340 //starting in the new first node and unlink it
341 if(!end_found){
342 base_t::unlink_after(base_t::get_previous_node(first, p));
345 //Now link p after the new last node
346 base_t::link_after(new_last, p);
347 return new_last;
350 //! <b>Effects</b>: Moves the node p n positions towards the beginning of the list.
351 //!
352 //! <b>Returns</b>: The previous node of p after the function if there has been any movement,
353 //! Null if n leads equals to no movement.
354 //!
355 //! <b>Throws</b>: Nothing.
356 //!
357 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
358 static node_ptr move_forward(node_ptr p, std::size_t n)
360 //Null shift, nothing to do
361 if(!n) return node_ptr(0);
362 node_ptr first = node_traits::get_next(p);
364 //count() == 1 or 2, nothing to do
365 if(node_traits::get_next(first) == p) return node_ptr(0);
367 //Iterate until p is found to know where the current last node is.
368 //If the shift count is less than the size of the list, we can also obtain
369 //the position of the new last node after the shift.
370 node_ptr old_last(first), next_to_it, new_last(p);
371 std::size_t distance = 1;
372 while(p != (next_to_it = node_traits::get_next(old_last))){
373 if(++distance > n)
374 new_last = node_traits::get_next(new_last);
375 old_last = next_to_it;
377 //If the shift was bigger or equal than the size, obtain the equivalent
378 //forward shifts and find the new last node.
379 if(distance <= n){
380 //Now find the equivalent forward shifts.
381 //Shortcut the shift with the modulo of the size of the list
382 std::size_t new_before_last_pos = (distance - (n % distance))% distance;
383 //If the shift is a multiple of the size there is nothing to do
384 if(!new_before_last_pos) return node_ptr(0);
386 for( new_last = p
387 ; new_before_last_pos--
388 ; new_last = node_traits::get_next(new_last)){
389 //empty
393 //Now unlink p and link it after the new last node
394 base_t::unlink_after(old_last);
395 base_t::link_after(new_last, p);
396 return new_last;
400 } //namespace intrusive
401 } //namespace boost
403 #include <boost/intrusive/detail/config_end.hpp>
405 #endif //BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP