343 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| // (C) Copyright Olaf Krzikalla 2004-2006.
 | |
| // (C) Copyright Ion Gaztanaga  2006-2014
 | |
| //
 | |
| // Distributed under the Boost Software License, Version 1.0.
 | |
| //    (See accompanying file LICENSE_1_0.txt or copy at
 | |
| //          http://www.boost.org/LICENSE_1_0.txt)
 | |
| //
 | |
| // See http://www.boost.org/libs/intrusive for documentation.
 | |
| //
 | |
| /////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #ifndef BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP
 | |
| #define BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP
 | |
| 
 | |
| #include <boost/intrusive/detail/config_begin.hpp>
 | |
| #include <boost/intrusive/intrusive_fwd.hpp>
 | |
| #include <boost/intrusive/detail/common_slist_algorithms.hpp>
 | |
| #include <boost/intrusive/detail/algo_type.hpp>
 | |
| #include <cstddef>
 | |
| #include <boost/intrusive/detail/minimal_pair_header.hpp>   //std::pair
 | |
| 
 | |
| #if defined(BOOST_HAS_PRAGMA_ONCE)
 | |
| #  pragma once
 | |
| #endif
 | |
| 
 | |
| namespace boost {
 | |
| namespace intrusive {
 | |
| 
 | |
| //! linear_slist_algorithms provides basic algorithms to manipulate nodes
 | |
| //! forming a linear singly linked list.
 | |
| //!
 | |
| //! linear_slist_algorithms is configured with a NodeTraits class, which encapsulates the
 | |
| //! information about the node to be manipulated. NodeTraits must support the
 | |
| //! following interface:
 | |
| //!
 | |
| //! <b>Typedefs</b>:
 | |
| //!
 | |
| //! <tt>node</tt>: The type of the node that forms the linear list
 | |
| //!
 | |
| //! <tt>node_ptr</tt>: A pointer to a node
 | |
| //!
 | |
| //! <tt>const_node_ptr</tt>: A pointer to a const node
 | |
| //!
 | |
| //! <b>Static functions</b>:
 | |
| //!
 | |
| //! <tt>static node_ptr get_next(const_node_ptr n);</tt>
 | |
| //!
 | |
| //! <tt>static void set_next(node_ptr n, node_ptr next);</tt>
 | |
| template<class NodeTraits>
 | |
| class linear_slist_algorithms
 | |
|    /// @cond
 | |
|    : public detail::common_slist_algorithms<NodeTraits>
 | |
|    /// @endcond
 | |
| {
 | |
|    /// @cond
 | |
|    typedef detail::common_slist_algorithms<NodeTraits> base_t;
 | |
|    /// @endcond
 | |
|    public:
 | |
|    typedef typename NodeTraits::node            node;
 | |
|    typedef typename NodeTraits::node_ptr        node_ptr;
 | |
|    typedef typename NodeTraits::const_node_ptr  const_node_ptr;
 | |
|    typedef NodeTraits                           node_traits;
 | |
| 
 | |
|    #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
 | |
| 
 | |
|    //! <b>Effects</b>: Constructs an non-used list element, putting the next
 | |
|    //!   pointer to null:
 | |
|    //!  <tt>NodeTraits::get_next(this_node) == node_ptr()</tt>
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static void init(const node_ptr & this_node);
 | |
| 
 | |
|    //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:
 | |
|    //!  or it's a not inserted node:
 | |
|    //!  <tt>return node_ptr() == NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node</tt>
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static bool unique(const_node_ptr this_node);
 | |
| 
 | |
|    //! <b>Effects</b>: Returns true is "this_node" has the same state as if
 | |
|    //!  it was inited using "init(node_ptr)"
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static bool inited(const_node_ptr this_node);
 | |
| 
 | |
|    //! <b>Requires</b>: prev_node must be in a circular list or be an empty circular list.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Unlinks the next node of prev_node from the circular list.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static void unlink_after(const node_ptr & prev_node);
 | |
| 
 | |
|    //! <b>Requires</b>: prev_node and last_node must be in a circular list
 | |
|    //!  or be an empty circular list.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Unlinks the range (prev_node, last_node) from the linear list.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static void unlink_after(const node_ptr & prev_node, const node_ptr & last_node);
 | |
| 
 | |
|    //! <b>Requires</b>: prev_node must be a node of a linear list.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Links this_node after prev_node in the linear list.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static void link_after(const node_ptr & prev_node, const node_ptr & this_node);
 | |
| 
 | |
|    //! <b>Requires</b>: b and e must be nodes of the same linear list or an empty range.
 | |
|    //!   and p must be a node of a different linear list.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Removes the nodes from (b, e] range from their linear list and inserts
 | |
|    //!   them after p in p's linear list.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static void transfer_after(const node_ptr & p, const node_ptr & b, const node_ptr & e);
 | |
| 
 | |
|    #endif   //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
 | |
| 
 | |
|    //! <b>Effects</b>: Constructs an empty list, making this_node the only
 | |
|    //!   node of the circular list:
 | |
|    //!  <tt>NodeTraits::get_next(this_node) == this_node</tt>.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    BOOST_INTRUSIVE_FORCEINLINE static void init_header(const node_ptr & this_node)
 | |
|    {  NodeTraits::set_next(this_node, node_ptr ());  }
 | |
| 
 | |
|    //! <b>Requires</b>: this_node and prev_init_node must be in the same linear list.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Returns the previous node of this_node in the linear list starting.
 | |
|    //!   the search from prev_init_node. The first node checked for equality
 | |
|    //!   is NodeTraits::get_next(prev_init_node).
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Linear to the number of elements between prev_init_node and this_node.
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous_node(const node_ptr & prev_init_node, const node_ptr & this_node)
 | |
|    {  return base_t::get_previous_node(prev_init_node, this_node);   }
 | |
| 
 | |
|    //! <b>Requires</b>: this_node must be in a linear list or be an empty linear list.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Returns the number of nodes in a linear list. If the linear list
 | |
|    //!  is empty, returns 1.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Linear
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static std::size_t count(const const_node_ptr & this_node)
 | |
|    {
 | |
|       std::size_t result = 0;
 | |
|       const_node_ptr p = this_node;
 | |
|       do{
 | |
|          p = NodeTraits::get_next(p);
 | |
|          ++result;
 | |
|       } while (p);
 | |
|       return result;
 | |
|    }
 | |
| 
 | |
|    //! <b>Requires</b>: this_node and other_node must be nodes inserted
 | |
|    //!  in linear lists or be empty linear lists.
 | |
|    //!
 | |
|    //! <b>Effects</b>: Moves all the nodes previously chained after this_node after other_node
 | |
|    //!   and vice-versa.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Constant
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    static void swap_trailing_nodes(const node_ptr & this_node, const node_ptr & other_node)
 | |
|    {
 | |
|       node_ptr this_nxt    = NodeTraits::get_next(this_node);
 | |
|       node_ptr other_nxt   = NodeTraits::get_next(other_node);
 | |
|       NodeTraits::set_next(this_node, other_nxt);
 | |
|       NodeTraits::set_next(other_node, this_nxt);
 | |
|    }
 | |
| 
 | |
|    //! <b>Effects</b>: Reverses the order of elements in the list.
 | |
|    //!
 | |
|    //! <b>Returns</b>: The new first node of the list.
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: This function is linear to the contained elements.
 | |
|    static node_ptr reverse(const node_ptr & p)
 | |
|    {
 | |
|       if(!p) return node_ptr();
 | |
|       node_ptr i = NodeTraits::get_next(p);
 | |
|       node_ptr first(p);
 | |
|       while(i){
 | |
|          node_ptr nxti(NodeTraits::get_next(i));
 | |
|          base_t::unlink_after(p);
 | |
|          NodeTraits::set_next(i, first);
 | |
|          first = i;
 | |
|          i = nxti;
 | |
|       }
 | |
|       return first;
 | |
|    }
 | |
| 
 | |
|    //! <b>Effects</b>: Moves the first n nodes starting at p to the end of the list.
 | |
|    //!
 | |
|    //! <b>Returns</b>: A pair containing the new first and last node of the list or
 | |
|    //!   if there has been any movement, a null pair if n leads to no movement.
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
 | |
|    static std::pair<node_ptr, node_ptr> move_first_n_backwards(const node_ptr & p, std::size_t n)
 | |
|    {
 | |
|       std::pair<node_ptr, node_ptr> ret;
 | |
|       //Null shift, or count() == 0 or 1, nothing to do
 | |
|       if(!n || !p || !NodeTraits::get_next(p)){
 | |
|          return ret;
 | |
|       }
 | |
| 
 | |
|       node_ptr first = p;
 | |
|       bool end_found = false;
 | |
|       node_ptr new_last = node_ptr();
 | |
|       node_ptr old_last = node_ptr();
 | |
| 
 | |
|       //Now find the new last node according to the shift count.
 | |
|       //If we find 0 before finding the new last node
 | |
|       //unlink p, shortcut the search now that we know the size of the list
 | |
|       //and continue.
 | |
|       for(std::size_t i = 1; i <= n; ++i){
 | |
|          new_last = first;
 | |
|          first = NodeTraits::get_next(first);
 | |
|          if(first == node_ptr()){
 | |
|             //Shortcut the shift with the modulo of the size of the list
 | |
|             n %= i;
 | |
|             if(!n)   return ret;
 | |
|             old_last = new_last;
 | |
|             i = 0;
 | |
|             //Unlink p and continue the new first node search
 | |
|             first = p;
 | |
|             //unlink_after(new_last);
 | |
|             end_found = true;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       //If the p has not been found in the previous loop, find it
 | |
|       //starting in the new first node and unlink it
 | |
|       if(!end_found){
 | |
|          old_last = base_t::get_previous_node(first, node_ptr());
 | |
|       }
 | |
| 
 | |
|       //Now link p after the new last node
 | |
|       NodeTraits::set_next(old_last, p);
 | |
|       NodeTraits::set_next(new_last, node_ptr());
 | |
|       ret.first   = first;
 | |
|       ret.second  = new_last;
 | |
|       return ret;
 | |
|    }
 | |
| 
 | |
|    //! <b>Effects</b>: Moves the first n nodes starting at p to the beginning of the list.
 | |
|    //!
 | |
|    //! <b>Returns</b>: A pair containing the new first and last node of the list or
 | |
|    //!   if there has been any movement, a null pair if n leads to no movement.
 | |
|    //!
 | |
|    //! <b>Throws</b>: Nothing.
 | |
|    //!
 | |
|    //! <b>Complexity</b>: Linear to the number of elements plus the number moved positions.
 | |
|    static std::pair<node_ptr, node_ptr> move_first_n_forward(const node_ptr & p, std::size_t n)
 | |
|    {
 | |
|       std::pair<node_ptr, node_ptr> ret;
 | |
|       //Null shift, or count() == 0 or 1, nothing to do
 | |
|       if(!n || !p || !NodeTraits::get_next(p))
 | |
|          return ret;
 | |
| 
 | |
|       node_ptr first  = p;
 | |
| 
 | |
|       //Iterate until p is found to know where the current last node is.
 | |
|       //If the shift count is less than the size of the list, we can also obtain
 | |
|       //the position of the new last node after the shift.
 | |
|       node_ptr old_last(first), next_to_it, new_last(p);
 | |
|       std::size_t distance = 1;
 | |
|       while(!!(next_to_it = node_traits::get_next(old_last))){
 | |
|          if(distance++ > n)
 | |
|             new_last = node_traits::get_next(new_last);
 | |
|          old_last = next_to_it;
 | |
|       }
 | |
|       //If the shift was bigger or equal than the size, obtain the equivalent
 | |
|       //forward shifts and find the new last node.
 | |
|       if(distance <= n){
 | |
|          //Now find the equivalent forward shifts.
 | |
|          //Shortcut the shift with the modulo of the size of the list
 | |
|          std::size_t new_before_last_pos = (distance - (n % distance))% distance;
 | |
|          //If the shift is a multiple of the size there is nothing to do
 | |
|          if(!new_before_last_pos)
 | |
|             return ret;
 | |
| 
 | |
|          for( new_last = p
 | |
|             ; --new_before_last_pos
 | |
|             ; new_last = node_traits::get_next(new_last)){
 | |
|             //empty
 | |
|          }
 | |
|       }
 | |
| 
 | |
|       //Get the first new node
 | |
|       node_ptr new_first(node_traits::get_next(new_last));
 | |
|       //Now put the old beginning after the old end
 | |
|       NodeTraits::set_next(old_last, p);
 | |
|       NodeTraits::set_next(new_last, node_ptr());
 | |
|       ret.first   = new_first;
 | |
|       ret.second  = new_last;
 | |
|       return ret;
 | |
|    }
 | |
| };
 | |
| 
 | |
| /// @cond
 | |
| 
 | |
| template<class NodeTraits>
 | |
| struct get_algo<LinearSListAlgorithms, NodeTraits>
 | |
| {
 | |
|    typedef linear_slist_algorithms<NodeTraits> type;
 | |
| };
 | |
| 
 | |
| /// @endcond
 | |
| 
 | |
| } //namespace intrusive
 | |
| } //namespace boost
 | |
| 
 | |
| #include <boost/intrusive/detail/config_end.hpp>
 | |
| 
 | |
| #endif //BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP
 | 
