From 0ddb2b7045ac45814ea9f712593f22559f7a0f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 27 Jan 2008 22:22:22 +0000 Subject: [PATCH] Merged Interprocess + Intrusive revision 42982 from trunk to release branch [SVN r42994] --- doc/html/reference.css | 8 + example/doc_list_algorithms.cpp | 2 +- example/doc_slist_algorithms.cpp | 2 +- example/doc_splay_algorithms.cpp | 3 +- .../intrusive/circular_list_algorithms.hpp | 116 ++- .../intrusive/circular_slist_algorithms.hpp | 320 ++++++--- .../detail/common_slist_algorithms.hpp | 95 +++ .../intrusive/detail/tree_algorithms.hpp | 4 +- include/boost/intrusive/detail/utilities.hpp | 3 +- include/boost/intrusive/hashtable.hpp | 2 +- include/boost/intrusive/intrusive_fwd.hpp | 2 + .../intrusive/linear_slist_algorithms.hpp | 326 +++++++++ include/boost/intrusive/list.hpp | 220 +++--- include/boost/intrusive/options.hpp | 41 +- include/boost/intrusive/slist.hpp | 669 +++++++++++------- include/boost/intrusive/slist_hook.hpp | 2 + proj/vc7ide/Intrusive.sln | 350 ++++----- .../vc7ide/_intrusivelib/_intrusivelib.vcproj | 6 + proj/vc7ide/to-do.txt | 7 - test/itestvalue.hpp | 12 +- test/list_test.cpp | 125 +++- test/slist_test.cpp | 354 +++++++-- test/test_templates.hpp | 65 -- 23 files changed, 1896 insertions(+), 838 deletions(-) create mode 100644 include/boost/intrusive/detail/common_slist_algorithms.hpp create mode 100644 include/boost/intrusive/linear_slist_algorithms.hpp delete mode 100644 proj/vc7ide/to-do.txt delete mode 100644 test/test_templates.hpp diff --git a/doc/html/reference.css b/doc/html/reference.css index be4e64c..956d7da 100644 --- a/doc/html/reference.css +++ b/doc/html/reference.css @@ -1,3 +1,11 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ PRE.synopsis { background-color: #e0ffff; border: thin solid blue; 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/example/doc_splay_algorithms.cpp b/example/doc_splay_algorithms.cpp index 5f929fa..80797db 100644 --- a/example/doc_splay_algorithms.cpp +++ b/example/doc_splay_algorithms.cpp @@ -75,5 +75,4 @@ int main() algo::erase(&header, &three); return 0; } - -//] \ No newline at end of file +//] diff --git a/include/boost/intrusive/circular_list_algorithms.hpp b/include/boost/intrusive/circular_list_algorithms.hpp index 5e28e19..97438bf 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. @@ -124,10 +154,9 @@ class circular_list_algorithms static void unlink(node_ptr b, node_ptr e) { if (b != e) { - node_ptr prev(NodeTraits::get_previous(b)); - node_ptr next(NodeTraits::get_next(e)); - NodeTraits::set_previous(next, prev); - NodeTraits::set_next(prev, next); + node_ptr prevb(NodeTraits::get_previous(b)); + NodeTraits::set_previous(e, prevb); + NodeTraits::set_next(prevb, e); } } @@ -229,6 +258,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 +278,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 +301,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 +355,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..73e4590 100644 --- a/include/boost/intrusive/circular_slist_algorithms.hpp +++ b/include/boost/intrusive/circular_slist_algorithms.hpp @@ -16,6 +16,8 @@ #include #include +#include +#include #include namespace boost { @@ -25,7 +27,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: //! @@ -44,22 +46,98 @@ namespace intrusive { //! static void set_next(node_ptr n, node_ptr next); template class circular_slist_algorithms + /// @cond + : public detail::common_slist_algorithms + /// @endcond { + /// @cond + typedef detail::common_slist_algorithms base_t; + /// @endcond public: typedef typename NodeTraits::node_ptr node_ptr; typedef typename NodeTraits::const_node_ptr const_node_ptr; typedef NodeTraits node_traits; - //! Requires: this_node must be in a circular list or be an empty circular list. + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + + //! Effects: Constructs an non-used list element, putting the next + //! pointer to null: + //! NodeTraits::get_next(this_node) == 0 //! - //! Effects: Returns the previous node of this_node in the circular list. - //! - //! Complexity: Linear to the number of elements in the circular list. + //! Complexity: Constant //! //! Throws: Nothing. - static node_ptr get_previous_node(node_ptr this_node) - { return get_previous_node(this_node, this_node); } + static void init(node_ptr this_node); + //! 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: + //! or it's a not inserted node: + //! return !NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool unique(const_node_ptr 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); + + //! Requires: prev_node must be in a circular list or be an empty circular list. + //! + //! Effects: Unlinks the next node of prev_node from the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(node_ptr prev_node); + + //! Requires: prev_node and last_node must be in a circular list + //! or be an empty circular list. + //! + //! Effects: Unlinks the range (prev_node, last_node) from the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(node_ptr prev_node, node_ptr last_node); + + //! Requires: prev_node must be a node of a circular list. + //! + //! Effects: Links this_node after prev_node in the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void link_after(node_ptr prev_node, node_ptr 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 + //! them after p in p's circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void transfer_after(node_ptr p, node_ptr b, node_ptr e); + + #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + + //! Effects: Constructs an empty list, making this_node the only + //! node of the circular list: + //! 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); } //! Requires: this_node and prev_init_node must be in the same circular list. //! @@ -71,15 +149,17 @@ 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; - for( node_ptr p_next - ; this_node != (p_next = NodeTraits::get_next(p)) - ; p = p_next){ - //empty - } - return p; - } + { return base_t::get_previous_node(prev_init_node, this_node); } + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Returns the previous node of this_node in the circular list. + //! + //! Complexity: Linear to the number of elements in the circular list. + //! + //! Throws: Nothing. + static node_ptr get_previous_node(node_ptr this_node) + { return base_t::get_previous_node(this_node, this_node); } //! Requires: this_node must be in a circular list or be an empty circular list. //! @@ -113,28 +193,6 @@ class circular_slist_algorithms return p; } - //! 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. - //! - //! Complexity: Constant - //! - //! Throws: Nothing. - static void init(node_ptr this_node) - { NodeTraits::set_next(this_node, this_node); } - - //! 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 - //! - //! Complexity: Constant - //! - //! Throws: Nothing. - static bool unique(const_node_ptr this_node) - { return NodeTraits::get_next(this_node) == this_node; } - //! Requires: this_node must be in a circular list or be an empty circular list. //! //! Effects: Returns the number of nodes in a circular list. If the circular list @@ -154,34 +212,7 @@ class circular_slist_algorithms return result; } - //! Requires: prev_node must be in a circular list or be an empty circular list. - //! - //! Effects: Unlinks the next node of prev_node from the circular 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)); - NodeTraits::set_next(this_node, this_node); - } - - //! Requires: nxt_node must be in a circular list or be an empty circular list. - //! - //! Effects: Unlinks the previous node of nxt_node from the circular list. - //! - //! Complexity: Linear to the elements in the circular list. - //! - //! Throws: Nothing. - static void unlink_before(node_ptr nxt_node) - { - node_ptr prev_to_erase(get_previous_previous_node(nxt_node)); - 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,20 +220,9 @@ class circular_slist_algorithms //! //! Throws: Nothing. static void unlink(node_ptr this_node) - { unlink_after(get_previous_node(this_node)); } - - //! Requires: prev_node must be a node of a circular list. - //! - //! Effects: Links this_node after prev_node in the circular list. - //! - //! Complexity: Constant - //! - //! 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(prev_node, this_node); + if(NodeTraits::get_next(this_node)) + base_t::unlink_after(get_previous_node(this_node)); } //! Requires: nxt_node must be a node of a circular list. @@ -213,7 +233,7 @@ class circular_slist_algorithms //! //! Throws: Nothing. static void link_before (node_ptr nxt_node, node_ptr this_node) - { link_after(get_previous_node(nxt_node), this_node); } + { base_t::link_after(get_previous_node(nxt_node), this_node); } //! Requires: this_node and other_node must be nodes inserted //! in circular lists or be empty circular lists. @@ -229,8 +249,17 @@ class circular_slist_algorithms { if (other_node == this_node) return; - bool empty1 = unique(this_node); - bool empty2 = unique(other_node); + bool this_inited = base_t::inited(this_node); + bool other_inited = base_t::inited(other_node); + if(this_inited){ + base_t::init_header(this_node); + } + if(other_inited){ + base_t::init_header(other_node); + } + + bool empty1 = base_t::unique(this_node); + bool empty2 = base_t::unique(other_node); node_ptr prev_this (get_previous_node(this_node)); node_ptr prev_other(get_previous_node(other_node)); @@ -240,26 +269,12 @@ 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); - } - //! 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 - //! them after p in p's circular 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); + if(this_inited){ + base_t::init(other_node); + } + if(other_inited){ + base_t::init(this_node); } } @@ -275,9 +290,110 @@ class circular_slist_algorithms node_ptr nxt(NodeTraits::get_next(i)); if (nxt == e) break; - transfer_after(e, i, nxt); + base_t::transfer_after(e, i, nxt); } } + + //! Effects: Moves the node p n positions towards the end of the list. + //! + //! Returns: The previous node of p after the function if there has been any movement, + //! Null if n leads to no movement. + //! + //! 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, nothing to do + if(!n) return 0; + node_ptr first = NodeTraits::get_next(p); + + //count() == 1 or 2, nothing to do + if(NodeTraits::get_next(first) == p) + return 0; + + 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 0; + i = 0; + //Unlink p and continue the new first node search + first = NodeTraits::get_next(p); + base_t::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){ + base_t::unlink_after(base_t::get_previous_node(first, p)); + } + + //Now link p after the new last node + base_t::link_after(new_last, p); + return new_last; + } + + //! Effects: Moves the node p n positions towards the beginning of the list. + //! + //! Returns: The previous node of p after the function if there has been any movement, + //! Null if n leads equals to no movement. + //! + //! 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, nothing to do + if(!n) return 0; + node_ptr first = node_traits::get_next(p); + + //count() == 1 or 2, nothing to do + if(node_traits::get_next(first) == p) return 0; + + //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 0; + + 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 + base_t::unlink_after(old_last); + base_t::link_after(new_last, p); + return new_last; + } }; } //namespace intrusive diff --git a/include/boost/intrusive/detail/common_slist_algorithms.hpp b/include/boost/intrusive/detail/common_slist_algorithms.hpp new file mode 100644 index 0000000..4f4a8f1 --- /dev/null +++ b/include/boost/intrusive/detail/common_slist_algorithms.hpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2008 +// +// 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_COMMON_SLIST_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +class common_slist_algorithms +{ + public: + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef NodeTraits node_traits; + + 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){ + //Logic error: possible use of linear lists with + //operations only permitted with lists + BOOST_INTRUSIVE_INVARIANT_ASSERT(p); + } + return p; + } + + static void init_header(node_ptr this_node) + { NodeTraits::set_next(this_node, this_node); } + + static void init(node_ptr this_node) + { NodeTraits::set_next(this_node, 0); } + + static bool unique(const_node_ptr this_node) + { + node_ptr next = NodeTraits::get_next(this_node); + return !next || next == this_node; + } + + static bool inited(const_node_ptr this_node) + { return !NodeTraits::get_next(this_node); } + + 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)); + } + + static void unlink_after(node_ptr prev_node, node_ptr last_node) + { NodeTraits::set_next(prev_node, last_node); } + + 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); + } + + 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); + } + } +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP 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 2e018c9..e8b3bb3 100644 --- a/include/boost/intrusive/detail/utilities.hpp +++ b/include/boost/intrusive/detail/utilities.hpp @@ -498,7 +498,8 @@ inline std::size_t floor_log2 (std::size_t x) inline float fast_log2 (float val) { - boost::uint32_t * const exp_ptr = reinterpret_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/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index e21f883..6947427 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -747,7 +747,7 @@ class hashtable_impl } BOOST_INTRUSIVE_CATCH(...){ this->clear_and_dispose(disposer); - BOOST_RETHROW; + BOOST_INTRUSIVE_RETHROW; } BOOST_INTRUSIVE_CATCH_END } diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp index 67d50a7..9228bcb 100644 --- a/include/boost/intrusive/intrusive_fwd.hpp +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -69,6 +69,8 @@ template , class O1 = none , class O2 = none , class O3 = none + , class O4 = none + , class O5 = 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..681c13b --- /dev/null +++ b/include/boost/intrusive/linear_slist_algorithms.hpp @@ -0,0 +1,326 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (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 +#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 + /// @cond + : public detail::common_slist_algorithms + /// @endcond +{ + /// @cond + typedef detail::common_slist_algorithms base_t; + /// @endcond + public: + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef NodeTraits node_traits; + + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + + //! 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); + + //! 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: + //! or it's a not inserted node: + //! return !NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool unique(const_node_ptr 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); + + //! Requires: prev_node must be in a circular list or be an empty circular list. + //! + //! Effects: Unlinks the next node of prev_node from the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(node_ptr prev_node); + + //! Requires: prev_node and last_node must be in a circular list + //! or be an empty circular list. + //! + //! Effects: Unlinks the range (prev_node, last_node) from the linear list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(node_ptr prev_node, node_ptr last_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); + + //! 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); + + #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + + //! Effects: Constructs an empty list, making this_node the only + //! node of the circular list: + //! NodeTraits::get_next(this_node) == this_node. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init_header(node_ptr this_node) + { NodeTraits::set_next(this_node, 0); } + + //! 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) + { return base_t::get_previous_node(prev_init_node, 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: 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); + } + + //! 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)); + base_t::unlink_after(p); + NodeTraits::set_next(i, first); + first = i; + i = nxti; + } + return first; + } + + //! Effects: Moves the first n nodes starting at p to the end of the list. + //! + //! Returns: 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. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static std::pair move_first_n_backwards(node_ptr p, std::size_t n) + { + std::pair ret(0, 0); + //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(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 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, 0); + } + + //Now link p after the new last node + NodeTraits::set_next(old_last, p); + NodeTraits::set_next(new_last, 0); + ret.first = first; + ret.second = new_last; + return ret; + } + + //! Effects: Moves the first n nodes starting at p to the beginning of the list. + //! + //! Returns: 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. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static std::pair move_first_n_forward(node_ptr p, std::size_t n) + { + std::pair ret(0, 0); + //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, 0); + ret.first = new_first; + ret.second = new_last; + return ret; + } +}; + +} //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..5968dd2 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(); } @@ -290,14 +290,8 @@ class list_impl //! Complexity: Constant. //! //! Note: Invalidates the iterators (but not the references) to the erased element. - void pop_back() - { - node_ptr to_erase = node_traits::get_previous(this->get_root_node()); - node_algorithms::unlink(to_erase); - this->priv_size_traits().decrement(); - if(safemode_or_autounlink) - node_algorithms::init(to_erase); - } + void pop_back() + { return this->pop_back_and_dispose(detail::null_disposer()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -329,14 +323,8 @@ class list_impl //! Complexity: Constant. //! //! Note: Invalidates the iterators (but not the references) to the erased element. - void pop_front() - { - node_ptr to_erase = node_traits::get_next(this->get_root_node()); - node_algorithms::unlink(to_erase); - this->priv_size_traits().decrement(); - if(safemode_or_autounlink) - node_algorithms::init(to_erase); - } + void pop_front() + { return this->pop_front_and_dispose(detail::null_disposer()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -406,7 +394,7 @@ class list_impl //! //! Complexity: Constant. const_iterator begin() const - { return cbegin(); } + { return this->cbegin(); } //! Effects: Returns a const_iterator to the first element contained in the list. //! @@ -430,7 +418,7 @@ class list_impl //! //! Complexity: Constant. const_iterator end() const - { return cend(); } + { return this->cend(); } //! Effects: Returns a constant iterator to the end of the list. //! @@ -447,7 +435,7 @@ class list_impl //! //! Complexity: Constant. reverse_iterator rbegin() - { return reverse_iterator(end()); } + { return reverse_iterator(this->end()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed list. @@ -456,7 +444,7 @@ class list_impl //! //! Complexity: Constant. const_reverse_iterator rbegin() const - { return crbegin(); } + { return this->crbegin(); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed list. @@ -483,7 +471,7 @@ class list_impl //! //! Complexity: Constant. const_reverse_iterator rend() const - { return crend(); } + { return this->crend(); } //! Effects: Returns a const_reverse_iterator pointing to the end //! of the reversed list. @@ -492,7 +480,7 @@ class list_impl //! //! Complexity: Constant. const_reverse_iterator crend() const - { return const_reverse_iterator(begin()); } + { return const_reverse_iterator(this->begin()); } //! Precondition: end_iterator must be a valid end iterator //! of list. @@ -503,7 +491,7 @@ class list_impl //! //! Complexity: Constant. static list_impl &container_from_end_iterator(iterator end_iterator) - { return priv_container_from_end_iterator(end_iterator); } + { return list_impl::priv_container_from_end_iterator(end_iterator); } //! Precondition: end_iterator must be a valid end const_iterator //! of list. @@ -514,7 +502,7 @@ class list_impl //! //! Complexity: Constant. static const list_impl &container_from_end_iterator(const_iterator end_iterator) - { return priv_container_from_end_iterator(end_iterator); } + { return list_impl::priv_container_from_end_iterator(end_iterator); } //! Effects: Returns the number of the elements contained in the list. //! @@ -540,7 +528,7 @@ class list_impl //! //! Note: Does not affect the validity of iterators and references. bool empty() const - { return node_algorithms::unique(this->get_root_node()); } + { return node_algorithms::unique(this->get_root_node()); } //! Effects: Swaps the elements of x and *this. //! @@ -569,21 +557,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 +569,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. @@ -623,16 +584,7 @@ class list_impl //! Note: Invalidates the iterators (but not the references) to the //! erased element. iterator erase(iterator i) - { - iterator erase = i; - ++i; - node_ptr to_erase = erase.pointed_node(); - node_algorithms::unlink(to_erase); - this->priv_size_traits().decrement(); - if(safemode_or_autounlink) - node_algorithms::init(to_erase); - return i; - } + { return this->erase_and_dispose(i, detail::null_disposer()); } //! Requires: first and last must be valid iterator to elements in *this. //! @@ -652,10 +604,7 @@ class list_impl iterator erase(iterator b, iterator e) { if(safemode_or_autounlink || constant_time_size){ - while(b != e){ - b = this->erase(b); - } - return b; + return this->erase_and_dispose(b, e, detail::null_disposer()); } else{ node_algorithms::unlink(b.pointed_node(), e.pointed_node()); @@ -680,14 +629,13 @@ class list_impl template iterator erase_and_dispose(iterator i, Disposer disposer) { - iterator erase = i; + node_ptr to_erase(i.pointed_node()); ++i; - node_ptr to_erase = erase.pointed_node(); node_algorithms::unlink(to_erase); this->priv_size_traits().decrement(); if(safemode_or_autounlink) node_algorithms::init(to_erase); - disposer(get_real_value_traits().to_value_ptr(to_erase)); + disposer(this->get_real_value_traits().to_value_ptr(to_erase)); return i; } @@ -708,10 +656,17 @@ class list_impl template iterator erase_and_dispose(iterator b, iterator e, Disposer disposer) { - while(b != e){ - b = this->erase_and_dispose(b, disposer); + node_ptr bp(b.pointed_node()), ep(e.pointed_node()); + node_algorithms::unlink(bp, ep); + while(bp != ep){ + node_ptr to_erase(bp); + bp = node_traits::get_next(bp); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + this->priv_size_traits().decrement(); } - return b; + return e; } //! Effects: Erases all the elements of the container. @@ -726,10 +681,10 @@ class list_impl void clear() { if(safemode_or_autounlink){ - this->erase(this->begin(), this->end()); + this->clear_and_dispose(detail::null_disposer()); } 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)); } } @@ -747,7 +702,18 @@ class list_impl //! Note: Invalidates the iterators to the erased elements. template void clear_and_dispose(Disposer disposer) - { this->erase_and_dispose(this->begin(), this->end(), disposer); } + { + iterator it(this->begin()), itend(this->end()); + while(it != itend){ + node_ptr to_erase(it.pointed_node()); + ++it; + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + } + node_algorithms::init_header(this->get_root_node()); + this->priv_size_traits().set_size(0); + } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -792,9 +758,9 @@ class list_impl //! Note: Does not affect the validity of iterators and references. iterator insert(iterator p, reference value) { - node_ptr to_insert = get_real_value_traits().to_node_ptr(value); + node_ptr to_insert = this->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); @@ -921,19 +887,10 @@ class list_impl //! list. Iterators of this list and all the references are not invalidated. void splice(iterator p, list_impl&x, iterator start, iterator end) { - if(start != end){ - if(constant_time_size){ - size_traits &thist = this->priv_size_traits(); - size_traits &xt = x.priv_size_traits(); - size_type increment = std::distance(start, end); - node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); - thist.set_size(thist.get_size() + increment); - xt.set_size(xt.get_size() - increment); - } - else{ - node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); - } - } + if(constant_time_size) + this->splice(p, x, start, end, std::distance(start, end)); + else + this->splice(p, x, start, end, 1);//distance is a dummy value } //! Requires: p must be a valid iterator of *this. @@ -978,7 +935,7 @@ class list_impl //! Complexity: The number of comparisons is approximately N log N, where N //! is the list's size. void sort() - { sort(std::less()); } + { this->sort(std::less()); } //! Requires: p must be a comparison function that induces a strict weak ordering //! @@ -1031,7 +988,7 @@ class list_impl //! //! Note: Iterators and references are not invalidated void merge(list_impl& x) - { merge(x, std::less()); } + { this->merge(x, std::less()); } //! Requires: p must be a comparison function that induces a strict weak //! ordering and both *this and x must be sorted according to that ordering @@ -1050,9 +1007,9 @@ class list_impl template void merge(list_impl& x, Predicate p) { - iterator e = this->end(); - iterator bx = x.begin(); - iterator ex = x.end(); + iterator e(this->end()); + iterator bx(x.begin()); + iterator ex(x.end()); for (iterator b = this->begin(); b != e; ++b) { size_type n(0); @@ -1087,7 +1044,7 @@ class list_impl //! Note: The relative order of elements that are not removed is unchanged, //! and iterators to elements that are not removed remain valid. void remove(const_reference value) - { remove_if(detail::equal_to_value(value)); } + { this->remove_if(detail::equal_to_value(value)); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1102,7 +1059,7 @@ class list_impl //! and iterators to elements that are not removed remain valid. template void remove_and_dispose(const_reference value, Disposer disposer) - { remove_and_dispose_if(detail::equal_to_value(value), disposer); } + { this->remove_and_dispose_if(detail::equal_to_value(value), disposer); } //! Effects: Removes all the elements for which a specified //! predicate is satisfied. No destructors are called. @@ -1115,7 +1072,7 @@ class list_impl //! and iterators to elements that are not removed remain valid. template void remove_if(Pred pred) - { remove_and_dispose_if(pred, detail::null_disposer()); } + { this->remove_and_dispose_if(pred, detail::null_disposer()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1132,17 +1089,15 @@ class list_impl template void remove_and_dispose_if(Pred pred, Disposer disposer) { - iterator first = begin(); - iterator last = end(); - while(first != last) { - iterator next = first; - ++next; - if(pred(*first)){ - pointer p = first.operator->(); - this->erase(first); - disposer(p); + iterator cur(this->begin()); + iterator last(this->end()); + while(cur != last) { + if(pred(*cur)){ + cur = this->erase_and_dispose(cur, disposer); + } + else{ + ++cur; } - first = next; } } @@ -1156,7 +1111,7 @@ class list_impl //! Note: The relative order of elements that are not removed is unchanged, //! and iterators to elements that are not removed remain valid. void unique() - { unique_and_dispose(std::equal_to(), detail::null_disposer()); } + { this->unique_and_dispose(std::equal_to(), detail::null_disposer()); } //! Effects: Removes adjacent duplicate elements or adjacent //! elements that satisfy some binary predicate from the list. @@ -1170,7 +1125,7 @@ class list_impl //! and iterators to elements that are not removed remain valid. template void unique(BinaryPredicate pred) - { unique_and_dispose(pred, detail::null_disposer()); } + { this->unique_and_dispose(pred, detail::null_disposer()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1186,7 +1141,7 @@ class list_impl //! and iterators to elements that are not removed remain valid. template void unique_and_dispose(Disposer disposer) - { unique_and_dispose(std::equal_to(), disposer); } + { this->unique_and_dispose(std::equal_to(), disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1203,18 +1158,19 @@ class list_impl template void unique_and_dispose(BinaryPredicate pred, Disposer disposer) { - if(!this->empty()){ - iterator first = begin(); - iterator after = first; + iterator itend(this->end()); + iterator cur(this->begin()); + + if(cur != itend){ + iterator after(cur); ++after; - while(after != this->end()){ - if(pred(*first, *after)){ - pointer p = after.operator->(); - after = erase(after); - disposer(p); + while(after != itend){ + if(pred(*cur, *after)){ + after = this->erase_and_dispose(after, disposer); } else{ - first = after++; + cur = after; + ++after; } } } @@ -1234,7 +1190,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 +1208,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); } @@ -1266,8 +1222,8 @@ 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); } @@ -1281,8 +1237,8 @@ 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..ab1f3dc 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,34 @@ 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 if the list container should +//!use a linear implementation instead of a circular one. +template +struct cache_last +{ +/// @cond + template + struct pack : Base + { + static const bool cache_last = 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 +499,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..232ab7e 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -21,13 +21,15 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include //std::size_t +#include //std::pair namespace boost { namespace intrusive { @@ -46,12 +48,27 @@ 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 constant_time_size = ConstantTimeSize; + static const bool linear = Linear; + static const bool cache_last = CacheLast; +}; + +template +struct root_plus_last +{ + Node root_; + NodePtr last_; +}; + +template +struct root_plus_last +{ + Node root_; }; template @@ -66,7 +83,9 @@ struct slist_defaults >::type > , constant_time_size + , linear , size_type + , cache_last >::type {}; @@ -86,15 +105,15 @@ struct slist_defaults //! //! The container supports the following options: //! \c base_hook<>/member_hook<>/value_traits<>, -//! \c constant_time_size<> and \c size_type<>. +//! \c constant_time_size<>, \c size_type<>, +//! \c linear<> and \c cache_last<>. //! //! The iterators of slist are forward iterators. slist provides a static //! function called "previous" to compute the previous iterator of a given iterator. //! This function has linear complexity. To improve the usability esp. with //! the '*_after' functions, ++end() == begin() and previous(begin()) == end() -//! are defined. In addition, whenever you have an end iterator, 'after this -//! iterator' means 'at the beginning of the list'. To improve the self-documentation -//! a "before_begin()" function is defined, returning the end() iterator. +//! are defined. An new special function "before_begin()" is defined, which returns +//! an iterator that points one less the beginning of the list: ++before_begin() == begin() #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED template #else @@ -129,10 +148,16 @@ 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; + static const bool cache_last = Config::cache_last; /// @cond private: @@ -152,6 +177,16 @@ 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))); + //A list with cached last node is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(cache_last && ((int)real_value_traits::link_mode == (int)auto_unlink))); + + node_ptr get_end_node() + { return node_ptr(linear ? 0 : this->get_root_node()); } + + const_node_ptr get_end_node() const + { return const_node_ptr(linear ? 0 : this->get_root_node()); } node_ptr get_root_node() { return node_ptr(&data_.root_plus_size_.root_); } @@ -159,16 +194,49 @@ class slist_impl const_node_ptr get_root_node() const { return const_node_ptr(&data_.root_plus_size_.root_); } + node_ptr get_last_node() + { return this->get_last_node(detail::bool_()); } + + const_node_ptr get_last_node() const + { return this->get_last_node(detail::bool_()); } + + void set_last_node(node_ptr n) + { return this->set_last_node(n, detail::bool_()); } + + node_ptr get_last_node(detail::bool_) + { return node_ptr(0); } + + const_node_ptr get_last_node(detail::bool_) const + { return const_node_ptr(0); } + + void set_last_node(node_ptr, detail::bool_) + {} + + node_ptr get_last_node(detail::bool_) + { return node_ptr(data_.root_plus_size_.last_); } + + const_node_ptr get_last_node(detail::bool_) const + { return const_node_ptr(data_.root_plus_size_.last_); } + + void set_last_node(node_ptr n, detail::bool_) + { data_.root_plus_size_.last_ = n; } + static node_ptr uncast(const_node_ptr ptr) + { return node_ptr(const_cast(detail::get_pointer(ptr))); } + + void set_default_constructed_state() { - return node_ptr(const_cast(detail::get_pointer(ptr))); + node_algorithms::init_header(this->get_root_node()); + this->priv_size_traits().set_size(size_type(0)); + if(cache_last){ + this->set_last_node(this->get_root_node()); + } } struct root_plus_size : public size_traits - { - node root_; - }; + , public root_plus_last + {}; struct data_t : public slist_impl::value_traits @@ -218,10 +286,7 @@ class slist_impl //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). slist_impl(const value_traits &v_traits = value_traits()) : data_(v_traits) - { - this->priv_size_traits().set_size(size_type(0)); - node_algorithms::init(this->get_root_node()); - } + { this->set_default_constructed_state(); } //! Requires: Dereferencing iterator must yield an lvalue of type value_type. //! @@ -235,9 +300,8 @@ class slist_impl slist_impl(Iterator b, Iterator e, const value_traits &v_traits = value_traits()) : data_(v_traits) { - this->priv_size_traits().set_size(size_type(0)); - node_algorithms::init(this->get_root_node()); - insert_after(before_begin(), b, e); + this->set_default_constructed_state(); + this->insert_after(this->before_begin(), b, e); } //! Effects: If it's a safe-mode @@ -263,11 +327,10 @@ class slist_impl void clear() { if(safemode_or_autounlink){ - this->erase_after(this->before_begin(), this->end()); + this->clear_and_dispose(detail::null_disposer()); } else{ - node_algorithms::init(this->get_root_node()); - this->priv_size_traits().set_size(size_type(0)); + this->set_default_constructed_state(); } } @@ -283,7 +346,17 @@ class slist_impl //! Note: Invalidates the iterators to the erased elements. template void clear_and_dispose(Disposer disposer) - { this->erase_after_and_dispose(this->before_begin(), this->end(), disposer); } + { + iterator it(this->begin()), itend(this->end()); + while(it != itend){ + node_ptr to_erase(it.pointed_node()); + ++it; + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + } + this->set_default_constructed_state(); + } //! Requires: value must be an lvalue. //! @@ -299,11 +372,33 @@ 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)); + if(cache_last){ + if(this->empty()){ + this->set_last_node(to_insert); + } + } node_algorithms::link_after(this->get_root_node(), to_insert); this->priv_size_traits().increment(); } + //! Requires: value must be an lvalue. + //! + //! Effects: Inserts the value in the back of the list. + //! No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + //! This function is only available is cache_last<> is true. + void push_back(reference value) + { + BOOST_STATIC_ASSERT((cache_last != 0)); + this->insert_after(iterator(this->get_last_node(), this), value); + } + //! Effects: Erases the first element of the list. //! No destructors are called. //! @@ -313,13 +408,7 @@ class slist_impl //! //! Note: Invalidates the iterators (but not the references) to the erased element. void pop_front() - { - node_ptr to_erase = node_traits::get_next(this->get_root_node()); - node_algorithms::unlink_after(this->get_root_node()); - this->priv_size_traits().decrement(); - if(safemode_or_autounlink) - node_algorithms::init(to_erase); - } + { return this->pop_front_and_dispose(detail::null_disposer()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -335,8 +424,16 @@ class slist_impl void pop_front_and_dispose(Disposer disposer) { node_ptr to_erase = node_traits::get_next(this->get_root_node()); - this->pop_front(); + node_algorithms::unlink_after(this->get_root_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)); + if(cache_last){ + if(this->empty()){ + this->set_last_node(this->get_root_node()); + } + } } //! Effects: Returns a reference to the first element of the list. @@ -345,7 +442,7 @@ class slist_impl //! //! Complexity: Constant. reference front() - { return *get_real_value_traits().to_value_ptr(node_traits::get_next(this->get_root_node())); } + { return *this->get_real_value_traits().to_value_ptr(node_traits::get_next(this->get_root_node())); } //! Effects: Returns a const_reference to the first element of the list. //! @@ -353,7 +450,35 @@ class slist_impl //! //! Complexity: Constant. const_reference front() const - { return *get_real_value_traits().to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); } + { return *this->get_real_value_traits().to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); } + + //! Effects: Returns a reference to the last element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + //! This function is only available is cache_last<> is true. + reference back() + { + BOOST_STATIC_ASSERT((cache_last != 0)); + return *this->get_real_value_traits().to_value_ptr(this->get_last_node()); + } + + //! Effects: Returns a const_reference to the last element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + //! This function is only available is cache_last<> is true. + const_reference back() const + { + BOOST_STATIC_ASSERT((cache_last != 0)); + return *this->get_real_value_traits().to_value_ptr(this->get_last_node()); + } //! Effects: Returns an iterator to the first element contained in the list. //! @@ -377,7 +502,7 @@ class slist_impl //! //! Complexity: Constant. const_iterator cbegin() const - { return const_iterator (node_traits::get_next(this->get_root_node()), this); } + { return const_iterator(node_traits::get_next(this->get_root_node()), this); } //! Effects: Returns an iterator to the end of the list. //! @@ -385,7 +510,7 @@ class slist_impl //! //! Complexity: Constant. iterator end() - { return iterator (this->get_root_node(), this); } + { return iterator(this->get_end_node(), this); } //! Effects: Returns a const_iterator to the end of the list. //! @@ -393,7 +518,7 @@ class slist_impl //! //! Complexity: Constant. const_iterator end() const - { return const_iterator (uncast(this->get_root_node()), this); } + { return const_iterator(uncast(this->get_end_node()), this); } //! Effects: Returns a const_iterator to the end of the list. //! @@ -401,7 +526,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 +535,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 +544,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 +553,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. @@ -439,7 +564,7 @@ class slist_impl //! //! Complexity: Constant. static slist_impl &container_from_end_iterator(iterator end_iterator) - { return priv_container_from_end_iterator(end_iterator); } + { return slist_impl::priv_container_from_end_iterator(end_iterator); } //! Precondition: end_iterator must be a valid end const_iterator //! of slist. @@ -450,7 +575,7 @@ class slist_impl //! //! Complexity: Constant. static const slist_impl &container_from_end_iterator(const_iterator end_iterator) - { return priv_container_from_end_iterator(end_iterator); } + { return slist_impl::priv_container_from_end_iterator(end_iterator); } //! Effects: Returns the number of the elements contained in the list. //! @@ -482,12 +607,18 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the number of elements of both lists. + //! Complexity: Linear to the number of elements of both lists. + //! Constant-time if linear<> and/or cache_last<> options are used. //! //! 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()); + if(cache_last){ + this->priv_swap_cache_last(other); + } + else{ + this->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()); @@ -505,45 +636,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); - } + { this->priv_shift_backwards(n, detail::bool_()); } //! Effects: Moves forward all the elements, so that the second //! element becomes the first, the third becomes the second... @@ -555,45 +648,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); - } + { this->priv_shift_forward(n, detail::bool_()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -610,18 +665,18 @@ class slist_impl //! Throws: If cloner throws. template void clone_from(const slist_impl &src, Cloner cloner, Disposer disposer) - { + { this->clear_and_dispose(disposer); BOOST_INTRUSIVE_TRY{ - iterator prev = this->before_begin(); + iterator prev(this->before_begin()); const_iterator b(src.begin()), e(src.end()); - for(; b != e; ++b, ++prev){ - this->insert_after(prev, *cloner(*b)); + for(; b != e; ++b){ + prev = this->insert_after(prev, *cloner(*b)); } } BOOST_INTRUSIVE_CATCH(...){ this->clear_and_dispose(disposer); - BOOST_RETHROW; + BOOST_INTRUSIVE_RETHROW; } BOOST_INTRUSIVE_CATCH_END } @@ -643,8 +698,12 @@ 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)); - node_algorithms::link_after(prev_p.pointed_node(), n); + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(n)); + node_ptr prev_n(prev_p.pointed_node()); + node_algorithms::link_after(prev_n, n); + if(cache_last && (this->get_last_node() == prev_n)){ + this->set_last_node(n); + } this->priv_size_traits().increment(); return iterator (n, this); } @@ -665,7 +724,7 @@ class slist_impl void insert_after(iterator prev_p, Iterator first, Iterator last) { for (; first != last; ++first) - prev_p = insert_after(prev_p, *first); + prev_p = this->insert_after(prev_p, *first); } //! Requires: value must be an lvalue and p must point to an element @@ -676,11 +735,12 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the number of elements before p. + //! Complexity: Linear to the number of elements before p. + //! Constant-time if cache_last<> is true and p == end(). //! //! Note: Does not affect the validity of iterators and references. iterator insert(iterator p, reference value) - { return insert_after(this->previous(p), value); } + { return this->insert_after(this->previous(p), value); } //! Requires: Dereferencing iterator must yield //! an lvalue of type value_type and p must point to an element @@ -693,11 +753,12 @@ class slist_impl //! //! Complexity: Linear to the number of elements inserted plus linear //! to the elements before b. + //! Linear to the number of elements to insert if cache_last<> option is true and p == end(). //! //! Note: Does not affect the validity of iterators and references. template void insert(iterator p, Iterator b, Iterator e) - { return insert_after(this->previous(p), b, e); } + { return this->insert_after(this->previous(p), b, e); } //! Effects: Erases the element after the element pointed by prev of //! the list. No destructors are called. @@ -712,16 +773,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 +783,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. @@ -775,7 +821,7 @@ class slist_impl //! Note: Invalidates the iterators (but not the references) to the //! erased elements. iterator erase(iterator first, iterator last) - { return erase_after(this->previous(first), last); } + { return this->erase_after(this->previous(first), last); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -794,11 +840,20 @@ 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_ptr prev_n(prev.pointed_node()); + node_algorithms::unlink_after(prev_n); + if(cache_last && (to_erase == this->get_last_node())){ + this->set_last_node(prev_n); + } + 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 +873,19 @@ 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); + node_ptr bfp(before_first.pointed_node()), lp(last.pointed_node()); + node_ptr fp(node_traits::get_next(bfp)); + node_algorithms::unlink_after(bfp, lp); + while(fp != lp){ + node_ptr to_erase(fp); + fp = node_traits::get_next(fp); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + this->priv_size_traits().decrement(); + } + if(cache_last && (node_traits::get_next(bfp) == this->get_end_node())){ + this->set_last_node(bfp); } return last; } @@ -863,7 +928,7 @@ class slist_impl //! erased elements. template iterator erase_and_dispose(iterator first, iterator last, Disposer disposer) - { return erase_after_and_dispose(this->previous(first), last, disposer); } + { return this->erase_after_and_dispose(this->previous(first), last, disposer); } //! Requires: Dereferencing iterator must yield //! an lvalue of type value_type. @@ -884,7 +949,7 @@ class slist_impl void assign(Iterator b, Iterator e) { this->clear(); - this->insert_after(before_begin(), b, e); + this->insert_after(this->before_begin(), b, e); } //! Requires: Disposer::operator()(pointer) shouldn't throw. @@ -921,18 +986,21 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the elements contained in x + //! Complexity: Linear to the elements contained in x. + //! Constant-time if cache_last<> option is true. //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. iterator splice_after(iterator prev, slist_impl &x) { if (!x.empty()){ - iterator last_x(x.previous(x.end())); - node_algorithms::transfer_after - ( prev.pointed_node() - , x.end().pointed_node() - , last_x.pointed_node()); + iterator last_x(x.previous(x.end())); //<- constant time if cache_last is active + node_ptr prev_n(prev.pointed_node()); + node_ptr last_x_n(last_x.pointed_node()); + if(cache_last && node_traits::get_next(prev_n) == this->get_end_node()){ + this->set_last_node(last_x_n); + } + node_algorithms::transfer_after( prev_n, x.before_begin().pointed_node(), last_x_n); 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)); return last_x; @@ -955,15 +1023,12 @@ class slist_impl //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. - void splice_after(iterator prev, slist_impl &x, iterator prev_ele) + void splice_after(iterator prev_pos, slist_impl &x, iterator prev_ele) { - iterator nxt = prev_ele; - ++nxt; - if (nxt != prev && prev_ele != prev){ - node_algorithms::transfer_after - (prev.pointed_node(), prev_ele.pointed_node(), nxt.pointed_node()); - this->priv_size_traits().increment(); - x.priv_size_traits().decrement(); + iterator elem = prev_ele; + ++elem; + if (elem != prev_pos && prev_ele != prev_pos){ + this->splice_after(prev_pos, x, prev_ele, elem, 1); } } @@ -984,19 +1049,11 @@ class slist_impl //! list. Iterators of this list and all the references are not invalidated. void splice_after(iterator prev_pos, slist_impl &x, iterator before_first, iterator before_last) { - if (before_first != before_last){ - if(constant_time_size){ - size_type increment = std::distance(before_first, before_last); - node_algorithms::transfer_after - (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); - this->priv_size_traits().set_size(this->priv_size_traits().get_size() + increment); - x.priv_size_traits().set_size(x.priv_size_traits().get_size() - increment); - } - else{ - node_algorithms::transfer_after - (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); - } - } + if(constant_time_size) + this->splice_after(prev_pos, x, before_first, before_last, std::distance(before_first, before_last)); + else + this->priv_splice_after + (prev_pos.pointed_node(), x, before_first.pointed_node(), before_last.pointed_node()); } //! Requires: prev_pos must be a dereferenceable iterator in *this or be @@ -1016,17 +1073,13 @@ class slist_impl void splice_after(iterator prev_pos, slist_impl &x, iterator before_first, iterator before_last, difference_type n) { if(n){ + BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(before_first, before_last) == n); + this->priv_splice_after + (prev_pos.pointed_node(), x, before_first.pointed_node(), before_last.pointed_node()); if(constant_time_size){ - BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(before_first, before_last) == n); - node_algorithms::transfer_after - (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); this->priv_size_traits().set_size(this->priv_size_traits().get_size() + n); x.priv_size_traits().set_size(x.priv_size_traits().get_size() - n); } - else{ - node_algorithms::transfer_after - (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); - } } } @@ -1044,11 +1097,13 @@ class slist_impl //! //! Complexity: Linear to the elements contained in x plus linear to //! the elements before it. + //! Linear to the elements before it if cache_last<> option is true. + //! Constant-time if cache_last<> option is true and it == end(). //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. iterator splice(iterator it, slist_impl &x) - { return splice_after(this->previous(it), x); } + { return this->splice_after(this->previous(it), x); } //! Requires: it p must be a valid iterator of *this. //! elem must point to an element contained in list @@ -1060,11 +1115,12 @@ class slist_impl //! Throws: Nothing. //! //! Complexity: Linear to the elements before pos and before elem. + //! Linear to the elements before elem if cache_last<> option is true and pos == end(). //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. void splice(iterator pos, slist_impl &x, iterator elem) - { return splice_after(this->previous(pos), x, this->previous(elem)); } + { return this->splice_after(this->previous(pos), x, x.previous(elem)); } //! Requires: pos must be a dereferenceable iterator in *this //! and first and last belong to x and first and last a valid range on x. @@ -1075,13 +1131,16 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the sum of elements before pos, first, and last. - //! Plus linear to the number of elements transferred if constant_time_size is true. + //! Complexity: Linear to the sum of elements before pos, first, and last + //! plus linear to the number of elements transferred if constant_time_size is true. + //! Linear to the sum of elements before first, and last + //! plus linear to the number of elements transferred if constant_time_size is true + //! if cache_last<> is true and pos == end() //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. void splice(iterator pos, slist_impl &x, iterator first, iterator last) - { return splice_after(this->previous(pos), x, this->previous(first), this->previous(last)); } + { return this->splice_after(this->previous(pos), x, x.previous(first), x.previous(last)); } //! Requires: pos must be a dereferenceable iterator in *this //! and first and last belong to x and first and last a valid range on x. @@ -1094,11 +1153,13 @@ class slist_impl //! Throws: Nothing. //! //! Complexity: Linear to the sum of elements before pos, first, and last. + //! Linear to the sum of elements before first and last + //! if cache_last<> is true and pos == end(). //! //! Note: Iterators of values obtained from list x now point to elements of this //! list. Iterators of this list and all the references are not invalidated. void splice(iterator pos, slist_impl &x, iterator first, iterator last, difference_type n) - { return splice_after(this->previous(pos), x, this->previous(first), this->previous(last), n); } + { return this->splice_after(this->previous(pos), x, x.previous(first), x.previous(last), n); } //! Effects: This function sorts the list *this according to std::less. //! The sort is stable, that is, the relative order of equivalent elements is preserved. @@ -1133,12 +1194,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 +1214,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 +1262,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 +1296,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. //! @@ -1244,8 +1305,13 @@ class slist_impl //! Complexity: This function is linear to the contained elements. //! //! Note: Iterators and references are not invalidated - void reverse() - { node_algorithms::reverse(this->get_root_node()); } + void reverse() + { + if(cache_last && !this->empty()){ + this->set_last_node(node_traits::get_next(this->get_root_node())); + } + this->priv_reverse(detail::bool_()); + } //! Effects: Removes all the elements that compare equal to value. //! No destructors are called. @@ -1258,7 +1324,7 @@ class slist_impl //! and iterators to elements that are not removed remain valid. This function is //! linear time: it performs exactly size() comparisons for equality. void remove(const_reference value) - { remove_if(detail::equal_to_value(value)); } + { this->remove_if(detail::equal_to_value(value)); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1273,7 +1339,7 @@ class slist_impl //! and iterators to elements that are not removed remain valid. template void remove_and_dispose(const_reference value, Disposer disposer) - { remove_and_dispose_if(detail::equal_to_value(value), disposer); } + { this->remove_and_dispose_if(detail::equal_to_value(value), disposer); } //! Effects: Removes all the elements for which a specified //! predicate is satisfied. No destructors are called. @@ -1286,7 +1352,7 @@ class slist_impl //! and iterators to elements that are not removed remain valid. template void remove_if(Pred pred) - { remove_and_dispose_if(pred, detail::null_disposer()); } + { this->remove_and_dispose_if(pred, detail::null_disposer()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1303,18 +1369,20 @@ class slist_impl template void remove_and_dispose_if(Pred pred, Disposer disposer) { - iterator bcur(this->before_begin()), cur, e(this->end()); + iterator bcur(this->before_begin()), cur(this->begin()), e(this->end()); - while(++(cur = bcur) != e){ + while(cur != e){ if (pred(*cur)){ - pointer p = cur.operator->(); - this->erase_after(bcur); - disposer(p); + cur = this->erase_after_and_dispose(bcur, disposer); } else{ - ++bcur; + bcur = cur; + ++cur; } } + if(cache_last){ + this->set_last_node(bcur.pointed_node()); + } } //! Effects: Removes adjacent duplicate elements or adjacent @@ -1327,7 +1395,7 @@ class slist_impl //! Note: The relative order of elements that are not removed is unchanged, //! and iterators to elements that are not removed remain valid. void unique() - { unique_and_dispose(std::equal_to(), detail::null_disposer()); } + { this->unique_and_dispose(std::equal_to(), detail::null_disposer()); } //! Effects: Removes adjacent duplicate elements or adjacent //! elements that satisfy some binary predicate from the list. @@ -1341,7 +1409,7 @@ class slist_impl //! and iterators to elements that are not removed remain valid. template void unique(BinaryPredicate pred) - { unique_and_dispose(pred, detail::null_disposer()); } + { this->unique_and_dispose(pred, detail::null_disposer()); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1357,7 +1425,7 @@ class slist_impl //! and iterators to elements that are not removed remain valid. template void unique_and_dispose(Disposer disposer) - { unique(std::equal_to(), disposer); } + { this->unique(std::equal_to(), disposer); } //! Requires: Disposer::operator()(pointer) shouldn't throw. //! @@ -1374,21 +1442,23 @@ class slist_impl template void unique_and_dispose(BinaryPredicate pred, Disposer disposer) { - iterator end_n(end()); - iterator cur(begin()); - iterator cur_next; - - if (cur != end_n) { - while(++(cur_next = cur) != end_n) { - if (pred(*cur, *cur_next)){ - pointer p = cur_next.operator->(); - this->erase_after(cur); - disposer(p); + iterator end_n(this->end()); + iterator bcur(this->begin()); + if(bcur != end_n){ + iterator cur(bcur); + ++cur; + while(cur != end_n) { + if (pred(*bcur, *cur)){ + cur = this->erase_after_and_dispose(bcur, disposer); } else{ + bcur = cur; ++cur; } } + if(cache_last){ + this->set_last_node(bcur.pointed_node()); + } } } @@ -1406,7 +1476,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 +1494,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); } @@ -1438,8 +1508,8 @@ 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); } @@ -1453,8 +1523,8 @@ 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); } @@ -1464,12 +1534,16 @@ class slist_impl //! //! Throws: Nothing. //! - //! Complexity: Linear to the number of elements before i. + //! Complexity: Linear to the number of elements before i. + //! Constant if cache_last<> is true and i == end(). iterator previous(iterator i) { + if(cache_last && (i.pointed_node() == this->get_end_node())){ + return iterator(this->get_last_node(), this); + } return iterator (node_algorithms::get_previous_node - (before_begin().pointed_node(), i.pointed_node()), 0); + (this->before_begin().pointed_node(), i.pointed_node()), this); } //! Returns: The const_iterator to the element before i in the list. @@ -1479,18 +1553,117 @@ class slist_impl //! Throws: Nothing. //! //! Complexity: Linear to the number of elements before i. + //! Constant if cache_last<> is true and i == end(). const_iterator previous(const_iterator i) const { + if(cache_last && (i.pointed_node() == this->get_end_node())){ + return iterator(uncast(this->get_last_node()), this); + } return const_iterator (node_algorithms::get_previous_node - (before_begin().pointed_node(), i.pointed_node()), 0); + (this->before_begin().pointed_node(), i.pointed_node()), this); } private: + void priv_splice_after(node_ptr prev_pos_n, slist_impl &x, node_ptr before_first_n, node_ptr before_last_n) + { + if(cache_last){ + if(node_traits::get_next(prev_pos_n) == this->get_end_node()){ + this->set_last_node(before_last_n); + } + if(node_traits::get_next(before_last_n) == x.get_end_node()){ + x.set_last_node(before_first_n); + } + } + node_algorithms::transfer_after(prev_pos_n, before_first_n, before_last_n); + } + + 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_ptr last = node_algorithms::move_forward(this->get_root_node(), (std::size_t)n); + if(cache_last && last){ + this->set_last_node(last); + } + } + + void priv_shift_backwards(size_type n, detail::bool_) + { + std::pair ret( + node_algorithms::move_first_n_forward + (node_traits::get_next(this->get_root_node()), (std::size_t)n)); + if(ret.first){ + node_traits::set_next(this->get_root_node(), ret.first); + if(cache_last){ + this->set_last_node(ret.second); + } + } + } + + void priv_shift_forward(size_type n, detail::bool_) + { + node_ptr last = node_algorithms::move_backwards(this->get_root_node(), (std::size_t)n); + if(cache_last && last){ + this->set_last_node(last); + } + } + + void priv_shift_forward(size_type n, detail::bool_) + { + std::pair ret( + node_algorithms::move_first_n_backwards + (node_traits::get_next(this->get_root_node()), (std::size_t)n)); + if(ret.first){ + node_traits::set_next(this->get_root_node(), ret.first); + if(cache_last){ + this->set_last_node(ret.second); + } + } + } + + void priv_swap_cache_last(slist_impl &other) + { + node_ptr other_last(other.get_last_node()); + node_ptr this_last(this->get_last_node()); + node_ptr other_bfirst(other.get_root_node()); + node_ptr this_bfirst(this->get_root_node()); + node_algorithms::transfer_after(this_bfirst, other_bfirst, other_last); + node_algorithms::transfer_after(other_bfirst, other_last != other_bfirst? other_last : this_bfirst, this_last); + node_ptr tmp(this->get_last_node()); + this->set_last_node(other.get_last_node()); + other.set_last_node(tmp); + if(this->get_last_node() == other_bfirst){ + this->set_last_node(this_bfirst); + } + if(other.get_last_node() == this_bfirst){ + other.set_last_node(other_bfirst); + } + } + + //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_); + ( detail::get_pointer(end_iterator.pointed_node()), (&root_plus_size::root_)); data_t *d = detail::parent_from_member ( r, &data_t::root_plus_size_); slist_impl *s = detail::parent_from_member(d, &slist_impl::data_); @@ -1620,13 +1793,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, O5>::type packed_options; typedef typename detail::get_value_traits ::type value_traits; typedef slist_impl @@ -1635,6 +1808,8 @@ struct make_slist < value_traits , typename packed_options::size_type , packed_options::constant_time_size + , packed_options::linear + , packed_options::cache_last > > implementation_defined; /// @endcond @@ -1643,12 +1818,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/Intrusive.sln b/proj/vc7ide/Intrusive.sln index 4fb0638..8767b1e 100644 --- a/proj/vc7ide/Intrusive.sln +++ b/proj/vc7ide/Intrusive.sln @@ -1,175 +1,175 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list", "list\list.vcproj", "{977B61B4-9968-497C-9F0B-24A8145473B8}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist", "slist\slist.vcproj", "{5A02061D-3728-4C49-AFC8-0130C1F161C0}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multiset", "multiset\multiset.vcproj", "{961F0E06-C092-4AF7-ABC5-2A49999F3B79}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_intrusivelib", "_intrusivelib\_intrusivelib.vcproj", "{90F3C5BD-8E6C-4629-BC71-A1009EC88059}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "set", "set\set.vcproj", "{960E01F6-92C1-F74A-BCA5-2A9F3B994979}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_set", "unordered_set\unordered_set.vcproj", "{90E701E6-2C91-F4A7-BA6C-A9F3B0949279}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_multiset", "unordered_multiset\unordered_multiset.vcproj", "{9101EE76-BB6C-2C91-F4B7-A9F3B9490279}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "perf_test", "perf_test\perf_test.vcproj", "{910E70E6-2C91-AA67-BF4C-A9C74A309927}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "default_hook", "default_hook\default_hook.vcproj", "{761A79B4-9968-CB81-F02B-2A4497345475}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stateful_value_traits", "stateful_value_traits\stateful_value_traits.vcproj", "{9571A7B4-9968-B9C1-17FB-134547B46975}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "virtual_base", "virtual_base\virtual_base.vcproj", "{3579B1A4-9894-02AB-CB81-297B46154345}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_functions", "make_functions\make_functions.vcproj", "{7679B41B-F2B4-9176-CB81-35449467B435}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "custom_bucket_traits", "custom_bucket_traits\custom_bucket_traits.vcproj", "{31C77B84-0B2C-9481-CB81-27A149F33825}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "external_value_traits", "external_value_traits\external_value_traits.vcproj", "{97B69A72-B9D3-7389-17FB-74612F4A9543}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "splay_multiset", "splay_multiset\splay_multiset.vcproj", "{01E70176-B6C5-BF47-2C91-A949077BA323}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "splay_set", "splay_set\splay_set.vcproj", "{1E6909E7-C971-F24A-6C7B-A92094B71B59}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avl_multiset", "avl_multiset\avl_multiset.vcproj", "{0AE70176-5B8C-4BC7-392C-A4A312B07893}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avl_set", "avl_set\avl_set.vcproj", "{16909EE7-24AF-97C1-C76B-204B971BA959}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sg_multiset", "sg_multiset\sg_multiset.vcproj", "{07022E76-6CB5-92C1-B47F-A10772A79B43}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sg_set", "sg_set\sg_set.vcproj", "{1690A9E7-DB57-971C-F24A-09B752A942F7}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {977B61B4-9968-497C-9F0B-24A8145473B8}.Debug.ActiveCfg = Debug|Win32 - {977B61B4-9968-497C-9F0B-24A8145473B8}.Debug.Build.0 = Debug|Win32 - {977B61B4-9968-497C-9F0B-24A8145473B8}.Release.ActiveCfg = Release|Win32 - {977B61B4-9968-497C-9F0B-24A8145473B8}.Release.Build.0 = Release|Win32 - {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Debug.ActiveCfg = Debug|Win32 - {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Debug.Build.0 = Debug|Win32 - {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Release.ActiveCfg = Release|Win32 - {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Release.Build.0 = Release|Win32 - {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Debug.ActiveCfg = Debug|Win32 - {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Debug.Build.0 = Debug|Win32 - {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Release.ActiveCfg = Release|Win32 - {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Release.Build.0 = Release|Win32 - {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Debug.ActiveCfg = Debug|Win32 - {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Debug.Build.0 = Debug|Win32 - {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Release.ActiveCfg = Release|Win32 - {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Release.Build.0 = Release|Win32 - {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Debug.ActiveCfg = Debug|Win32 - {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Debug.Build.0 = Debug|Win32 - {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Release.ActiveCfg = Release|Win32 - {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Release.Build.0 = Release|Win32 - {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Debug.ActiveCfg = Debug|Win32 - {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Debug.Build.0 = Debug|Win32 - {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Release.ActiveCfg = Release|Win32 - {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Release.Build.0 = Release|Win32 - {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Debug.ActiveCfg = Debug|Win32 - {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Debug.Build.0 = Debug|Win32 - {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Release.ActiveCfg = Release|Win32 - {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Release.Build.0 = Release|Win32 - {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Debug.ActiveCfg = Debug|Win32 - {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Debug.Build.0 = Debug|Win32 - {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Release.ActiveCfg = Release|Win32 - {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Release.Build.0 = Release|Win32 - {761A79B4-9968-CB81-F02B-2A4497345475}.Debug.ActiveCfg = Debug|Win32 - {761A79B4-9968-CB81-F02B-2A4497345475}.Debug.Build.0 = Debug|Win32 - {761A79B4-9968-CB81-F02B-2A4497345475}.Release.ActiveCfg = Release|Win32 - {761A79B4-9968-CB81-F02B-2A4497345475}.Release.Build.0 = Release|Win32 - {9571A7B4-9968-B9C1-17FB-134547B46975}.Debug.ActiveCfg = Debug|Win32 - {9571A7B4-9968-B9C1-17FB-134547B46975}.Debug.Build.0 = Debug|Win32 - {9571A7B4-9968-B9C1-17FB-134547B46975}.Release.ActiveCfg = Release|Win32 - {9571A7B4-9968-B9C1-17FB-134547B46975}.Release.Build.0 = Release|Win32 - {3579B1A4-9894-02AB-CB81-297B46154345}.Debug.ActiveCfg = Debug|Win32 - {3579B1A4-9894-02AB-CB81-297B46154345}.Debug.Build.0 = Debug|Win32 - {3579B1A4-9894-02AB-CB81-297B46154345}.Release.ActiveCfg = Release|Win32 - {3579B1A4-9894-02AB-CB81-297B46154345}.Release.Build.0 = Release|Win32 - {7679B41B-F2B4-9176-CB81-35449467B435}.Debug.ActiveCfg = Debug|Win32 - {7679B41B-F2B4-9176-CB81-35449467B435}.Debug.Build.0 = Debug|Win32 - {7679B41B-F2B4-9176-CB81-35449467B435}.Release.ActiveCfg = Release|Win32 - {7679B41B-F2B4-9176-CB81-35449467B435}.Release.Build.0 = Release|Win32 - {31C77B84-0B2C-9481-CB81-27A149F33825}.Debug.ActiveCfg = Debug|Win32 - {31C77B84-0B2C-9481-CB81-27A149F33825}.Debug.Build.0 = Debug|Win32 - {31C77B84-0B2C-9481-CB81-27A149F33825}.Release.ActiveCfg = Release|Win32 - {31C77B84-0B2C-9481-CB81-27A149F33825}.Release.Build.0 = Release|Win32 - {97B69A72-B9D3-7389-17FB-74612F4A9543}.Debug.ActiveCfg = Debug|Win32 - {97B69A72-B9D3-7389-17FB-74612F4A9543}.Debug.Build.0 = Debug|Win32 - {97B69A72-B9D3-7389-17FB-74612F4A9543}.Release.ActiveCfg = Release|Win32 - {97B69A72-B9D3-7389-17FB-74612F4A9543}.Release.Build.0 = Release|Win32 - {01E70176-B6C5-BF47-2C91-A949077BA323}.Debug.ActiveCfg = Debug|Win32 - {01E70176-B6C5-BF47-2C91-A949077BA323}.Debug.Build.0 = Debug|Win32 - {01E70176-B6C5-BF47-2C91-A949077BA323}.Release.ActiveCfg = Release|Win32 - {01E70176-B6C5-BF47-2C91-A949077BA323}.Release.Build.0 = Release|Win32 - {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Debug.ActiveCfg = Debug|Win32 - {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Debug.Build.0 = Debug|Win32 - {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Release.ActiveCfg = Release|Win32 - {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Release.Build.0 = Release|Win32 - {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Debug.ActiveCfg = Debug|Win32 - {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Debug.Build.0 = Debug|Win32 - {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Release.ActiveCfg = Release|Win32 - {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Release.Build.0 = Release|Win32 - {16909EE7-24AF-97C1-C76B-204B971BA959}.Debug.ActiveCfg = Debug|Win32 - {16909EE7-24AF-97C1-C76B-204B971BA959}.Debug.Build.0 = Debug|Win32 - {16909EE7-24AF-97C1-C76B-204B971BA959}.Release.ActiveCfg = Release|Win32 - {16909EE7-24AF-97C1-C76B-204B971BA959}.Release.Build.0 = Release|Win32 - {07022E76-6CB5-92C1-B47F-A10772A79B43}.Debug.ActiveCfg = Debug|Win32 - {07022E76-6CB5-92C1-B47F-A10772A79B43}.Debug.Build.0 = Debug|Win32 - {07022E76-6CB5-92C1-B47F-A10772A79B43}.Release.ActiveCfg = Release|Win32 - {07022E76-6CB5-92C1-B47F-A10772A79B43}.Release.Build.0 = Release|Win32 - {1690A9E7-DB57-971C-F24A-09B752A942F7}.Debug.ActiveCfg = Debug|Win32 - {1690A9E7-DB57-971C-F24A-09B752A942F7}.Debug.Build.0 = Debug|Win32 - {1690A9E7-DB57-971C-F24A-09B752A942F7}.Release.ActiveCfg = Release|Win32 - {1690A9E7-DB57-971C-F24A-09B752A942F7}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list", "list\list.vcproj", "{977B61B4-9968-497C-9F0B-24A8145473B8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist", "slist\slist.vcproj", "{5A02061D-3728-4C49-AFC8-0130C1F161C0}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multiset", "multiset\multiset.vcproj", "{961F0E06-C092-4AF7-ABC5-2A49999F3B79}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_intrusivelib", "_intrusivelib\_intrusivelib.vcproj", "{90F3C5BD-8E6C-4629-BC71-A1009EC88059}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "set", "set\set.vcproj", "{960E01F6-92C1-F74A-BCA5-2A9F3B994979}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_set", "unordered_set\unordered_set.vcproj", "{90E701E6-2C91-F4A7-BA6C-A9F3B0949279}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_multiset", "unordered_multiset\unordered_multiset.vcproj", "{9101EE76-BB6C-2C91-F4B7-A9F3B9490279}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "perf_test", "perf_test\perf_test.vcproj", "{910E70E6-2C91-AA67-BF4C-A9C74A309927}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "default_hook", "default_hook\default_hook.vcproj", "{761A79B4-9968-CB81-F02B-2A4497345475}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stateful_value_traits", "stateful_value_traits\stateful_value_traits.vcproj", "{9571A7B4-9968-B9C1-17FB-134547B46975}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "virtual_base", "virtual_base\virtual_base.vcproj", "{3579B1A4-9894-02AB-CB81-297B46154345}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_functions", "make_functions\make_functions.vcproj", "{7679B41B-F2B4-9176-CB81-35449467B435}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "custom_bucket_traits", "custom_bucket_traits\custom_bucket_traits.vcproj", "{31C77B84-0B2C-9481-CB81-27A149F33825}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "external_value_traits", "external_value_traits\external_value_traits.vcproj", "{97B69A72-B9D3-7389-17FB-74612F4A9543}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "splay_multiset", "splay_multiset\splay_multiset.vcproj", "{01E70176-B6C5-BF47-2C91-A949077BA323}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "splay_set", "splay_set\splay_set.vcproj", "{1E6909E7-C971-F24A-6C7B-A92094B71B59}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avl_multiset", "avl_multiset\avl_multiset.vcproj", "{0AE70176-5B8C-4BC7-392C-A4A312B07893}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avl_set", "avl_set\avl_set.vcproj", "{16909EE7-24AF-97C1-C76B-204B971BA959}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sg_multiset", "sg_multiset\sg_multiset.vcproj", "{07022E76-6CB5-92C1-B47F-A10772A79B43}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sg_set", "sg_set\sg_set.vcproj", "{1690A9E7-DB57-971C-F24A-09B752A942F7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {977B61B4-9968-497C-9F0B-24A8145473B8}.Debug.ActiveCfg = Debug|Win32 + {977B61B4-9968-497C-9F0B-24A8145473B8}.Debug.Build.0 = Debug|Win32 + {977B61B4-9968-497C-9F0B-24A8145473B8}.Release.ActiveCfg = Release|Win32 + {977B61B4-9968-497C-9F0B-24A8145473B8}.Release.Build.0 = Release|Win32 + {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Debug.ActiveCfg = Debug|Win32 + {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Debug.Build.0 = Debug|Win32 + {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Release.ActiveCfg = Release|Win32 + {5A02061D-3728-4C49-AFC8-0130C1F161C0}.Release.Build.0 = Release|Win32 + {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Debug.ActiveCfg = Debug|Win32 + {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Debug.Build.0 = Debug|Win32 + {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Release.ActiveCfg = Release|Win32 + {961F0E06-C092-4AF7-ABC5-2A49999F3B79}.Release.Build.0 = Release|Win32 + {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Debug.ActiveCfg = Debug|Win32 + {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Debug.Build.0 = Debug|Win32 + {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Release.ActiveCfg = Release|Win32 + {90F3C5BD-8E6C-4629-BC71-A1009EC88059}.Release.Build.0 = Release|Win32 + {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Debug.ActiveCfg = Debug|Win32 + {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Debug.Build.0 = Debug|Win32 + {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Release.ActiveCfg = Release|Win32 + {960E01F6-92C1-F74A-BCA5-2A9F3B994979}.Release.Build.0 = Release|Win32 + {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Debug.ActiveCfg = Debug|Win32 + {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Debug.Build.0 = Debug|Win32 + {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Release.ActiveCfg = Release|Win32 + {90E701E6-2C91-F4A7-BA6C-A9F3B0949279}.Release.Build.0 = Release|Win32 + {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Debug.ActiveCfg = Debug|Win32 + {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Debug.Build.0 = Debug|Win32 + {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Release.ActiveCfg = Release|Win32 + {9101EE76-BB6C-2C91-F4B7-A9F3B9490279}.Release.Build.0 = Release|Win32 + {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Debug.ActiveCfg = Debug|Win32 + {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Debug.Build.0 = Debug|Win32 + {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Release.ActiveCfg = Release|Win32 + {910E70E6-2C91-AA67-BF4C-A9C74A309927}.Release.Build.0 = Release|Win32 + {761A79B4-9968-CB81-F02B-2A4497345475}.Debug.ActiveCfg = Debug|Win32 + {761A79B4-9968-CB81-F02B-2A4497345475}.Debug.Build.0 = Debug|Win32 + {761A79B4-9968-CB81-F02B-2A4497345475}.Release.ActiveCfg = Release|Win32 + {761A79B4-9968-CB81-F02B-2A4497345475}.Release.Build.0 = Release|Win32 + {9571A7B4-9968-B9C1-17FB-134547B46975}.Debug.ActiveCfg = Debug|Win32 + {9571A7B4-9968-B9C1-17FB-134547B46975}.Debug.Build.0 = Debug|Win32 + {9571A7B4-9968-B9C1-17FB-134547B46975}.Release.ActiveCfg = Release|Win32 + {9571A7B4-9968-B9C1-17FB-134547B46975}.Release.Build.0 = Release|Win32 + {3579B1A4-9894-02AB-CB81-297B46154345}.Debug.ActiveCfg = Debug|Win32 + {3579B1A4-9894-02AB-CB81-297B46154345}.Debug.Build.0 = Debug|Win32 + {3579B1A4-9894-02AB-CB81-297B46154345}.Release.ActiveCfg = Release|Win32 + {3579B1A4-9894-02AB-CB81-297B46154345}.Release.Build.0 = Release|Win32 + {7679B41B-F2B4-9176-CB81-35449467B435}.Debug.ActiveCfg = Debug|Win32 + {7679B41B-F2B4-9176-CB81-35449467B435}.Debug.Build.0 = Debug|Win32 + {7679B41B-F2B4-9176-CB81-35449467B435}.Release.ActiveCfg = Release|Win32 + {7679B41B-F2B4-9176-CB81-35449467B435}.Release.Build.0 = Release|Win32 + {31C77B84-0B2C-9481-CB81-27A149F33825}.Debug.ActiveCfg = Debug|Win32 + {31C77B84-0B2C-9481-CB81-27A149F33825}.Debug.Build.0 = Debug|Win32 + {31C77B84-0B2C-9481-CB81-27A149F33825}.Release.ActiveCfg = Release|Win32 + {31C77B84-0B2C-9481-CB81-27A149F33825}.Release.Build.0 = Release|Win32 + {97B69A72-B9D3-7389-17FB-74612F4A9543}.Debug.ActiveCfg = Debug|Win32 + {97B69A72-B9D3-7389-17FB-74612F4A9543}.Debug.Build.0 = Debug|Win32 + {97B69A72-B9D3-7389-17FB-74612F4A9543}.Release.ActiveCfg = Release|Win32 + {97B69A72-B9D3-7389-17FB-74612F4A9543}.Release.Build.0 = Release|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Debug.ActiveCfg = Debug|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Debug.Build.0 = Debug|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Release.ActiveCfg = Release|Win32 + {01E70176-B6C5-BF47-2C91-A949077BA323}.Release.Build.0 = Release|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Debug.ActiveCfg = Debug|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Debug.Build.0 = Debug|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Release.ActiveCfg = Release|Win32 + {1E6909E7-C971-F24A-6C7B-A92094B71B59}.Release.Build.0 = Release|Win32 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Debug.ActiveCfg = Debug|Win32 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Debug.Build.0 = Debug|Win32 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Release.ActiveCfg = Release|Win32 + {0AE70176-5B8C-4BC7-392C-A4A312B07893}.Release.Build.0 = Release|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.Debug.ActiveCfg = Debug|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.Debug.Build.0 = Debug|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.Release.ActiveCfg = Release|Win32 + {16909EE7-24AF-97C1-C76B-204B971BA959}.Release.Build.0 = Release|Win32 + {07022E76-6CB5-92C1-B47F-A10772A79B43}.Debug.ActiveCfg = Debug|Win32 + {07022E76-6CB5-92C1-B47F-A10772A79B43}.Debug.Build.0 = Debug|Win32 + {07022E76-6CB5-92C1-B47F-A10772A79B43}.Release.ActiveCfg = Release|Win32 + {07022E76-6CB5-92C1-B47F-A10772A79B43}.Release.Build.0 = Release|Win32 + {1690A9E7-DB57-971C-F24A-09B752A942F7}.Debug.ActiveCfg = Debug|Win32 + {1690A9E7-DB57-971C-F24A-09B752A942F7}.Debug.Build.0 = Debug|Win32 + {1690A9E7-DB57-971C-F24A-09B752A942F7}.Release.ActiveCfg = Release|Win32 + {1690A9E7-DB57-971C-F24A-09B752A942F7}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj index 9b36d35..587661c 100644 --- a/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj +++ b/proj/vc7ide/_intrusivelib/_intrusivelib.vcproj @@ -135,6 +135,9 @@ + + @@ -213,6 +216,9 @@ + + diff --git a/proj/vc7ide/to-do.txt b/proj/vc7ide/to-do.txt deleted file mode 100644 index ae66bad..0000000 --- a/proj/vc7ide/to-do.txt +++ /dev/null @@ -1,7 +0,0 @@ -add includes needed for the snippets -add section explaining splice(...,n) -Faltaría, en mi opinión, una guía de qué headers incluyen a cuáles. P.ej., -los *_hook.hpp típicamente están incluidos por el header del contenedor asociado, etc. -Add resize() to list -Optimize rehash for when shrinking: there is no need to hash the values. -Optimize store_hash to work with the same node and type traits as store_hash diff --git a/test/itestvalue.hpp b/test/itestvalue.hpp index 6878158..d6338bb 100644 --- a/test/itestvalue.hpp +++ b/test/itestvalue.hpp @@ -237,7 +237,7 @@ struct testvalue // have to be handled appropriately when copied: testvalue & operator= (const testvalue& src) - { + {/* set_base_hook_t::operator=(src); set_auto_base_hook_t::operator=(src); this->set_node_ = src.set_node_; @@ -270,7 +270,7 @@ struct testvalue slist_auto_base_hook_t::operator=(src); this->slist_node_ = src.slist_node_; this->slist_auto_node_ = src.slist_auto_node_; - +*/ value_ = src.value_; return *this; } @@ -366,6 +366,14 @@ struct even_odd } }; +struct is_even +{ + template + bool operator() + (const testvalue& v1) const + { return (v1.value_ & 1) == 0; } +}; + } //namespace boost{ } //namespace intrusive{ diff --git a/test/list_test.cpp b/test/list_test.cpp index 7b28289..3a000a9 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -31,6 +31,8 @@ struct test_list static void test_all(std::vector& values); static void test_front_back(std::vector& values); static void test_sort(std::vector& values); + static void test_merge(std::vector& values); + static void test_remove_unique(std::vector& values); static void test_insert(std::vector& values); static void test_shift(std::vector& values); static void test_swap(std::vector& values); @@ -58,19 +60,13 @@ void test_list::test_all(std::vector { int init_values [] = { 5, 3, 1, 4, 2 }; TEST_INTRUSIVE_SEQUENCE( init_values, testlist.begin() ); } } + +//test: merge due to error in merge implementation: +template +void test_list + ::test_remove_unique (std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size + > list_type; + { + list_type list(values.begin(), values.end()); + list.remove_if(is_even()); + int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() ); + } + { + std::vector values2(values); + list_type list(values.begin(), values.end()); + list.insert(list.end(), values2.begin(), values2.end()); + list.sort(); + int init_values [] = { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() ); + list.unique(); + int init_values2 [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values2, list.begin() ); + } +} + +//test: merge due to error in merge implementation: +template +void test_list + ::test_merge (std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size + > list_type; + list_type testlist1, testlist2; + testlist1.push_front (values[0]); + testlist2.push_front (values[4]); + testlist2.push_front (values[3]); + testlist2.push_front (values[2]); + testlist1.merge (testlist2); + + int init_values [] = { 1, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); +} //test: assign, insert, const_iterator, const_reverse_iterator, erase, s_iterator_to: template @@ -194,26 +244,29 @@ void test_list 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 +331,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..c8055c1 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -24,24 +24,28 @@ using namespace boost::intrusive; -template +template struct test_slist { typedef typename ValueTraits::value_type value_type; - static void test_all (std::vector& values); - static void test_front_back (std::vector& values); + static void test_all(std::vector& values); + static void test_front(std::vector& values); + static void test_back(std::vector& values, detail::bool_); + static void test_back(std::vector& values, detail::bool_); static void test_sort(std::vector& values); - static void test_merge (std::vector& values); + static void test_merge(std::vector& values); + static void test_remove_unique(std::vector& values); static void test_insert(std::vector& values); static void test_shift(std::vector& values); 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_slow_insert(std::vector& values); + static void test_clone(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 +54,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; { list_type list(values.begin(), values.end()); @@ -58,21 +64,23 @@ void test_slist list.insert(list.end(), values.begin(), values.end()); test::test_sequence_container(list, values); } - test_front_back (values); + test_front(values); + test_back(values, detail::bool_()); test_sort(values); test_merge (values); + test_remove_unique(values); test_insert(values); test_shift(values); 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 - ::test_front_back (std::vector& values) +template +void test_slist + ::test_front(std::vector& values) { typedef typename ValueTraits::value_type value_type; typedef slist @@ -80,6 +88,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist; BOOST_TEST (testlist.empty()); @@ -98,11 +108,45 @@ void test_slist testlist.pop_front(); BOOST_TEST (testlist.empty()); -} +} + +//test: push_front, pop_front, front, size, empty: +template +void test_slist + ::test_back(std::vector& values, detail::bool_) +{ + typedef typename ValueTraits::value_type value_type; + typedef slist + < value_type + , value_traits + , size_type + , constant_time_size + , linear + , cache_last + > list_type; + list_type testlist; + BOOST_TEST (testlist.empty()); + + testlist.push_back (values[0]); + BOOST_TEST (testlist.size() == 1); + BOOST_TEST (&testlist.front() == &values[0]); + BOOST_TEST (&testlist.back() == &values[0]); + testlist.push_back(values[1]); + BOOST_TEST(*testlist.previous(testlist.end()) == values[1]); + BOOST_TEST (&testlist.front() == &values[0]); + BOOST_TEST (&testlist.back() == &values[1]); +} + +//test: push_front, pop_front, front, size, empty: +template +void test_slist + ::test_back(std::vector&, detail::bool_) +{} + //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 +155,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist1, testlist2; testlist1.push_front (values[0]); @@ -123,9 +169,42 @@ void test_slist TEST_INTRUSIVE_SEQUENCE( init_values, testlist1.begin() ); } +//test: merge due to error in merge implementation: +template +void test_slist + ::test_remove_unique (std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef slist + < value_type + , value_traits + , size_type + , constant_time_size + , linear + , cache_last + > list_type; + { + list_type list(values.begin(), values.end()); + list.remove_if(is_even()); + int init_values [] = { 1, 3, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() ); + } + { + std::vector values2(values); + list_type list(values.begin(), values.end()); + list.insert_after(list.before_begin(), values2.begin(), values2.end()); + list.sort(); + int init_values [] = { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values, list.begin() ); + list.unique(); + int init_values2 [] = { 1, 2, 3, 4, 5 }; + TEST_INTRUSIVE_SEQUENCE( init_values2, list.begin() ); + } +} + //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 +213,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist (values.begin(), values.end()); @@ -145,13 +226,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 +241,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist; testlist.assign (&values[0] + 2, &values[0] + 5); @@ -189,8 +272,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 +282,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist; testlist.push_front (values[4]); @@ -232,8 +317,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 +327,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist; @@ -249,33 +336,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 +374,13 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > 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 +391,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 +419,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 +453,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist1 (&values[0], &values[0] + values.size()); @@ -349,9 +466,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 +477,8 @@ void test_slist , value_traits , size_type , constant_time_size + , linear + , cache_last > list_type; list_type testlist1 (&values[0], &values[0] + values.size()); BOOST_TEST (testlist1 == list_type::container_from_end_iterator(testlist1.end())); @@ -380,6 +500,8 @@ class test_main_template < value_type , typename value_type::slist_base_hook_t >::type + , false + , false >::test_all(data); test_slist < typename detail::get_member_value_traits < value_type @@ -388,8 +510,68 @@ class test_main_template , &value_type::slist_node_ > >::type + , false + , 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 + , false + >::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 + , false + >::test_all(data); + + //Now the same but caching the last node + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + , false + , 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 + , false + , true + >::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 + , 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 + , true + >::test_all(data); return 0; } }; @@ -409,6 +591,8 @@ class test_main_template < value_type , typename value_type::slist_base_hook_t >::type + , false + , false >::test_all(data); test_slist < typename detail::get_member_value_traits @@ -418,12 +602,16 @@ class test_main_template , &value_type::slist_node_ > >::type + , false + , false >::test_all(data); test_slist < typename detail::get_base_value_traits < value_type , typename value_type::slist_auto_base_hook_t >::type + , false + , false >::test_all(data); test_slist < typename detail::get_member_value_traits @@ -433,6 +621,66 @@ class test_main_template , &value_type::slist_auto_node_ > >::type + , false + , false + >::test_all(data); + + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + , true + , false + >::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 + , false + >::test_all(data); + + //Now cache last + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + , false + , 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 + , false + , true + >::test_all(data); + + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + , true + , 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 + , true >::test_all(data); return 0; } diff --git a/test/test_templates.hpp b/test/test_templates.hpp deleted file mode 100644 index 9374b5a..0000000 --- a/test/test_templates.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef BOOST_INTRUSIVE_TEST_TEST_TEMPLATES_HPP -#define BOOST_INTRUSIVE_TEST_TEST_TEMPLATES_HPP - -#include - -namespace boost { -namespace intrusive { -namespace test { - -template -void test_shift() -{ - typedef typename ValueTraits::value_type testvalue_t; - boost::test_tools::output_test_stream test_seq; - Container test_cont; - const int NumElem = 6; - - std::vector values(NumElem); - for(int i = 0; i < NumElem; ++i){ - values[i] = i+1; - } - - 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){ - test_cont.assign(values.begin(), values.end()); - test_cont.shift_forward(i); - for(int j = 0; j < num_values; ++j){ - expected_values[(j + num_values - i%num_values) % num_values] = (j + 1); - } - std::copy (test_cont.begin(), test_cont.end(), - std::ostream_iterator (test_seq)); - std::stringstream stream; - std::copy (expected_values.begin(), expected_values.end(), - std::ostream_iterator (stream)); - stream << std::ends; - BOOST_CHECK (test_seq.is_equal (stream.str().c_str())); - test_cont.clear(); - } - - //Shift backwards all possible positions - for(int i = 0; i < num_values*2; ++i){ - test_cont.assign(values.begin(), values.end()); - test_cont.shift_backwards(i); - for(int j = 0; j < num_values; ++j){ - expected_values[(j + i) % num_values] = (j + 1); - } - std::copy (test_cont.begin(), test_cont.end(), - std::ostream_iterator (test_seq)); - std::stringstream stream; - std::copy (expected_values.begin(), expected_values.end(), - std::ostream_iterator (stream)); - stream << std::ends; - BOOST_CHECK (test_seq.is_equal (stream.str().c_str())); - test_cont.clear(); - } -} - -} //namespace test { -} //namespace intrusive { -} //namespace boost { - -#endif //#ifndef BOOST_INTRUSIVE_TEST_TEST_TEMPLATES_HPP