|
||||
File indexing completed on 2025-01-18 09:38:40
0001 ///////////////////////////////////////////////////////////////////////////// 0002 // 0003 // (C) Copyright Olaf Krzikalla 2004-2006. 0004 // (C) Copyright Ion Gaztanaga 2006-2014 0005 // 0006 // Distributed under the Boost Software License, Version 1.0. 0007 // (See accompanying file LICENSE_1_0.txt or copy at 0008 // http://www.boost.org/LICENSE_1_0.txt) 0009 // 0010 // See http://www.boost.org/libs/intrusive for documentation. 0011 // 0012 ///////////////////////////////////////////////////////////////////////////// 0013 0014 #ifndef BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP 0015 #define BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP 0016 0017 #include <cstddef> 0018 #include <boost/intrusive/detail/config_begin.hpp> 0019 #include <boost/intrusive/intrusive_fwd.hpp> 0020 #include <boost/intrusive/detail/common_slist_algorithms.hpp> 0021 #include <boost/intrusive/detail/uncast.hpp> 0022 #include <boost/intrusive/detail/algo_type.hpp> 0023 0024 #if defined(BOOST_HAS_PRAGMA_ONCE) 0025 # pragma once 0026 #endif 0027 0028 namespace boost { 0029 namespace intrusive { 0030 0031 //! circular_slist_algorithms provides basic algorithms to manipulate nodes 0032 //! forming a circular singly linked list. An empty circular list is formed by a node 0033 //! whose pointer to the next node points to itself. 0034 //! 0035 //! circular_slist_algorithms is configured with a NodeTraits class, which encapsulates the 0036 //! information about the node to be manipulated. NodeTraits must support the 0037 //! following interface: 0038 //! 0039 //! <b>Typedefs</b>: 0040 //! 0041 //! <tt>node</tt>: The type of the node that forms the circular list 0042 //! 0043 //! <tt>node_ptr</tt>: A pointer to a node 0044 //! 0045 //! <tt>const_node_ptr</tt>: A pointer to a const node 0046 //! 0047 //! <b>Static functions</b>: 0048 //! 0049 //! <tt>static node_ptr get_next(const_node_ptr n);</tt> 0050 //! 0051 //! <tt>static void set_next(node_ptr n, node_ptr next);</tt> 0052 template<class NodeTraits> 0053 class circular_slist_algorithms 0054 /// @cond 0055 : public detail::common_slist_algorithms<NodeTraits> 0056 /// @endcond 0057 { 0058 /// @cond 0059 typedef detail::common_slist_algorithms<NodeTraits> base_t; 0060 /// @endcond 0061 public: 0062 typedef typename NodeTraits::node node; 0063 typedef typename NodeTraits::node_ptr node_ptr; 0064 typedef typename NodeTraits::const_node_ptr const_node_ptr; 0065 typedef NodeTraits node_traits; 0066 0067 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) 0068 0069 //! <b>Effects</b>: Constructs an non-used list element, putting the next 0070 //! pointer to null: 0071 //! <tt>NodeTraits::get_next(this_node) == node_ptr()</tt> 0072 //! 0073 //! <b>Complexity</b>: Constant 0074 //! 0075 //! <b>Throws</b>: Nothing. 0076 static void init(node_ptr this_node) BOOST_NOEXCEPT; 0077 0078 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list. 0079 //! 0080 //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list: 0081 //! or it's a not inserted node: 0082 //! <tt>return node_ptr() == NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node</tt> 0083 //! 0084 //! <b>Complexity</b>: Constant 0085 //! 0086 //! <b>Throws</b>: Nothing. 0087 static bool unique(const_node_ptr this_node) BOOST_NOEXCEPT; 0088 0089 //! <b>Effects</b>: Returns true is "this_node" has the same state as 0090 //! if it was inited using "init(node_ptr)" 0091 //! 0092 //! <b>Complexity</b>: Constant 0093 //! 0094 //! <b>Throws</b>: Nothing. 0095 static bool inited(const_node_ptr this_node) BOOST_NOEXCEPT; 0096 0097 //! <b>Requires</b>: prev_node must be in a circular list or be an empty circular list. 0098 //! 0099 //! <b>Effects</b>: Unlinks the next node of prev_node from the circular list. 0100 //! 0101 //! <b>Complexity</b>: Constant 0102 //! 0103 //! <b>Throws</b>: Nothing. 0104 static void unlink_after(node_ptr prev_node) BOOST_NOEXCEPT; 0105 0106 //! <b>Requires</b>: prev_node and last_node must be in a circular list 0107 //! or be an empty circular list. 0108 //! 0109 //! <b>Effects</b>: Unlinks the range (prev_node, last_node) from the circular list. 0110 //! 0111 //! <b>Complexity</b>: Constant 0112 //! 0113 //! <b>Throws</b>: Nothing. 0114 static void unlink_after(node_ptr prev_node, node_ptr last_node) BOOST_NOEXCEPT; 0115 0116 //! <b>Requires</b>: prev_node must be a node of a circular list. 0117 //! 0118 //! <b>Effects</b>: Links this_node after prev_node in the circular list. 0119 //! 0120 //! <b>Complexity</b>: Constant 0121 //! 0122 //! <b>Throws</b>: Nothing. 0123 static void link_after(node_ptr prev_node, node_ptr this_node) BOOST_NOEXCEPT; 0124 0125 //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range. 0126 //! and p must be a node of a different circular list. 0127 //! 0128 //! <b>Effects</b>: Removes the nodes from (b, e] range from their circular list and inserts 0129 //! them after p in p's circular list. 0130 //! 0131 //! <b>Complexity</b>: Constant 0132 //! 0133 //! <b>Throws</b>: Nothing. 0134 static void transfer_after(node_ptr p, node_ptr b, node_ptr e) BOOST_NOEXCEPT; 0135 0136 #else 0137 0138 using base_t::transfer_after; 0139 0140 #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) 0141 0142 //! <b>Effects</b>: Constructs an empty list, making this_node the only 0143 //! node of the circular list: 0144 //! <tt>NodeTraits::get_next(this_node) == this_node</tt>. 0145 //! 0146 //! <b>Complexity</b>: Constant 0147 //! 0148 //! <b>Throws</b>: Nothing. 0149 BOOST_INTRUSIVE_FORCEINLINE static void init_header(node_ptr this_node) BOOST_NOEXCEPT 0150 { NodeTraits::set_next(this_node, this_node); } 0151 0152 //! <b>Requires</b>: 'p' is the first node of a list. 0153 //! 0154 //! <b>Effects</b>: Returns a pointer to a node that represents the "end" (one past end) node 0155 //! 0156 //! <b>Complexity</b>: Constant time. 0157 //! 0158 //! <b>Throws</b>: Nothing. 0159 BOOST_INTRUSIVE_FORCEINLINE static node_ptr end_node(const_node_ptr p) BOOST_NOEXCEPT 0160 { return detail::uncast(p); } 0161 0162 //! <b>Effects</b>: Returns true if this_node_points to an empty list. 0163 //! 0164 //! <b>Complexity</b>: Constant 0165 //! 0166 //! <b>Throws</b>: Nothing. 0167 BOOST_INTRUSIVE_FORCEINLINE static bool is_empty(const_node_ptr this_node) BOOST_NOEXCEPT 0168 { return NodeTraits::get_next(this_node) == this_node; } 0169 0170 //! <b>Effects</b>: Returns true if this_node points to a sentinel node. 0171 //! 0172 //! <b>Complexity</b>: Constant 0173 //! 0174 //! <b>Throws</b>: Nothing. 0175 BOOST_INTRUSIVE_FORCEINLINE static bool is_sentinel(const_node_ptr this_node) BOOST_NOEXCEPT 0176 { return NodeTraits::get_next(this_node) == node_ptr(); } 0177 0178 //! <b>Effects</b>: Marks this node as a "sentinel" node, a special state that is different from "empty", 0179 //! that can be used to mark a special state of the list 0180 //! 0181 //! <b>Complexity</b>: Constant 0182 //! 0183 //! <b>Throws</b>: Nothing. 0184 BOOST_INTRUSIVE_FORCEINLINE static void set_sentinel(node_ptr this_node) BOOST_NOEXCEPT 0185 { NodeTraits::set_next(this_node, node_ptr()); } 0186 0187 //! <b>Requires</b>: this_node and prev_init_node must be in the same circular list. 0188 //! 0189 //! <b>Effects</b>: Returns the previous node of this_node in the circular list starting. 0190 //! the search from prev_init_node. The first node checked for equality 0191 //! is NodeTraits::get_next(prev_init_node). 0192 //! 0193 //! <b>Complexity</b>: Linear to the number of elements between prev_init_node and this_node. 0194 //! 0195 //! <b>Throws</b>: Nothing. 0196 BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous_node(node_ptr prev_init_node, node_ptr this_node) BOOST_NOEXCEPT 0197 { return base_t::get_previous_node(prev_init_node, this_node); } 0198 0199 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list. 0200 //! 0201 //! <b>Effects</b>: Returns the previous node of this_node in the circular list. 0202 //! 0203 //! <b>Complexity</b>: Linear to the number of elements in the circular list. 0204 //! 0205 //! <b>Throws</b>: Nothing. 0206 BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous_node(node_ptr this_node) BOOST_NOEXCEPT 0207 { return base_t::get_previous_node(this_node, this_node); } 0208 0209 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list. 0210 //! 0211 //! <b>Effects</b>: Returns the previous node of the previous node of this_node in the circular list. 0212 //! 0213 //! <b>Complexity</b>: Linear to the number of elements in the circular list. 0214 //! 0215 //! <b>Throws</b>: Nothing. 0216 BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous_previous_node(node_ptr this_node) BOOST_NOEXCEPT 0217 { return get_previous_previous_node(this_node, this_node); } 0218 0219 //! <b>Requires</b>: this_node and p must be in the same circular list. 0220 //! 0221 //! <b>Effects</b>: Returns the previous node of the previous node of this_node in the 0222 //! circular list starting. the search from p. The first node checked 0223 //! for equality is NodeTraits::get_next((NodeTraits::get_next(p)). 0224 //! 0225 //! <b>Complexity</b>: Linear to the number of elements in the circular list. 0226 //! 0227 //! <b>Throws</b>: Nothing. 0228 static node_ptr get_previous_previous_node(node_ptr p, node_ptr this_node) BOOST_NOEXCEPT 0229 { 0230 node_ptr p_next = NodeTraits::get_next(p); 0231 node_ptr p_next_next = NodeTraits::get_next(p_next); 0232 while (this_node != p_next_next){ 0233 p = p_next; 0234 p_next = p_next_next; 0235 p_next_next = NodeTraits::get_next(p_next); 0236 } 0237 return p; 0238 } 0239 0240 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list. 0241 //! 0242 //! <b>Effects</b>: Returns the number of nodes in a circular list. If the circular list 0243 //! is empty, returns 1. 0244 //! 0245 //! <b>Complexity</b>: Linear 0246 //! 0247 //! <b>Throws</b>: Nothing. 0248 static std::size_t count(const_node_ptr this_node) BOOST_NOEXCEPT 0249 { 0250 std::size_t result = 0; 0251 const_node_ptr p = this_node; 0252 do{ 0253 p = NodeTraits::get_next(p); 0254 ++result; 0255 } while (p != this_node); 0256 return result; 0257 } 0258 0259 //! <b>Requires</b>: this_node must be in a circular list, be an empty circular list or be inited. 0260 //! 0261 //! <b>Effects</b>: Unlinks the node from the circular list. 0262 //! 0263 //! <b>Complexity</b>: Linear to the number of elements in the circular list 0264 //! 0265 //! <b>Throws</b>: Nothing. 0266 static void unlink(node_ptr this_node) BOOST_NOEXCEPT 0267 { 0268 if(NodeTraits::get_next(this_node)) 0269 base_t::unlink_after(get_previous_node(this_node)); 0270 } 0271 0272 //! <b>Requires</b>: nxt_node must be a node of a circular list. 0273 //! 0274 //! <b>Effects</b>: Links this_node before nxt_node in the circular list. 0275 //! 0276 //! <b>Complexity</b>: Linear to the number of elements in the circular list. 0277 //! 0278 //! <b>Throws</b>: Nothing. 0279 BOOST_INTRUSIVE_FORCEINLINE static void link_before (node_ptr nxt_node, node_ptr this_node) BOOST_NOEXCEPT 0280 { base_t::link_after(get_previous_node(nxt_node), this_node); } 0281 0282 //! <b>Requires</b>: this_node and other_node must be nodes inserted 0283 //! in circular lists or be empty circular lists. 0284 //! 0285 //! <b>Effects</b>: Swaps the position of the nodes: this_node is inserted in 0286 //! other_nodes position in the second circular list and the other_node is inserted 0287 //! in this_node's position in the first circular list. 0288 //! 0289 //! <b>Complexity</b>: Linear to number of elements of both lists 0290 //! 0291 //! <b>Throws</b>: Nothing. 0292 static void swap_nodes(node_ptr this_node, node_ptr other_node) BOOST_NOEXCEPT 0293 { 0294 if (other_node == this_node) 0295 return; 0296 const node_ptr this_next = NodeTraits::get_next(this_node); 0297 const node_ptr other_next = NodeTraits::get_next(other_node); 0298 const bool this_null = !this_next; 0299 const bool other_null = !other_next; 0300 const bool this_empty = this_next == this_node; 0301 const bool other_empty = other_next == other_node; 0302 0303 if(!(other_null || other_empty)){ 0304 NodeTraits::set_next(this_next == other_node ? other_node : get_previous_node(other_node), this_node ); 0305 } 0306 if(!(this_null | this_empty)){ 0307 NodeTraits::set_next(other_next == this_node ? this_node : get_previous_node(this_node), other_node ); 0308 } 0309 NodeTraits::set_next(this_node, other_empty ? this_node : (other_next == this_node ? other_node : other_next) ); 0310 NodeTraits::set_next(other_node, this_empty ? other_node : (this_next == other_node ? this_node : this_next ) ); 0311 } 0312 0313 //! <b>Effects</b>: Reverses the order of elements in the list. 0314 //! 0315 //! <b>Throws</b>: Nothing. 0316 //! 0317 //! <b>Complexity</b>: This function is linear to the contained elements. 0318 static void reverse(node_ptr p) BOOST_NOEXCEPT 0319 { 0320 node_ptr i = NodeTraits::get_next(p), e(p); 0321 for (;;) { 0322 node_ptr nxt(NodeTraits::get_next(i)); 0323 if (nxt == e) 0324 break; 0325 base_t::transfer_after(e, i, nxt); 0326 } 0327 } 0328 0329 //! <b>Effects</b>: Moves the node p n positions towards the end of the list. 0330 //! 0331 //! <b>Returns</b>: The previous node of p after the function if there has been any movement, 0332 //! Null if n leads to no movement. 0333 //! 0334 //! <b>Throws</b>: Nothing. 0335 //! 0336 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions. 0337 static node_ptr move_backwards(node_ptr p, std::size_t n) BOOST_NOEXCEPT 0338 { 0339 //Null shift, nothing to do 0340 if(!n) return node_ptr(); 0341 node_ptr first = NodeTraits::get_next(p); 0342 0343 //count() == 1 or 2, nothing to do 0344 if(NodeTraits::get_next(first) == p) 0345 return node_ptr(); 0346 0347 bool end_found = false; 0348 node_ptr new_last = node_ptr(); 0349 0350 //Now find the new last node according to the shift count. 0351 //If we find p before finding the new last node 0352 //unlink p, shortcut the search now that we know the size of the list 0353 //and continue. 0354 for(std::size_t i = 1; i <= n; ++i){ 0355 new_last = first; 0356 first = NodeTraits::get_next(first); 0357 if(first == p){ 0358 //Shortcut the shift with the modulo of the size of the list 0359 n %= i; 0360 if(!n) 0361 return node_ptr(); 0362 i = 0; 0363 //Unlink p and continue the new first node search 0364 first = NodeTraits::get_next(p); 0365 base_t::unlink_after(new_last); 0366 end_found = true; 0367 } 0368 } 0369 0370 //If the p has not been found in the previous loop, find it 0371 //starting in the new first node and unlink it 0372 if(!end_found){ 0373 base_t::unlink_after(base_t::get_previous_node(first, p)); 0374 } 0375 0376 //Now link p after the new last node 0377 base_t::link_after(new_last, p); 0378 return new_last; 0379 } 0380 0381 //! <b>Effects</b>: Moves the node p n positions towards the beginning of the list. 0382 //! 0383 //! <b>Returns</b>: The previous node of p after the function if there has been any movement, 0384 //! Null if n leads equals to no movement. 0385 //! 0386 //! <b>Throws</b>: Nothing. 0387 //! 0388 //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions. 0389 static node_ptr move_forward(node_ptr p, std::size_t n) BOOST_NOEXCEPT 0390 { 0391 //Null shift, nothing to do 0392 if(!n) return node_ptr(); 0393 node_ptr first = node_traits::get_next(p); 0394 0395 //count() == 1 or 2, nothing to do 0396 if(node_traits::get_next(first) == p) return node_ptr(); 0397 0398 //Iterate until p is found to know where the current last node is. 0399 //If the shift count is less than the size of the list, we can also obtain 0400 //the position of the new last node after the shift. 0401 node_ptr old_last(first), next_to_it, new_last(p); 0402 std::size_t distance = 1; 0403 while(p != (next_to_it = node_traits::get_next(old_last))){ 0404 if(++distance > n) 0405 new_last = node_traits::get_next(new_last); 0406 old_last = next_to_it; 0407 } 0408 //If the shift was bigger or equal than the size, obtain the equivalent 0409 //forward shifts and find the new last node. 0410 if(distance <= n){ 0411 //Now find the equivalent forward shifts. 0412 //Shortcut the shift with the modulo of the size of the list 0413 std::size_t new_before_last_pos = (distance - (n % distance))% distance; 0414 //If the shift is a multiple of the size there is nothing to do 0415 if(!new_before_last_pos) return node_ptr(); 0416 0417 for( new_last = p 0418 ; new_before_last_pos-- 0419 ; new_last = node_traits::get_next(new_last)){ 0420 //empty 0421 } 0422 } 0423 0424 //Now unlink p and link it after the new last node 0425 base_t::unlink_after(old_last); 0426 base_t::link_after(new_last, p); 0427 return new_last; 0428 } 0429 0430 //! <b>Requires</b>: other must be a list and p must be a node of a different list. 0431 //! 0432 //! <b>Effects</b>: Transfers all nodes from other after p in p's list. 0433 //! 0434 //! <b>Complexity</b>: Linear 0435 //! 0436 //! <b>Throws</b>: Nothing. 0437 static void transfer_after(node_ptr p, node_ptr other) BOOST_NOEXCEPT 0438 { 0439 node_ptr other_last((get_previous_node)(other)); 0440 base_t::transfer_after(p, other, other_last); 0441 } 0442 0443 //! <b>Requires</b>: "disposer" must be an object function 0444 //! taking a node_ptr parameter and shouldn't throw. 0445 //! 0446 //! <b>Effects</b>: Unlinks all nodes reachable from p (but not p) and calls 0447 //! <tt>void disposer::operator()(node_ptr)</tt> for every node of the list 0448 //! where p is linked. 0449 //! 0450 //! <b>Returns</b>: The number of disposed nodes 0451 //! 0452 //! <b>Complexity</b>: Linear to the number of element of the list. 0453 //! 0454 //! <b>Throws</b>: Nothing. 0455 template<class Disposer> 0456 BOOST_INTRUSIVE_FORCEINLINE static std::size_t detach_and_dispose(node_ptr p, Disposer disposer) BOOST_NOEXCEPT 0457 { return base_t::unlink_after_and_dispose(p, p, disposer); } 0458 }; 0459 0460 /// @cond 0461 0462 template<class NodeTraits> 0463 struct get_algo<CircularSListAlgorithms, NodeTraits> 0464 { 0465 typedef circular_slist_algorithms<NodeTraits> type; 0466 }; 0467 0468 /// @endcond 0469 0470 } //namespace intrusive 0471 } //namespace boost 0472 0473 #include <boost/intrusive/detail/config_end.hpp> 0474 0475 #endif //BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |