1 /////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Olaf Krzikalla 2004-2006.
4 // (C) Copyright Ion Gaztanaga 2006-2008
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)
10 // See http://www.boost.org/libs/intrusive for documentation.
12 /////////////////////////////////////////////////////////////////////////////
14 #ifndef BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP
15 #define BOOST_INTRUSIVE_LINEAR_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>
26 //! linear_slist_algorithms provides basic algorithms to manipulate nodes
27 //! forming a linear singly linked list.
29 //! linear_slist_algorithms is configured with a NodeTraits class, which encapsulates the
30 //! information about the node to be manipulated. NodeTraits must support the
31 //! following interface:
35 //! <tt>node</tt>: The type of the node that forms the linear list
37 //! <tt>node_ptr</tt>: A pointer to a node
39 //! <tt>const_node_ptr</tt>: A pointer to a const node
41 //! <b>Static functions</b>:
43 //! <tt>static node_ptr get_next(const_node_ptr n);</tt>
45 //! <tt>static void set_next(node_ptr n, node_ptr next);</tt>
46 template<class NodeTraits
>
47 class linear_slist_algorithms
49 : public detail::common_slist_algorithms
<NodeTraits
>
53 typedef detail::common_slist_algorithms
<NodeTraits
> base_t
;
56 typedef typename
NodeTraits::node node
;
57 typedef typename
NodeTraits::node_ptr node_ptr
;
58 typedef typename
NodeTraits::const_node_ptr const_node_ptr
;
59 typedef NodeTraits node_traits
;
61 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
63 //! <b>Effects</b>: Constructs an non-used list element, putting the next
65 //! <tt>NodeTraits::get_next(this_node) == 0
67 //! <b>Complexity</b>: Constant
69 //! <b>Throws</b>: Nothing.
70 static void init(node_ptr this_node
);
72 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
74 //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:
75 //! or it's a not inserted node:
76 //! <tt>return !NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node</tt>
78 //! <b>Complexity</b>: Constant
80 //! <b>Throws</b>: Nothing.
81 static bool unique(const_node_ptr this_node
);
83 //! <b>Effects</b>: Returns true is "this_node" has the same state as if
84 //! it was inited using "init(node_ptr)"
86 //! <b>Complexity</b>: Constant
88 //! <b>Throws</b>: Nothing.
89 static bool inited(const_node_ptr this_node
);
91 //! <b>Requires</b>: prev_node must be in a circular list or be an empty circular list.
93 //! <b>Effects</b>: Unlinks the next node of prev_node from the circular list.
95 //! <b>Complexity</b>: Constant
97 //! <b>Throws</b>: Nothing.
98 static void unlink_after(node_ptr prev_node
);
100 //! <b>Requires</b>: prev_node and last_node must be in a circular list
101 //! or be an empty circular list.
103 //! <b>Effects</b>: Unlinks the range (prev_node, last_node) from the linear list.
105 //! <b>Complexity</b>: Constant
107 //! <b>Throws</b>: Nothing.
108 static void unlink_after(node_ptr prev_node
, node_ptr last_node
);
110 //! <b>Requires</b>: prev_node must be a node of a linear list.
112 //! <b>Effects</b>: Links this_node after prev_node in the linear list.
114 //! <b>Complexity</b>: Constant
116 //! <b>Throws</b>: Nothing.
117 static void link_after(node_ptr prev_node
, node_ptr this_node
);
119 //! <b>Requires</b>: b and e must be nodes of the same linear list or an empty range.
120 //! and p must be a node of a different linear list.
122 //! <b>Effects</b>: Removes the nodes from (b, e] range from their linear list and inserts
123 //! them after p in p's linear list.
125 //! <b>Complexity</b>: Constant
127 //! <b>Throws</b>: Nothing.
128 static void transfer_after(node_ptr p
, node_ptr b
, node_ptr e
);
130 #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
132 //! <b>Effects</b>: Constructs an empty list, making this_node the only
133 //! node of the circular list:
134 //! <tt>NodeTraits::get_next(this_node) == this_node</tt>.
136 //! <b>Complexity</b>: Constant
138 //! <b>Throws</b>: Nothing.
139 static void init_header(node_ptr this_node
)
140 { NodeTraits::set_next(this_node
, node_ptr(0)); }
142 //! <b>Requires</b>: this_node and prev_init_node must be in the same linear list.
144 //! <b>Effects</b>: Returns the previous node of this_node in the linear list starting.
145 //! the search from prev_init_node. The first node checked for equality
146 //! is NodeTraits::get_next(prev_init_node).
148 //! <b>Complexity</b>: Linear to the number of elements between prev_init_node and this_node.
150 //! <b>Throws</b>: Nothing.
151 static node_ptr
get_previous_node(node_ptr prev_init_node
, node_ptr this_node
)
152 { return base_t::get_previous_node(prev_init_node
, this_node
); }
154 //! <b>Requires</b>: this_node must be in a linear list or be an empty linear list.
156 //! <b>Effects</b>: Returns the number of nodes in a linear list. If the linear list
157 //! is empty, returns 1.
159 //! <b>Complexity</b>: Constant
161 //! <b>Throws</b>: Nothing.
162 static std::size_t count(const_node_ptr this_node
)
164 std::size_t result
= 0;
165 const_node_ptr p
= this_node
;
167 p
= NodeTraits::get_next(p
);
173 //! <b>Requires</b>: this_node and other_node must be nodes inserted
174 //! in linear lists or be empty linear lists.
176 //! <b>Effects</b>: Moves all the nodes previously chained after this_node after other_node
179 //! <b>Complexity</b>: Constant
181 //! <b>Throws</b>: Nothing.
182 static void swap_trailing_nodes(node_ptr this_node
, node_ptr other_node
)
184 node_ptr this_nxt
= NodeTraits::get_next(this_node
);
185 node_ptr other_nxt
= NodeTraits::get_next(other_node
);
186 NodeTraits::set_next(this_node
, other_nxt
);
187 NodeTraits::set_next(other_node
, this_nxt
);
190 //! <b>Effects</b>: Reverses the order of elements in the list.
192 //! <b>Returns</b>: The new first node of the list.
194 //! <b>Throws</b>: Nothing.
196 //! <b>Complexity</b>: This function is linear to the contained elements.
197 static node_ptr
reverse(node_ptr p
)
199 if(!p
) return node_ptr(0);
200 node_ptr i
= NodeTraits::get_next(p
);
203 node_ptr
nxti(NodeTraits::get_next(i
));
204 base_t::unlink_after(p
);
205 NodeTraits::set_next(i
, first
);
212 //! <b>Effects</b>: Moves the first n nodes starting at p to the end of the list.
214 //! <b>Returns</b>: A pair containing the new first and last node of the list or
215 //! if there has been any movement, a null pair if n leads to no movement.
217 //! <b>Throws</b>: Nothing.
219 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
220 static std::pair
<node_ptr
, node_ptr
> move_first_n_backwards(node_ptr p
, std::size_t n
)
222 std::pair
<node_ptr
, node_ptr
> ret(node_ptr(0), node_ptr(0));
223 //Null shift, or count() == 0 or 1, nothing to do
224 if(!n
|| !p
|| !NodeTraits::get_next(p
)){
229 bool end_found
= false;
230 node_ptr
new_last(0);
231 node_ptr
old_last(0);
233 //Now find the new last node according to the shift count.
234 //If we find 0 before finding the new last node
235 //unlink p, shortcut the search now that we know the size of the list
237 for(std::size_t i
= 1; i
<= n
; ++i
){
239 first
= NodeTraits::get_next(first
);
241 //Shortcut the shift with the modulo of the size of the list
246 //Unlink p and continue the new first node search
248 //unlink_after(new_last);
253 //If the p has not been found in the previous loop, find it
254 //starting in the new first node and unlink it
256 old_last
= base_t::get_previous_node(first
, node_ptr(0));
259 //Now link p after the new last node
260 NodeTraits::set_next(old_last
, p
);
261 NodeTraits::set_next(new_last
, node_ptr(0));
263 ret
.second
= new_last
;
267 //! <b>Effects</b>: Moves the first n nodes starting at p to the beginning of the list.
269 //! <b>Returns</b>: A pair containing the new first and last node of the list or
270 //! if there has been any movement, a null pair if n leads to no movement.
272 //! <b>Throws</b>: Nothing.
274 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
275 static std::pair
<node_ptr
, node_ptr
> move_first_n_forward(node_ptr p
, std::size_t n
)
277 std::pair
<node_ptr
, node_ptr
> ret(node_ptr(0), node_ptr(0));
278 //Null shift, or count() == 0 or 1, nothing to do
279 if(!n
|| !p
|| !NodeTraits::get_next(p
))
284 //Iterate until p is found to know where the current last node is.
285 //If the shift count is less than the size of the list, we can also obtain
286 //the position of the new last node after the shift.
287 node_ptr
old_last(first
), next_to_it
, new_last(p
);
288 std::size_t distance
= 1;
289 while(!!(next_to_it
= node_traits::get_next(old_last
))){
291 new_last
= node_traits::get_next(new_last
);
292 old_last
= next_to_it
;
294 //If the shift was bigger or equal than the size, obtain the equivalent
295 //forward shifts and find the new last node.
297 //Now find the equivalent forward shifts.
298 //Shortcut the shift with the modulo of the size of the list
299 std::size_t new_before_last_pos
= (distance
- (n
% distance
))% distance
;
300 //If the shift is a multiple of the size there is nothing to do
301 if(!new_before_last_pos
)
305 ; --new_before_last_pos
306 ; new_last
= node_traits::get_next(new_last
)){
311 //Get the first new node
312 node_ptr
new_first(node_traits::get_next(new_last
));
313 //Now put the old beginning after the old end
314 NodeTraits::set_next(old_last
, p
);
315 NodeTraits::set_next(new_last
, node_ptr(0));
316 ret
.first
= new_first
;
317 ret
.second
= new_last
;
322 } //namespace intrusive
325 #include <boost/intrusive/detail/config_end.hpp>
327 #endif //BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP