diff --git a/example/doc_list_algorithms.cpp b/example/doc_list_algorithms.cpp index 0d1277d..7b4fc89 100644 --- a/example/doc_list_algorithms.cpp +++ b/example/doc_list_algorithms.cpp @@ -38,7 +38,7 @@ int main() //Create an empty doubly linked list container: //"one" will be the first node of the container - algo::init(&one); + algo::init_header(&one); assert(algo::count(&one) == 1); //Now add a new node before "one" diff --git a/example/doc_slist_algorithms.cpp b/example/doc_slist_algorithms.cpp index d13d333..d89b678 100644 --- a/example/doc_slist_algorithms.cpp +++ b/example/doc_slist_algorithms.cpp @@ -36,7 +36,7 @@ int main() //Create an empty singly linked list container: //"one" will be the first node of the container - algo::init(&one); + algo::init_header(&one); assert(algo::count(&one) == 1); //Now add a new node diff --git a/include/boost/intrusive/circular_list_algorithms.hpp b/include/boost/intrusive/circular_list_algorithms.hpp index 5e28e19..7d442b7 100644 --- a/include/boost/intrusive/circular_list_algorithms.hpp +++ b/include/boost/intrusive/circular_list_algorithms.hpp @@ -54,6 +54,27 @@ class circular_list_algorithms typedef typename NodeTraits::const_node_ptr const_node_ptr; typedef NodeTraits node_traits; + //! Effects: Constructs an non-used list element, so that + //! inited(this_node) == true + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init(node_ptr this_node) + { + NodeTraits::set_next(this_node, 0); + NodeTraits::set_previous(this_node, 0); + } + + //! Effects: Returns true is "this_node" is in a non-used state + //! as if it was initialized by the "init" function. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool inited(const_node_ptr this_node) + { return !NodeTraits::get_next(this_node); } + //! Effects: Constructs an empty list, making this_node the only //! node of the circular list: //! NodeTraits::get_next(this_node) == NodeTraits::get_previous(this_node) @@ -62,11 +83,12 @@ class circular_list_algorithms //! Complexity: Constant //! //! Throws: Nothing. - static void init(node_ptr this_node) + static void init_header(node_ptr this_node) { NodeTraits::set_next(this_node, this_node); NodeTraits::set_previous(this_node, this_node); - } + } + //! Requires: this_node must be in a circular list or be an empty circular list. //! @@ -76,8 +98,11 @@ class circular_list_algorithms //! Complexity: Constant //! //! Throws: Nothing. - static bool unique(const_node_ptr this_node) - { return NodeTraits::get_next(this_node) == this_node; } + static bool unique(const_node_ptr this_node) + { + node_ptr next = NodeTraits::get_next(this_node); + return !next || next == this_node; + } //! Requires: this_node must be in a circular list or be an empty circular list. //! @@ -107,11 +132,16 @@ class circular_list_algorithms //! Throws: Nothing. static node_ptr unlink(node_ptr this_node) { - node_ptr next(NodeTraits::get_next(this_node)); - node_ptr prev(NodeTraits::get_previous(this_node)); - NodeTraits::set_next(prev, next); - NodeTraits::set_previous(next, prev); - return next; + if(NodeTraits::get_next(this_node)){ + node_ptr next(NodeTraits::get_next(this_node)); + node_ptr prev(NodeTraits::get_previous(this_node)); + NodeTraits::set_next(prev, next); + NodeTraits::set_previous(next, prev); + return next; + } + else{ + return this_node; + } } //! Requires: b and e must be nodes of the same circular list or an empty range. @@ -229,6 +259,17 @@ class circular_list_algorithms public: static void swap_nodes(node_ptr this_node, node_ptr other_node) { + if (other_node == this_node) + return; + bool this_inited = inited(this_node); + bool other_inited = inited(other_node); + if(this_inited){ + init_header(this_node); + } + if(other_inited){ + init_header(other_node); + } + node_ptr next_this(NodeTraits::get_next(this_node)); node_ptr prev_this(NodeTraits::get_previous(this_node)); node_ptr next_other(NodeTraits::get_next(other_node)); @@ -238,6 +279,13 @@ class circular_list_algorithms swap_next(prev_this, prev_other); swap_next(this_node, other_node); swap_prev(this_node, other_node); + + if(this_inited){ + init(other_node); + } + if(other_inited){ + init(this_node); + } } //! Requires: b and e must be nodes of the same circular list or an empty range. @@ -254,8 +302,8 @@ class circular_list_algorithms { if (b != e) { node_ptr prev_p(NodeTraits::get_previous(p)); - node_ptr prev_e(NodeTraits::get_previous(e)); node_ptr prev_b(NodeTraits::get_previous(b)); + node_ptr prev_e(NodeTraits::get_previous(e)); NodeTraits::set_next(prev_e, p); NodeTraits::set_previous(p, prev_e); NodeTraits::set_next(prev_b, e); @@ -308,6 +356,47 @@ class circular_list_algorithms f = n; } } + + //! Effects: Moves the node p n positions towards the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of moved positions. + static void move_backwards(node_ptr p, std::size_t n) + { + //Null shift, nothing to do + if(!n) return; + node_ptr first = NodeTraits::get_next(p); + //size() == 0 or 1, nothing to do + if(first == NodeTraits::get_previous(p)) return; + unlink(p); + //Now get the new first node + while(n--){ + first = NodeTraits::get_next(first); + } + link_before(first, p); + } + + //! Effects: Moves the node p n positions towards the beginning of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of moved positions. + static void move_forward(node_ptr p, std::size_t n) + { + //Null shift, nothing to do + if(!n) return; + node_ptr last = NodeTraits::get_previous(p); + //size() == 0 or 1, nothing to do + if(last == NodeTraits::get_next(p)) return; + + unlink(p); + //Now get the new last node + while(n--){ + last = NodeTraits::get_previous(last); + } + link_after(last, p); + } }; } //namespace intrusive diff --git a/include/boost/intrusive/circular_slist_algorithms.hpp b/include/boost/intrusive/circular_slist_algorithms.hpp index 20dcafa..2768261 100644 --- a/include/boost/intrusive/circular_slist_algorithms.hpp +++ b/include/boost/intrusive/circular_slist_algorithms.hpp @@ -16,6 +16,7 @@ #include #include +#include #include namespace boost { @@ -25,7 +26,7 @@ namespace intrusive { //! forming a circular singly linked list. An empty circular list is formed by a node //! whose pointer to the next node points to itself. //! -//! circular_slist_algorithms is configured with a NodeTraits class, which capsulates the +//! circular_slist_algorithms is configured with a NodeTraits class, which encapsulates the //! information about the node to be manipulated. NodeTraits must support the //! following interface: //! @@ -72,11 +73,13 @@ class circular_slist_algorithms //! Throws: Nothing. static node_ptr get_previous_node(node_ptr prev_init_node, node_ptr this_node) { - node_ptr p = prev_init_node; + node_ptr p = prev_init_node; for( node_ptr p_next ; this_node != (p_next = NodeTraits::get_next(p)) ; p = p_next){ - //empty + //Logic error: possible use of linear lists with + //operations only permitted with circular lists + BOOST_INTRUSIVE_INVARIANT_ASSERT(p); } return p; } @@ -115,25 +118,46 @@ class circular_slist_algorithms //! Effects: Constructs an empty list, making this_node the only //! node of the circular list: - //! NodeTraits::get_next(this_node) == NodeTraits::get_previous(this_node) - //! == this_node. + //! NodeTraits::get_next(this_node) == this_node. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init_header(node_ptr this_node) + { NodeTraits::set_next(this_node, this_node); } + + //! Effects: Constructs an non-used list element, putting the next + //! pointer to null: + //! NodeTraits::get_next(this_node) == 0 //! //! Complexity: Constant //! //! Throws: Nothing. static void init(node_ptr this_node) - { NodeTraits::set_next(this_node, this_node); } + { NodeTraits::set_next(this_node, 0); } //! Requires: this_node must be in a circular list or be an empty circular list. //! //! Effects: Returns true is "this_node" is the only node of a circular list: - //! return NodeTraits::get_next(this_node) == this_node + //! or it's a not inserted node: + //! return !NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node or //! //! Complexity: Constant //! //! Throws: Nothing. - static bool unique(const_node_ptr this_node) - { return NodeTraits::get_next(this_node) == this_node; } + static bool unique(const_node_ptr this_node) + { + node_ptr next = NodeTraits::get_next(this_node); + return !next || next == this_node; + } + + //! Effects: Returns true is "this_node" has the same state as if it was inited using "init(node_ptr)" + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool inited(const_node_ptr this_node) + { return !NodeTraits::get_next(this_node); } //! Requires: this_node must be in a circular list or be an empty circular list. //! @@ -165,7 +189,7 @@ class circular_slist_algorithms { node_ptr this_node(NodeTraits::get_next(prev_node)); NodeTraits::set_next(prev_node, NodeTraits::get_next(this_node)); - NodeTraits::set_next(this_node, this_node); + //NodeTraits::set_next(this_node, this_node); } //! Requires: nxt_node must be in a circular list or be an empty circular list. @@ -181,7 +205,7 @@ class circular_slist_algorithms unlink_after(prev_to_erase); } - //! Requires: this_node must be in a circular list or be an empty circular list. + //! Requires: this_node must be in a circular list, be an empty circular list or be inited. //! //! Effects: Unlinks the node from the circular list. //! @@ -189,7 +213,10 @@ class circular_slist_algorithms //! //! Throws: Nothing. static void unlink(node_ptr this_node) - { unlink_after(get_previous_node(this_node)); } + { + if(NodeTraits::get_next(this_node)) + unlink_after(get_previous_node(this_node)); + } //! Requires: prev_node must be a node of a circular list. //! @@ -200,8 +227,7 @@ class circular_slist_algorithms //! Throws: Nothing. static void link_after(node_ptr prev_node, node_ptr this_node) { - node_ptr this_nxt = NodeTraits::get_next(prev_node); - NodeTraits::set_next(this_node, this_nxt); + NodeTraits::set_next(this_node, NodeTraits::get_next(prev_node)); NodeTraits::set_next(prev_node, this_node); } @@ -229,6 +255,15 @@ class circular_slist_algorithms { if (other_node == this_node) return; + bool this_inited = inited(this_node); + bool other_inited = inited(other_node); + if(this_inited){ + init_header(this_node); + } + if(other_inited){ + init_header(other_node); + } + bool empty1 = unique(this_node); bool empty2 = unique(other_node); node_ptr prev_this (get_previous_node(this_node)); @@ -240,12 +275,19 @@ class circular_slist_algorithms NodeTraits::set_next(other_node, this_next); NodeTraits::set_next(empty1 ? other_node : prev_this, other_node); NodeTraits::set_next(empty2 ? this_node : prev_other, this_node); + + if(this_inited){ + init(other_node); + } + if(other_inited){ + init(this_node); + } } //! Requires: b and e must be nodes of the same circular list or an empty range. //! and p must be a node of a different circular list. //! - //! Effects: Removes the nodes from [b, e) range from their circular list and inserts + //! Effects: Removes the nodes from (b, e] range from their circular list and inserts //! them after p in p's circular list. //! //! Complexity: Constant @@ -278,6 +320,99 @@ class circular_slist_algorithms transfer_after(e, i, nxt); } } + + //! Effects: Moves the node p n positions towards the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static void move_backwards(node_ptr p, std::size_t n) + { + //Null shift, nothing to do + if(!n) return; + node_ptr first = NodeTraits::get_next(p); + + //count() == 1 or 2, nothing to do + if(NodeTraits::get_next(first) == p) + return; + + bool end_found = false; + node_ptr new_last(0); + + //Now find the new last node according to the shift count. + //If we find p 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 == p){ + //Shortcut the shift with the modulo of the size of the list + n %= i; + if(!n) + return; + i = 0; + //Unlink p and continue the new first node search + first = NodeTraits::get_next(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){ + unlink_after(get_previous_node(first, p)); + } + + //Now link p after the new last node + link_after(new_last, p); + } + + //! Effects: Moves the node p n positions towards the beginning of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static void move_forward(node_ptr p, std::size_t n) + { + //Null shift, nothing to do + if(!n) return; + node_ptr first = node_traits::get_next(p); + + //count() == 1 or 2, nothing to do + if(node_traits::get_next(first) == p) return; + + //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(p != (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; + + for( new_last = p + ; new_before_last_pos-- + ; new_last = node_traits::get_next(new_last)){ + //empty + } + } + + //Now unlink p and link it after the new last node + unlink_after(old_last); + link_after(new_last, p); + } }; } //namespace intrusive diff --git a/include/boost/intrusive/detail/tree_algorithms.hpp b/include/boost/intrusive/detail/tree_algorithms.hpp index 1a6c045..7cf320c 100644 --- a/include/boost/intrusive/detail/tree_algorithms.hpp +++ b/include/boost/intrusive/detail/tree_algorithms.hpp @@ -137,9 +137,9 @@ class tree_algorithms { return uncast(header); } //! Requires: node is a node of the tree or an node initialized - //! by init(...). + //! by init(...) or init_node. //! - //! Effects: Returns true if the node is initialized by init(). + //! Effects: Returns true if the node is initialized by init() or init_node(). //! //! Complexity: Constant time. //! diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp index 2528aba..e8b3bb3 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -498,8 +498,8 @@ inline std::size_t floor_log2 (std::size_t x) inline float fast_log2 (float val) { - boost::uint32_t * const exp_ptr = - static_cast (static_cast(&val)); + boost::uint32_t * exp_ptr = + static_cast(static_cast(&val)); boost::uint32_t x = *exp_ptr; const int log_2 = (int)(((x >> 23) & 255) - 128); x &= ~(255 << 23); diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp index 67d50a7..65fe353 100644 --- a/include/boost/intrusive/intrusive_fwd.hpp +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -69,6 +69,7 @@ template , class O1 = none , class O2 = none , class O3 = none + , class O4 = none > class slist; diff --git a/include/boost/intrusive/linear_slist_algorithms.hpp b/include/boost/intrusive/linear_slist_algorithms.hpp new file mode 100644 index 0000000..46595e3 --- /dev/null +++ b/include/boost/intrusive/linear_slist_algorithms.hpp @@ -0,0 +1,324 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-2007 +// +// 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 +#include +#include + +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: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the linear list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! Static functions: +//! +//! static node_ptr get_next(const_node_ptr n); +//! +//! static void set_next(node_ptr n, node_ptr next); +template +class linear_slist_algorithms +{ + public: + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef NodeTraits node_traits; + + //! Requires: this_node and prev_init_node must be in the same linear list. + //! + //! Effects: 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). + //! + //! Complexity: Linear to the number of elements between prev_init_node and this_node. + //! + //! Throws: Nothing. + static node_ptr get_previous_node(node_ptr prev_init_node, node_ptr this_node) + { + node_ptr p = prev_init_node; + for( node_ptr p_next + ; this_node != (p_next = NodeTraits::get_next(p)) + ; p = p_next){ + //empty + } + return p; + } + + //! Effects: Constructs an empty list, making this_node the only + //! node of the linear list: + //! NodeTraits::get_next(this_node) == 0. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init_header(node_ptr this_node) + { NodeTraits::set_next(this_node, 0); } + + //! Effects: Constructs an non-used list element, putting the next + //! pointer to null: + //! NodeTraits::get_next(this_node) == 0 + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init(node_ptr this_node) + { NodeTraits::set_next(this_node, 0); } + + //! Requires: this_node must be in a linear list or be an empty linear list. + //! + //! Effects: Returns true is "this_node" is the only node of a linear list: + //! return NodeTraits::get_next(this_node) == this_node + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool unique(const_node_ptr this_node) + { + node_ptr next = NodeTraits::get_next(this_node); + return !next || next == this_node; + } + + //! Requires: this_node must be in a linear list or be an empty linear list. + //! + //! Effects: Returns true is "this_node" is the only node of a linear list: + //! return NodeTraits::get_next(this_node) == this_node + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool inited(const_node_ptr this_node) + { return !NodeTraits::get_next(this_node); } + + //! Requires: this_node must be in a linear list or be an empty linear list. + //! + //! Effects: Returns the number of nodes in a linear list. If the linear list + //! is empty, returns 1. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static std::size_t count(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; + } + + //! Requires: prev_node must be in a linear list or be an empty linear list. + //! + //! Effects: Unlinks the next node of prev_node from the linear list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(node_ptr prev_node) + { + node_ptr this_node(NodeTraits::get_next(prev_node)); + NodeTraits::set_next(prev_node, NodeTraits::get_next(this_node)); + } + + //! Requires: prev_node must be a node of a linear list. + //! + //! Effects: Links this_node after prev_node in the linear list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void link_after(node_ptr prev_node, node_ptr this_node) + { + NodeTraits::set_next(this_node, NodeTraits::get_next(prev_node)); + NodeTraits::set_next(prev_node, this_node); + } + + //! Requires: this_node and other_node must be nodes inserted + //! in linear lists or be empty linear lists. + //! + //! Effects: Moves all the nodes previously chained after this_node after other_node + //! and vice-versa. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void swap_trailing_nodes(node_ptr this_node, 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); + } + + //! Requires: 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. + //! + //! Effects: Removes the nodes from (b, e] range from their linear list and inserts + //! them after p in p's linear list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void transfer_after(node_ptr p, node_ptr b, node_ptr e) + { + if (p != b && p != e) { + node_ptr next_b = NodeTraits::get_next(b); + node_ptr next_e = NodeTraits::get_next(e); + node_ptr next_p = NodeTraits::get_next(p); + NodeTraits::set_next(b, next_e); + NodeTraits::set_next(e, next_p); + NodeTraits::set_next(p, next_b); + } + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Returns: The new first node of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear to the contained elements. + static node_ptr reverse(node_ptr p) + { + if(!p) return 0; + node_ptr i = NodeTraits::get_next(p); + node_ptr first(p); + while(i){ + node_ptr nxti(NodeTraits::get_next(i)); + unlink_after(p); + NodeTraits::set_next(i, first); + first = i; + i = nxti; + } + return first; + } + + //! Effects: Moves the node p n positions towards the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static node_ptr move_backwards(node_ptr p, std::size_t n) + { + //Null shift, or count() == 0 or 1, nothing to do + if(!n || !p || !NodeTraits::get_next(p)) + return p; + + node_ptr first = p; + bool end_found = false; + node_ptr new_last(0); + node_ptr old_last(0); + + //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 == 0){ + //Shortcut the shift with the modulo of the size of the list + n %= i; + if(!n) return p; + 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 = get_previous_node(first, 0); + } + + //Now link p after the new last node + NodeTraits::set_next(old_last, p); + NodeTraits::set_next(new_last, 0); + return first; + } + + //! Effects: Moves the node p n positions towards the beginning of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static node_ptr move_forward(node_ptr p, std::size_t n) + { + //Null shift, or count() == 0 or 1, nothing to do + if(!n || !p || !NodeTraits::get_next(p)) + return p; + + 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 p; + + 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, 0); + return new_first; + } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index 3b337d8..77c0c47 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -208,7 +208,7 @@ class list_impl : data_(v_traits) { this->priv_size_traits().set_size(size_type(0)); - node_algorithms::init(this->get_root_node()); + node_algorithms::init_header(this->get_root_node()); } //! Requires: Dereferencing iterator must yield an lvalue of type value_type. @@ -224,7 +224,7 @@ class list_impl : data_(v_traits) { this->priv_size_traits().set_size(size_type(0)); - node_algorithms::init(this->get_root_node()); + node_algorithms::init_header(this->get_root_node()); this->insert(this->end(), b, e); } @@ -258,7 +258,7 @@ class list_impl { node_ptr to_insert = get_real_value_traits().to_node_ptr(value); if(safemode_or_autounlink) - BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(to_insert)); node_algorithms::link_before(this->get_root_node(), to_insert); this->priv_size_traits().increment(); } @@ -277,7 +277,7 @@ class list_impl { node_ptr to_insert = get_real_value_traits().to_node_ptr(value); if(safemode_or_autounlink) - BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(to_insert)); node_algorithms::link_before(node_traits::get_next(this->get_root_node()), to_insert); this->priv_size_traits().increment(); } @@ -569,21 +569,7 @@ class list_impl //! //! Note: Does not affect the validity of iterators and references. void shift_backwards(size_type n = 1) - { - //Null shift, nothing to do - if(!n) return; - node_ptr root = this->get_root_node(); - node_ptr last = node_traits::get_previous(root); - //size() == 0 or 1, nothing to do - if(last == node_traits::get_next(root)) return; - - node_algorithms::unlink(root); - //Now get the new last node - while(n--){ - last = node_traits::get_previous(last); - } - node_algorithms::link_after(last, root); - } + { node_algorithms::move_forward(this->get_root_node(), n); } //! Effects: Moves forward all the elements, so that the second //! element becomes the first, the third becomes the second... @@ -595,20 +581,7 @@ class list_impl //! //! Note: Does not affect the validity of iterators and references. void shift_forward(size_type n = 1) - { - //Null shift, nothing to do - if(!n) return; - node_ptr root = this->get_root_node(); - node_ptr first = node_traits::get_next(root); - //size() == 0 or 1, nothing to do - if(first == node_traits::get_previous(root)) return; - node_algorithms::unlink(root); - //Now get the new first node - while(n--){ - first = node_traits::get_next(first); - } - node_algorithms::link_before(first, root); - } + { node_algorithms::move_backwards(this->get_root_node(), n); } //! Effects: Erases the element pointed by i of the list. //! No destructors are called. @@ -729,7 +702,7 @@ class list_impl this->erase(this->begin(), this->end()); } else{ - node_algorithms::init(this->get_root_node()); + node_algorithms::init_header(this->get_root_node()); this->priv_size_traits().set_size(size_type(0)); } } @@ -794,7 +767,7 @@ class list_impl { node_ptr to_insert = get_real_value_traits().to_node_ptr(value); if(safemode_or_autounlink) - BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(to_insert)); node_algorithms::link_before(p.pointed_node(), to_insert); this->priv_size_traits().increment(); return iterator(to_insert, this); @@ -1234,7 +1207,7 @@ class list_impl static iterator s_iterator_to(reference value) { BOOST_STATIC_ASSERT((!stateful_value_traits)); - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(value))); + BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(real_value_traits::to_node_ptr(value))); return iterator(real_value_traits::to_node_ptr(value), 0); } @@ -1252,7 +1225,7 @@ class list_impl static const_iterator s_iterator_to(const_reference value) { BOOST_STATIC_ASSERT((!stateful_value_traits)); - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(const_cast (value)))); + BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(real_value_traits::to_node_ptr(const_cast (value)))); return const_iterator(real_value_traits::to_node_ptr(const_cast (value)), 0); } @@ -1267,7 +1240,7 @@ class list_impl //! Note: Iterators and references are not invalidated. iterator iterator_to(reference value) { - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(value))); + BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(real_value_traits::to_node_ptr(value))); return iterator(real_value_traits::to_node_ptr(value), this); } @@ -1282,7 +1255,7 @@ class list_impl //! Note: Iterators and references are not invalidated. const_iterator iterator_to(const_reference value) const { - BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::unique(real_value_traits::to_node_ptr(const_cast (value)))); + BOOST_INTRUSIVE_INVARIANT_ASSERT(!node_algorithms::inited(real_value_traits::to_node_ptr(const_cast (value)))); return const_iterator(real_value_traits::to_node_ptr(const_cast (value)), this); } diff --git a/include/boost/intrusive/options.hpp b/include/boost/intrusive/options.hpp index 3ced4ea..cda392e 100644 --- a/include/boost/intrusive/options.hpp +++ b/include/boost/intrusive/options.hpp @@ -318,10 +318,8 @@ struct tag /// @endcond }; -//!This option setter specifies the type of -//!a void pointer. This will instruct the hook -//!to use this type of pointer instead of the -//!default one +//!This option setter specifies the link mode +//!(normal_link, safe_link or auto_unlink) template struct link_mode { @@ -334,10 +332,8 @@ struct link_mode /// @endcond }; -//!This option setter specifies the type of -//!a void pointer. This will instruct the hook -//!to use this type of pointer instead of the -//!default one +//!This option setter specifies if the hook +//!should be optimized for size instead of for speed. template struct optimize_size { @@ -350,6 +346,20 @@ struct optimize_size /// @endcond }; +//!This option setter specifies if the list container should +//!use a linear implementation instead of a circular one. +template +struct linear +{ +/// @cond + template + struct pack : Base + { + static const bool linear = Enabled; + }; +/// @endcond +}; + //!This option setter specifies the bucket traits //!class for unordered associative containers. When this option is specified, //!instead of using the default bucket traits, a user defined holder will be defined @@ -475,6 +485,7 @@ struct hook_defaults , tag , optimize_size , store_hash + , linear >::type {}; diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index dadd25b..ba0240a 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -46,12 +47,13 @@ template struct get_default_slist_hook { typedef typename T::default_slist_hook type; }; -template +template struct slistopt { typedef ValueTraits value_traits; typedef SizeType size_type; static const bool constant_time_size = ConstantTimeSize; + static const bool linear = Linear; }; template @@ -66,6 +68,7 @@ struct slist_defaults >::type > , constant_time_size + , linear , size_type >::type {}; @@ -129,10 +132,15 @@ class slist_impl ::type node_ptr; typedef typename boost::pointer_to_other ::type const_node_ptr; - typedef circular_slist_algorithms node_algorithms; + typedef typename detail::if_c + < Config::linear + , linear_slist_algorithms + , circular_slist_algorithms + >::type node_algorithms; static const bool constant_time_size = Config::constant_time_size; static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; + static const bool linear = Config::linear; /// @cond private: @@ -152,6 +160,8 @@ class slist_impl //Constant-time size is incompatible with auto-unlink hooks! BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink))); + //Linear singly linked lists are incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(linear && ((int)real_value_traits::link_mode == (int)auto_unlink))); node_ptr get_root_node() { return node_ptr(&data_.root_plus_size_.root_); } @@ -220,7 +230,7 @@ class slist_impl : data_(v_traits) { this->priv_size_traits().set_size(size_type(0)); - node_algorithms::init(this->get_root_node()); + node_algorithms::init_header(this->get_root_node()); } //! Requires: Dereferencing iterator must yield an lvalue of type value_type. @@ -236,7 +246,7 @@ class slist_impl : data_(v_traits) { this->priv_size_traits().set_size(size_type(0)); - node_algorithms::init(this->get_root_node()); + node_algorithms::init_header(this->get_root_node()); insert_after(before_begin(), b, e); } @@ -266,7 +276,7 @@ class slist_impl this->erase_after(this->before_begin(), this->end()); } else{ - node_algorithms::init(this->get_root_node()); + node_algorithms::init_header(this->get_root_node()); this->priv_size_traits().set_size(size_type(0)); } } @@ -299,7 +309,7 @@ class slist_impl { node_ptr to_insert = get_real_value_traits().to_node_ptr(value); if(safemode_or_autounlink) - BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(to_insert)); node_algorithms::link_after(this->get_root_node(), to_insert); this->priv_size_traits().increment(); } @@ -385,7 +395,7 @@ class slist_impl //! //! Complexity: Constant. iterator end() - { return iterator (this->get_root_node(), this); } + { return iterator (linear ? 0 : this->get_root_node(), this); } //! Effects: Returns a const_iterator to the end of the list. //! @@ -393,7 +403,7 @@ class slist_impl //! //! Complexity: Constant. const_iterator end() const - { return const_iterator (uncast(this->get_root_node()), this); } + { return const_iterator (linear ? 0 : uncast(this->get_root_node()), this); } //! Effects: Returns a const_iterator to the end of the list. //! @@ -401,7 +411,7 @@ class slist_impl //! //! Complexity: Constant. const_iterator cend() const - { return const_iterator (uncast(this->get_root_node()), this); } + { return this->end(); } //! Effects: Returns an iterator that points to a position //! before the first element. Equivalent to "end()" @@ -410,7 +420,7 @@ class slist_impl //! //! Complexity: Constant. iterator before_begin() - { return end(); } + { return iterator(this->get_root_node(), this); } //! Effects: Returns an iterator that points to a position //! before the first element. Equivalent to "end()" @@ -419,7 +429,7 @@ class slist_impl //! //! Complexity: Constant. const_iterator before_begin() const - { return end(); } + { return const_iterator(uncast(this->get_root_node()), this); } //! Effects: Returns an iterator that points to a position //! before the first element. Equivalent to "end()" @@ -428,7 +438,7 @@ class slist_impl //! //! Complexity: Constant. const_iterator cbefore_begin() const - { return end(); } + { return this->before_begin(); } //! Precondition: end_iterator must be a valid end iterator //! of slist. @@ -487,7 +497,7 @@ class slist_impl //! Note: Does not affect the validity of iterators and references. void swap(slist_impl& other) { - node_algorithms::swap_nodes(this->get_root_node(), other.get_root_node()); + priv_swap_lists(this->get_root_node(), other.get_root_node(), detail::bool_()); if(constant_time_size){ size_type backup = this->priv_size_traits().get_size(); this->priv_size_traits().set_size(other.priv_size_traits().get_size()); @@ -506,43 +516,7 @@ class slist_impl //! Note: Iterators Does not affect the validity of iterators and references. void shift_backwards(size_type n = 1) { - //Null shift, nothing to do - if(!n) return; - node_ptr root = this->get_root_node(); - node_ptr first = node_traits::get_next(root); - - //size() == 0 or 1, nothing to do - if(node_traits::get_next(first) == root) return; - - //Iterate until the root node 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(root); - size_type distance = 1; - while(root != (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. - //Shorcut the shift with the modulo of the size of the list - size_type 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; - - for( new_last = root - ; new_before_last_pos-- - ; new_last = node_traits::get_next(new_last)){ - //empty - } - } - - //Now unlink the root node and link it after the new last node - node_algorithms::unlink_after(old_last); - node_algorithms::link_after(new_last, root); + priv_shift_backwards(n, detail::bool_()); } //! Effects: Moves forward all the elements, so that the second @@ -556,43 +530,7 @@ class slist_impl //! Note: Does not affect the validity of iterators and references. void shift_forward(size_type n = 1) { - //Null shift, nothing to do - if(!n) return; - node_ptr root = this->get_root_node(); - node_ptr first = node_traits::get_next(root); - - //size() == 0 or 1, nothing to do - if(node_traits::get_next(first) == root) return; - - bool end_found = false; - node_ptr new_last(0); - - //Now find the new last node according to the shift count. - //If we find the root node before finding the new last node - //unlink the root, shortcut the search now that we know the size of the list - //and continue. - for(size_type i = 1; i <= n; ++i){ - new_last = first; - first = node_traits::get_next(first); - if(first == root){ - //Shorcut the shift with the modulo of the size of the list - n %= i; - i = 0; - //Unlink the root node and continue the new first node search - first = node_traits::get_next(first); - node_algorithms::unlink_after(new_last); - end_found = true; - } - } - - //If the root node has not been found in the previous loop, find it - //starting in the new first node and unlink it - if(!end_found){ - node_algorithms::unlink_after(node_algorithms::get_previous_node(first, root)); - } - - //Now link the root node after the new last node - node_algorithms::link_after(new_last, root); + priv_shift_forward(n, detail::bool_()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -643,7 +581,7 @@ class slist_impl { node_ptr n = get_real_value_traits().to_node_ptr(value); if(safemode_or_autounlink) - BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n)); + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(n)); node_algorithms::link_after(prev_p.pointed_node(), n); this->priv_size_traits().increment(); return iterator (n, this); @@ -712,16 +650,7 @@ class slist_impl //! Note: Invalidates the iterators (but not the references) to the //! erased element. iterator erase_after(iterator prev) - { - iterator it(prev); ++it; - node_ptr to_erase(it.pointed_node()); - node_algorithms::unlink_after(prev.pointed_node()); - this->priv_size_traits().decrement(); - iterator ret(++prev); - if(safemode_or_autounlink) - node_algorithms::init(to_erase); - return ret; - } + { return this->erase_after_and_dispose(prev, detail::null_disposer()); } //! Effects: Erases the range (before_first, last) from //! the list. No destructors are called. @@ -731,18 +660,12 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Lineal to the elements (last - before_first). + //! Complexity: Lineal to the elements (last - before_first + 1). //! //! Note: Invalidates the iterators (but not the references) to the //! erased element. iterator erase_after(iterator before_first, iterator last) - { - iterator first; - while(++(first = before_first) != last){ - this->erase_after(before_first); - } - return last; - } + { return this->erase_after_and_dispose(before_first, last, detail::null_disposer()); } //! Effects: Erases the element pointed by i of the list. //! No destructors are called. @@ -794,11 +717,16 @@ class slist_impl template iterator erase_after_and_dispose(iterator prev, Disposer disposer) { - iterator it(prev); ++it; + iterator it(prev); + ++it; node_ptr to_erase(it.pointed_node()); - iterator ret(this->erase_after(prev)); + ++it; + node_algorithms::unlink_after(prev.pointed_node()); + this->priv_size_traits().decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); disposer(get_real_value_traits().to_value_ptr(to_erase)); - return ret; + return it; } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -818,9 +746,10 @@ class slist_impl template iterator erase_after_and_dispose(iterator before_first, iterator last, Disposer disposer) { - iterator first; - while(++(first = before_first) != last){ - this->erase_after_and_dispose(before_first, disposer); + iterator next(before_first); + ++next; + while(next != last){ + next = this->erase_after_and_dispose(before_first, disposer); } return last; } @@ -931,7 +860,7 @@ class slist_impl iterator last_x(x.previous(x.end())); node_algorithms::transfer_after ( prev.pointed_node() - , x.end().pointed_node() + , x.before_begin().pointed_node() , last_x.pointed_node()); this->priv_size_traits().set_size(this->priv_size_traits().get_size() + x.priv_size_traits().get_size()); x.priv_size_traits().set_size(size_type(0)); @@ -1133,12 +1062,12 @@ class slist_impl (last_inserted.pointed_node(), carry.end().pointed_node()); iterator last_element(p, this); if(constant_time_size){ - counter[i].splice_after( counter[i].end(), carry + counter[i].splice_after( counter[i].before_begin(), carry , carry.before_begin(), last_element , carry.size()); } else{ - counter[i].splice_after( counter[i].end(), carry + counter[i].splice_after( counter[i].before_begin(), carry , carry.before_begin(), last_element); } if(i == fill) @@ -1153,11 +1082,11 @@ class slist_impl (last_inserted.pointed_node(), counter[--fill].end().pointed_node()); iterator last_element(p, this); if(constant_time_size){ - this->splice_after( end(), counter[fill], counter[fill].before_begin() + this->splice_after( before_begin(), counter[fill], counter[fill].before_begin() , last_element, counter[fill].size()); } else{ - this->splice_after( end(), counter[fill], counter[fill].before_begin() + this->splice_after( before_begin(), counter[fill], counter[fill].before_begin() , last_element); } } @@ -1201,14 +1130,14 @@ class slist_impl template iterator merge(slist_impl& x, Predicate p) { - iterator a(before_begin()), e(end()), ax(x.before_begin()); + iterator a(before_begin()), e(end()), ax(x.before_begin()), ex(x.end()); iterator last_inserted(e); iterator a_next; while(++(a_next = a) != e && !x.empty()) { iterator ix(ax); iterator cx; size_type n(0); - while(++(cx = ix) != ax && p(*cx, *a_next)){ + while(++(cx = ix) != ex && p(*cx, *a_next)){ ++ix; ++n; } if(ax != ix){ @@ -1235,7 +1164,7 @@ class slist_impl //! //! Note: Iterators and references are not invalidated void merge(slist_impl& x) - { this->merge(x, std::less()); } + { this->merge(x, std::less()); } //! Effects: Reverses the order of elements in the list. //! @@ -1245,7 +1174,7 @@ class slist_impl //! //! Note: Iterators and references are not invalidated void reverse() - { node_algorithms::reverse(this->get_root_node()); } + { priv_reverse(detail::bool_()); } //! Effects: Removes all the elements that compare equal to value. //! No destructors are called. @@ -1406,7 +1335,7 @@ class slist_impl static iterator s_iterator_to(reference value) { BOOST_STATIC_ASSERT((!stateful_value_traits)); - BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(value))); + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(value))); return iterator (value_traits::to_node_ptr(value), 0); } @@ -1424,7 +1353,7 @@ class slist_impl static const_iterator s_iterator_to(const_reference value) { BOOST_STATIC_ASSERT((!stateful_value_traits)); - BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(const_cast (value)))); + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(const_cast (value)))); return const_iterator (value_traits::to_node_ptr(const_cast (value)), 0); } @@ -1439,7 +1368,7 @@ class slist_impl //! Note: Iterators and references are not invalidated. iterator iterator_to(reference value) { - BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(value))); + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(value))); return iterator (value_traits::to_node_ptr(value), this); } @@ -1454,7 +1383,7 @@ class slist_impl //! Note: Iterators and references are not invalidated. const_iterator iterator_to(const_reference value) const { - BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::unique(value_traits::to_node_ptr(const_cast (value)))); + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(const_cast (value)))); return const_iterator (value_traits::to_node_ptr(const_cast (value)), this); } @@ -1487,8 +1416,54 @@ class slist_impl } private: + + void priv_reverse(detail::bool_) + { node_algorithms::reverse(this->get_root_node()); } + + void priv_reverse(detail::bool_) + { + node_ptr new_first = node_algorithms::reverse + (node_traits::get_next(this->get_root_node())); + node_traits::set_next(this->get_root_node(), new_first); + } + + void priv_shift_backwards(size_type n, detail::bool_) + { + node_algorithms::move_forward(this->get_root_node(), (std::size_t)n); + } + + void priv_shift_backwards(size_type n, detail::bool_) + { + node_ptr new_first = node_algorithms::move_forward + (node_traits::get_next(this->get_root_node()), (std::size_t)n); + node_traits::set_next(this->get_root_node(), new_first); + } + + void priv_shift_forward(size_type n, detail::bool_) + { + node_algorithms::move_backwards(this->get_root_node(), (std::size_t)n); + } + + void priv_shift_forward(size_type n, detail::bool_) + { + node_ptr new_first = node_algorithms::move_backwards + (node_traits::get_next(this->get_root_node()), (std::size_t)n); + node_traits::set_next(this->get_root_node(), new_first); + } + + //circular version + static void priv_swap_lists(node_ptr this_node, node_ptr other_node, detail::bool_) + { node_algorithms::swap_nodes(this_node, other_node); } + + //linear version + static void priv_swap_lists(node_ptr this_node, node_ptr other_node, detail::bool_) + { node_algorithms::swap_trailing_nodes(this_node, other_node); } + static slist_impl &priv_container_from_end_iterator(const const_iterator &end_iterator) { + //Obtaining the container from the end iterator is not possible with linear + //singly linked lists (because "end" is represented by the null pointer) + BOOST_STATIC_ASSERT(!linear); root_plus_size *r = detail::parent_from_member ( detail::get_pointer(end_iterator.pointed_node()), &root_plus_size::root_); data_t *d = detail::parent_from_member @@ -1620,13 +1595,13 @@ inline void swap #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else -template +template #endif struct make_slist { /// @cond typedef typename pack_options - < slist_defaults, O1, O2, O3>::type packed_options; + < slist_defaults, O1, O2, O3, O4>::type packed_options; typedef typename detail::get_value_traits ::type value_traits; typedef slist_impl @@ -1635,6 +1610,7 @@ struct make_slist < value_traits , typename packed_options::size_type , packed_options::constant_time_size + , packed_options::linear > > implementation_defined; /// @endcond @@ -1643,12 +1619,12 @@ struct make_slist #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED -template +template class slist - : public make_slist::type + : public make_slist::type { typedef typename make_slist - ::type Base; + ::type Base; typedef typename Base::real_value_traits real_value_traits; //Assert if passed value traits are compatible with the type BOOST_STATIC_ASSERT((detail::is_same::value)); diff --git a/include/boost/intrusive/slist_hook.hpp b/include/boost/intrusive/slist_hook.hpp index 547ca6f..b7d5344 100644 --- a/include/boost/intrusive/slist_hook.hpp +++ b/include/boost/intrusive/slist_hook.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ struct get_slist_node_algo { typedef circular_slist_algorithms > type; }; + /// @endcond //! Helper metafunction to define a \c slist_base_hook that yields to the same diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index 9b36d35..9b2181d 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -135,6 +135,9 @@ + + diff --git a/test/list_test.cpp b/test/list_test.cpp index 7b28289..822b408 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -63,14 +63,6 @@ void test_list::test_all(std::vector const int num_values = (int)values.size(); std::vector expected_values(num_values); - //Shift forward all possible positions 3 times - for(int i = 0; i < num_values*3; ++i){ - testlist.assign(values.begin(), values.end()); - testlist.shift_forward(i); - for(int j = 0; j < num_values; ++j){ - expected_values[(j + num_values - i%num_values) % num_values] = (j + 1); + for(int s = 1; s <= num_values; ++s){ + expected_values.resize(s); + //Shift forward all possible positions 3 times + for(int i = 0; i < s*3; ++i){ + testlist.insert(testlist.begin(), &values[0], &values[0] + s); + testlist.shift_forward(i); + for(int j = 0; j < s; ++j){ + expected_values[(j + s - i%s) % s] = (j + 1); + } + TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()); + testlist.clear(); } - TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()); - testlist.clear(); - } - //Shift backwards all possible positions - for(int i = 0; i < num_values*3; ++i){ - testlist.assign(values.begin(), values.end()); - testlist.shift_backwards(i); - for(int j = 0; j < num_values; ++j){ - expected_values[(j + i) % num_values] = (j + 1); + //Shift backwards all possible positions + for(int i = 0; i < s*3; ++i){ + testlist.insert(testlist.begin(), &values[0], &values[0] + s); + testlist.shift_backwards(i); + for(int j = 0; j < s; ++j){ + expected_values[(j + i) % s] = (j + 1); + } + TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()); + testlist.clear(); } - TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()); - testlist.clear(); } } @@ -278,6 +273,28 @@ void test_list { int init_values [] = { 4, 3 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist2.begin() ); } } + { + list_type testlist1 (&values[0], &values[1]); + + { int init_values [] = { 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + + values[1].swap_nodes(values[2]); + + { int init_values [] = { 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + + values[0].swap_nodes(values[2]); + + { int init_values [] = { 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + + values[0].swap_nodes(values[2]); + + { int init_values [] = { 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + } + } template diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 06fc38c..698fea8 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -24,7 +24,7 @@ using namespace boost::intrusive; -template +template struct test_slist { typedef typename ValueTraits::value_type value_type; @@ -37,11 +37,12 @@ struct test_slist static void test_swap(std::vector& values); static void test_slow_insert (std::vector& values); static void test_clone (std::vector& values); - static void test_container_from_end(std::vector &values); + static void test_container_from_end(std::vector &, detail::bool_){} + static void test_container_from_end(std::vector &values, detail::bool_); }; -template -void test_slist +template +void test_slist ::test_all (std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -50,6 +51,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; { list_type list(values.begin(), values.end()); @@ -66,12 +68,12 @@ void test_slist test_slow_insert (values); test_swap(values); test_clone(values); - test_container_from_end(values); + test_container_from_end(values, detail::bool_()); } //test: push_front, pop_front, front, size, empty: -template -void test_slist +template +void test_slist ::test_front_back (std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -80,6 +82,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist; BOOST_TEST (testlist.empty()); @@ -101,8 +104,8 @@ void test_slist } //test: merge due to error in merge implementation: -template -void test_slist +template +void test_slist ::test_merge (std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -111,6 +114,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist1, testlist2; testlist1.push_front (values[0]); @@ -124,8 +128,8 @@ void test_slist } //test: constructor, iterator, sort, reverse: -template -void test_slist +template +void test_slist ::test_sort(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -134,6 +138,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist (values.begin(), values.end()); @@ -145,13 +150,13 @@ void test_slist TEST_INTRUSIVE_SEQUENCE( init_values, testlist.begin() ); } testlist.reverse(); - { int init_values [] = { 5, 3, 1, 4, 2, }; + { int init_values [] = { 5, 3, 1, 4, 2 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist.begin() ); } } //test: assign, insert_after, const_iterator, erase_after, s_iterator_to, previous: -template -void test_slist +template +void test_slist ::test_insert(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -160,6 +165,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist; testlist.assign (&values[0] + 2, &values[0] + 5); @@ -189,8 +195,8 @@ void test_slist } //test: insert, const_iterator, erase, siterator_to: -template -void test_slist +template +void test_slist ::test_slow_insert (std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -199,6 +205,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist; testlist.push_front (values[4]); @@ -232,8 +239,8 @@ void test_slist BOOST_TEST (testlist.front().value_ == 3); } -template -void test_slist +template +void test_slist ::test_shift(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -242,6 +249,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist; @@ -249,33 +257,36 @@ void test_slist std::vector expected_values(num_values); //Shift forward all possible positions 3 times - for(int i = 0; i < num_values*3; ++i){ - testlist.assign(values.begin(), values.end()); - testlist.shift_forward(i); - for(int j = 0; j < num_values; ++j){ - expected_values[(j + num_values - i%num_values) % num_values] = (j + 1); + for(int s = 1; s <= num_values; ++s){ + expected_values.resize(s); + for(int i = 0; i < s*3; ++i){ + testlist.insert_after(testlist.before_begin(), &values[0], &values[0] + s); + testlist.shift_forward(i); + for(int j = 0; j < s; ++j){ + expected_values[(j + s - i%s) % s] = (j + 1); + } + + TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()) + testlist.clear(); } - TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()) - testlist.clear(); - } + //Shift backwards all possible positions + for(int i = 0; i < s*3; ++i){ + testlist.insert_after(testlist.before_begin(), &values[0], &values[0] + s); + testlist.shift_backwards(i); + for(int j = 0; j < s; ++j){ + expected_values[(j + i) % s] = (j + 1); + } - //Shift backwards all possible positions - for(int i = 0; i < num_values*3; ++i){ - testlist.assign(values.begin(), values.end()); - testlist.shift_backwards(i); - for(int j = 0; j < num_values; ++j){ - expected_values[(j + i) % num_values] = (j + 1); + TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()) + testlist.clear(); } - - TEST_INTRUSIVE_SEQUENCE_EXPECTED(expected_values, testlist.begin()) - testlist.clear(); } } //test: insert_after (seq-version), swap, splice_after: -template -void test_slist +template +void test_slist ::test_swap(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -284,11 +295,12 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; { list_type testlist1 (&values[0], &values[0] + 2); list_type testlist2; - testlist2.insert_after (testlist2.end(), &values[0] + 2, &values[0] + 5); + testlist2.insert_after (testlist2.before_begin(), &values[0] + 2, &values[0] + 5); testlist1.swap(testlist2); { int init_values [] = { 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } @@ -299,19 +311,20 @@ void test_slist TEST_INTRUSIVE_SEQUENCE( init_values, testlist2.begin() ); } BOOST_TEST (testlist1.empty()); - testlist1.splice_after (testlist1.end(), testlist2, ++testlist2.begin()); + testlist1.splice_after (testlist1.before_begin(), testlist2, ++testlist2.begin()); { int init_values [] = { 4 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } { int init_values [] = { 1, 3, 5, 2 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist2.begin() ); } testlist1.splice_after (testlist1.begin(), testlist2, - testlist2.end(), ++++testlist2.begin()); + testlist2.before_begin(), ++++testlist2.begin()); { int init_values [] = { 4, 1, 3, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } { int init_values [] = { 2 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist2.begin() ); } } + if(!list_type::linear) { list_type testlist1 (&values[0], &values[0] + 2); list_type testlist2 (&values[0] + 3, &values[0] + 5); @@ -326,10 +339,32 @@ void test_slist { int init_values [] = { 4, 3 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist2.begin() ); } } + if(!list_type::linear) + { + list_type testlist1 (&values[0], &values[1]); + + { int init_values [] = { 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + + values[1].swap_nodes(values[2]); + + { int init_values [] = { 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + + values[0].swap_nodes(values[2]); + + { int init_values [] = { 3 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + + values[0].swap_nodes(values[2]); + + { int init_values [] = { 1 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } + } } -template -void test_slist +template +void test_slist ::test_clone(std::vector& values) { typedef typename ValueTraits::value_type value_type; @@ -338,6 +373,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist1 (&values[0], &values[0] + values.size()); @@ -349,9 +385,10 @@ void test_slist BOOST_TEST (testlist2.empty()); } -template -void test_slist - ::test_container_from_end(std::vector& values) +template +void test_slist + ::test_container_from_end(std::vector& values + ,detail::bool_) { typedef typename ValueTraits::value_type value_type; typedef slist @@ -359,6 +396,7 @@ void test_slist , value_traits , size_type , constant_time_size + , linear > list_type; list_type testlist1 (&values[0], &values[0] + values.size()); BOOST_TEST (testlist1 == list_type::container_from_end_iterator(testlist1.end())); @@ -380,6 +418,7 @@ class test_main_template < value_type , typename value_type::slist_base_hook_t >::type + , false >::test_all(data); test_slist < typename detail::get_member_value_traits < value_type @@ -388,6 +427,25 @@ class test_main_template , &value_type::slist_node_ > >::type + , false + >::test_all(data); + + //Now linear slists + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + , true + >::test_all(data); + + test_slist < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::slist_member_hook_t + , &value_type::slist_node_ + > + >::type + , true >::test_all(data); return 0; @@ -409,6 +467,7 @@ class test_main_template < value_type , typename value_type::slist_base_hook_t >::type + , false >::test_all(data); test_slist < typename detail::get_member_value_traits @@ -418,12 +477,14 @@ class test_main_template , &value_type::slist_node_ > >::type + , false >::test_all(data); test_slist < typename detail::get_base_value_traits < value_type , typename value_type::slist_auto_base_hook_t >::type + , false >::test_all(data); test_slist < typename detail::get_member_value_traits @@ -433,6 +494,24 @@ class test_main_template , &value_type::slist_auto_node_ > >::type + , false + >::test_all(data); + + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + , true + >::test_all(data); + + test_slist < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::slist_member_hook_t + , &value_type::slist_node_ + > + >::type + , true >::test_all(data); return 0; }