1 ///////////////////////////////////////////////////////////////////////////// 2 // 3 // (C) Copyright Olaf Krzikalla 2004-2006. 4 // (C) Copyright Ion Gaztanaga 2006-2014 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. 11 // 12 ///////////////////////////////////////////////////////////////////////////// 13 14 #ifndef BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP 15 #define BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP 16 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/algo_type.hpp> 21 #include <cstddef> 22 #include <boost/intrusive/detail/minimal_pair_header.hpp> //std::pair 23 24 #if defined(BOOST_HAS_PRAGMA_ONCE) 25 # pragma once 26 #endif 27 28 namespace boost { 29 namespace intrusive { 30 31 //! linear_slist_algorithms provides basic algorithms to manipulate nodes 32 //! forming a linear singly linked list. 33 //! 34 //! linear_slist_algorithms is configured with a NodeTraits class, which encapsulates the 35 //! information about the node to be manipulated. NodeTraits must support the 36 //! following interface: 37 //! 38 //! <b>Typedefs</b>: 39 //! 40 //! <tt>node</tt>: The type of the node that forms the linear list 41 //! 42 //! <tt>node_ptr</tt>: A pointer to a node 43 //! 44 //! <tt>const_node_ptr</tt>: A pointer to a const node 45 //! 46 //! <b>Static functions</b>: 47 //! 48 //! <tt>static node_ptr get_next(const_node_ptr n);</tt> 49 //! 50 //! <tt>static void set_next(node_ptr n, node_ptr next);</tt> 51 template<class NodeTraits> 52 class linear_slist_algorithms 53 /// @cond 54 : public detail::common_slist_algorithms<NodeTraits> 55 /// @endcond 56 { 57 /// @cond 58 typedef detail::common_slist_algorithms<NodeTraits> base_t; 59 /// @endcond 60 public: 61 typedef typename NodeTraits::node node; 62 typedef typename NodeTraits::node_ptr node_ptr; 63 typedef typename NodeTraits::const_node_ptr const_node_ptr; 64 typedef NodeTraits node_traits; 65 66 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) 67 68 //! <b>Effects</b>: Constructs an non-used list element, putting the next 69 //! pointer to null: 70 //! <tt>NodeTraits::get_next(this_node) == node_ptr()</tt> 71 //! 72 //! <b>Complexity</b>: Constant 73 //! 74 //! <b>Throws</b>: Nothing. 75 static void init(const node_ptr & this_node); 76 77 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list. 78 //! 79 //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list: 80 //! or it's a not inserted node: 81 //! <tt>return node_ptr() == NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node</tt> 82 //! 83 //! <b>Complexity</b>: Constant 84 //! 85 //! <b>Throws</b>: Nothing. 86 static bool unique(const_node_ptr this_node); 87 88 //! <b>Effects</b>: Returns true is "this_node" has the same state as if 89 //! it was inited using "init(node_ptr)" 90 //! 91 //! <b>Complexity</b>: Constant 92 //! 93 //! <b>Throws</b>: Nothing. 94 static bool inited(const_node_ptr this_node); 95 96 //! <b>Requires</b>: prev_node must be in a circular list or be an empty circular list. 97 //! 98 //! <b>Effects</b>: Unlinks the next node of prev_node from the circular list. 99 //! 100 //! <b>Complexity</b>: Constant 101 //! 102 //! <b>Throws</b>: Nothing. 103 static void unlink_after(const node_ptr & prev_node); 104 105 //! <b>Requires</b>: prev_node and last_node must be in a circular list 106 //! or be an empty circular list. 107 //! 108 //! <b>Effects</b>: Unlinks the range (prev_node, last_node) from the linear list. 109 //! 110 //! <b>Complexity</b>: Constant 111 //! 112 //! <b>Throws</b>: Nothing. 113 static void unlink_after(const node_ptr & prev_node, const node_ptr & last_node); 114 115 //! <b>Requires</b>: prev_node must be a node of a linear list. 116 //! 117 //! <b>Effects</b>: Links this_node after prev_node in the linear list. 118 //! 119 //! <b>Complexity</b>: Constant 120 //! 121 //! <b>Throws</b>: Nothing. 122 static void link_after(const node_ptr & prev_node, const node_ptr & this_node); 123 124 //! <b>Requires</b>: b and e must be nodes of the same linear list or an empty range. 125 //! and p must be a node of a different linear list. 126 //! 127 //! <b>Effects</b>: Removes the nodes from (b, e] range from their linear list and inserts 128 //! them after p in p's linear list. 129 //! 130 //! <b>Complexity</b>: Constant 131 //! 132 //! <b>Throws</b>: Nothing. 133 static void transfer_after(const node_ptr & p, const node_ptr & b, const node_ptr & e); 134 135 #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) 136 137 //! <b>Effects</b>: Constructs an empty list, making this_node the only 138 //! node of the circular list: 139 //! <tt>NodeTraits::get_next(this_node) == this_node</tt>. 140 //! 141 //! <b>Complexity</b>: Constant 142 //! 143 //! <b>Throws</b>: Nothing. init_header(const node_ptr & this_node)144 BOOST_INTRUSIVE_FORCEINLINE static void init_header(const node_ptr & this_node) 145 { NodeTraits::set_next(this_node, node_ptr ()); } 146 147 //! <b>Requires</b>: this_node and prev_init_node must be in the same linear list. 148 //! 149 //! <b>Effects</b>: Returns the previous node of this_node in the linear list starting. 150 //! the search from prev_init_node. The first node checked for equality 151 //! is NodeTraits::get_next(prev_init_node). 152 //! 153 //! <b>Complexity</b>: Linear to the number of elements between prev_init_node and this_node. 154 //! 155 //! <b>Throws</b>: Nothing. get_previous_node(const node_ptr & prev_init_node,const node_ptr & this_node)156 BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous_node(const node_ptr & prev_init_node, const node_ptr & this_node) 157 { return base_t::get_previous_node(prev_init_node, this_node); } 158 159 //! <b>Requires</b>: this_node must be in a linear list or be an empty linear list. 160 //! 161 //! <b>Effects</b>: Returns the number of nodes in a linear list. If the linear list 162 //! is empty, returns 1. 163 //! 164 //! <b>Complexity</b>: Linear 165 //! 166 //! <b>Throws</b>: Nothing. count(const const_node_ptr & this_node)167 static std::size_t count(const const_node_ptr & this_node) 168 { 169 std::size_t result = 0; 170 const_node_ptr p = this_node; 171 do{ 172 p = NodeTraits::get_next(p); 173 ++result; 174 } while (p); 175 return result; 176 } 177 178 //! <b>Requires</b>: this_node and other_node must be nodes inserted 179 //! in linear lists or be empty linear lists. 180 //! 181 //! <b>Effects</b>: Moves all the nodes previously chained after this_node after other_node 182 //! and vice-versa. 183 //! 184 //! <b>Complexity</b>: Constant 185 //! 186 //! <b>Throws</b>: Nothing. swap_trailing_nodes(node_ptr this_node,node_ptr other_node)187 static void swap_trailing_nodes(node_ptr this_node, node_ptr other_node) 188 { 189 node_ptr this_nxt = NodeTraits::get_next(this_node); 190 node_ptr other_nxt = NodeTraits::get_next(other_node); 191 NodeTraits::set_next(this_node, other_nxt); 192 NodeTraits::set_next(other_node, this_nxt); 193 } 194 195 //! <b>Effects</b>: Reverses the order of elements in the list. 196 //! 197 //! <b>Returns</b>: The new first node of the list. 198 //! 199 //! <b>Throws</b>: Nothing. 200 //! 201 //! <b>Complexity</b>: This function is linear to the contained elements. reverse(node_ptr p)202 static node_ptr reverse(node_ptr p) 203 { 204 if(!p) return node_ptr(); 205 node_ptr i = NodeTraits::get_next(p); 206 node_ptr first(p); 207 while(i){ 208 node_ptr nxti(NodeTraits::get_next(i)); 209 base_t::unlink_after(p); 210 NodeTraits::set_next(i, first); 211 first = i; 212 i = nxti; 213 } 214 return first; 215 } 216 217 //! <b>Effects</b>: Moves the first n nodes starting at p to the end of the list. 218 //! 219 //! <b>Returns</b>: A pair containing the new first and last node of the list or 220 //! if there has been any movement, a null pair if n leads to no movement. 221 //! 222 //! <b>Throws</b>: Nothing. 223 //! 224 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions. move_first_n_backwards(node_ptr p,std::size_t n)225 static std::pair<node_ptr, node_ptr> move_first_n_backwards(node_ptr p, std::size_t n) 226 { 227 std::pair<node_ptr, node_ptr> ret; 228 //Null shift, or count() == 0 or 1, nothing to do 229 if(!n || !p || !NodeTraits::get_next(p)){ 230 return ret; 231 } 232 233 node_ptr first = p; 234 bool end_found = false; 235 node_ptr new_last = node_ptr(); 236 node_ptr old_last = node_ptr(); 237 238 //Now find the new last node according to the shift count. 239 //If we find 0 before finding the new last node 240 //unlink p, shortcut the search now that we know the size of the list 241 //and continue. 242 for(std::size_t i = 1; i <= n; ++i){ 243 new_last = first; 244 first = NodeTraits::get_next(first); 245 if(first == node_ptr()){ 246 //Shortcut the shift with the modulo of the size of the list 247 n %= i; 248 if(!n) return ret; 249 old_last = new_last; 250 i = 0; 251 //Unlink p and continue the new first node search 252 first = p; 253 //unlink_after(new_last); 254 end_found = true; 255 } 256 } 257 258 //If the p has not been found in the previous loop, find it 259 //starting in the new first node and unlink it 260 if(!end_found){ 261 old_last = base_t::get_previous_node(first, node_ptr()); 262 } 263 264 //Now link p after the new last node 265 NodeTraits::set_next(old_last, p); 266 NodeTraits::set_next(new_last, node_ptr()); 267 ret.first = first; 268 ret.second = new_last; 269 return ret; 270 } 271 272 //! <b>Effects</b>: Moves the first n nodes starting at p to the beginning of the list. 273 //! 274 //! <b>Returns</b>: A pair containing the new first and last node of the list or 275 //! if there has been any movement, a null pair if n leads to no movement. 276 //! 277 //! <b>Throws</b>: Nothing. 278 //! 279 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions. move_first_n_forward(node_ptr p,std::size_t n)280 static std::pair<node_ptr, node_ptr> move_first_n_forward(node_ptr p, std::size_t n) 281 { 282 std::pair<node_ptr, node_ptr> ret; 283 //Null shift, or count() == 0 or 1, nothing to do 284 if(!n || !p || !NodeTraits::get_next(p)) 285 return ret; 286 287 node_ptr first = p; 288 289 //Iterate until p is found to know where the current last node is. 290 //If the shift count is less than the size of the list, we can also obtain 291 //the position of the new last node after the shift. 292 node_ptr old_last(first), next_to_it, new_last(p); 293 std::size_t distance = 1; 294 while(!!(next_to_it = node_traits::get_next(old_last))){ 295 if(distance++ > n) 296 new_last = node_traits::get_next(new_last); 297 old_last = next_to_it; 298 } 299 //If the shift was bigger or equal than the size, obtain the equivalent 300 //forward shifts and find the new last node. 301 if(distance <= n){ 302 //Now find the equivalent forward shifts. 303 //Shortcut the shift with the modulo of the size of the list 304 std::size_t new_before_last_pos = (distance - (n % distance))% distance; 305 //If the shift is a multiple of the size there is nothing to do 306 if(!new_before_last_pos) 307 return ret; 308 309 for( new_last = p 310 ; --new_before_last_pos 311 ; new_last = node_traits::get_next(new_last)){ 312 //empty 313 } 314 } 315 316 //Get the first new node 317 node_ptr new_first(node_traits::get_next(new_last)); 318 //Now put the old beginning after the old end 319 NodeTraits::set_next(old_last, p); 320 NodeTraits::set_next(new_last, node_ptr()); 321 ret.first = new_first; 322 ret.second = new_last; 323 return ret; 324 } 325 }; 326 327 /// @cond 328 329 template<class NodeTraits> 330 struct get_algo<LinearSListAlgorithms, NodeTraits> 331 { 332 typedef linear_slist_algorithms<NodeTraits> type; 333 }; 334 335 /// @endcond 336 337 } //namespace intrusive 338 } //namespace boost 339 340 #include <boost/intrusive/detail/config_end.hpp> 341 342 #endif //BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP 343