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