Back to home page

EIC code displayed by LXR

 
 

    


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