commit fe23901b24d675621bae7d84c912993bba18187b Author: Ion GaztaÃąaga Date: Fri May 4 21:22:02 2007 +0000 First inclusion [SVN r37592] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/include/boost/intrusive/circular_list_algorithms.hpp b/include/boost/intrusive/circular_list_algorithms.hpp new file mode 100644 index 0000000..0351065 --- /dev/null +++ b/include/boost/intrusive/circular_list_algorithms.hpp @@ -0,0 +1,319 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_CIRCULAR_LIST_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! circular_list_algorithms provides basic algorithms to manipulate nodes +//! forming a circular doubly linked list. An empty circular list is formed by a node +//! whose pointers point to itself. +//! +//! circular_list_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 circular list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! Static functions: +//! +//! static node_ptr get_previous(const_node_ptr n); +//! +//! static void set_previous(node_ptr n, node_ptr prev); +//! +//! static node_ptr get_next(const_node_ptr n); +//! +//! static void set_next(node_ptr n, node_ptr next); +template +class circular_list_algorithms +{ + public: + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + + //! 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); + NodeTraits::set_previous(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 + //! 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 != this_node); + return result; + } + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Unlinks the node from the circular list. + //! + //! Complexity: Constant + //! + //! 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; + } + + //! Requires: b and e must be nodes of the same circular list or an empty range. + //! + //! Effects: Unlinks the node [b, e) from the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + 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); + } + } + + //! Requires: nxt_node must be a node of a circular list. + //! + //! Effects: Links this_node before nxt_node in the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void link_before(node_ptr nxt_node, node_ptr this_node) + { + node_ptr prev(NodeTraits::get_previous(nxt_node)); + NodeTraits::set_previous(this_node, prev); + NodeTraits::set_next(prev, this_node); + NodeTraits::set_previous(nxt_node, this_node); + NodeTraits::set_next(this_node, nxt_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 next(NodeTraits::get_next(prev_node)); + NodeTraits::set_previous(this_node, prev_node); + NodeTraits::set_next(this_node, next); + NodeTraits::set_previous(next, this_node); + NodeTraits::set_next(prev_node, this_node); + } + + //! Requires: this_node and other_node must be nodes inserted + //! in circular lists or be empty circular lists. + //! + //! Effects: Swaps the position of the nodes: this_node is inserted in + //! other_nodes position in the second circular list and the other_node is inserted + //! in this_node's position in the first circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void swap_nodes(node_ptr this_node, node_ptr other_node) + { + if (other_node == this_node) + return; + bool empty1 = unique(this_node); + bool empty2 = unique(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)); + node_ptr prev_other(NodeTraits::get_previous(other_node)); + + //Do the swap + NodeTraits::set_next(this_node, next_other); + NodeTraits::set_next(other_node, next_this); + + NodeTraits::set_previous(this_node, prev_other); + NodeTraits::set_previous(other_node, prev_this); + + if (empty2){ + init(this_node); + } + else{ + NodeTraits::set_next(prev_other, this_node); + NodeTraits::set_previous(next_other, this_node); + } + if (empty1){ + init(other_node); + } + else{ + NodeTraits::set_next(prev_this, other_node); + NodeTraits::set_previous(next_this, other_node); + } + } +/* + //Watanabe version + private: + static void swap_prev(node_ptr this_node, node_ptr other_node) + { + node_ptr temp(NodeTraits::get_previous(this_node)); + NodeTraits::set_previous(this_node, NodeTraits::get_previous(other_node)); + NodeTraits::set_previous(other_node, temp); + } + static void swap_next(node_ptr this_node, node_ptr other_node) + { + node_ptr temp(NodeTraits::get_next(this_node)); + NodeTraits::set_next(this_node, NodeTraits::get_next(other_node)); + NodeTraits::set_next(other_node, temp); + } + + public: + static void swap_nodes(node_ptr this_node, node_ptr 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)); + node_ptr prev_other(NodeTraits::get_previous(other_node)); + //these first two swaps must happen before the other two + swap_prev(next_this, next_other); + swap_next(prev_this, prev_other); + swap_next(this_node, other_node); + swap_prev(this_node, other_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 or may not be an iterator in + // [b, e). + //! + //! Effects: Removes the nodes from [b, e) range from their circular list and inserts + //! them before p in p's circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void transfer(node_ptr p, node_ptr b, node_ptr e) + { + 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)); + NodeTraits::set_next(prev_e, p); + NodeTraits::set_previous(p, prev_e); + NodeTraits::set_next(prev_b, e); + NodeTraits::set_previous(e, prev_b); + NodeTraits::set_next(prev_p, b); + NodeTraits::set_previous(b, prev_p); + } + } + + //! Requires: i must a node of a circular list + //! and p must be a node of a different circular list. + //! + //! Effects: Removes the node i from its circular list and inserts + //! it before p in p's circular list. + //! If p == i or p == NodeTraits::get_next(i), this function is a null operation. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void transfer(node_ptr p, node_ptr i) + { + node_ptr n(NodeTraits::get_next(i)); + if(n != p && i != p){ + node_ptr prev_p(NodeTraits::get_previous(p)); + node_ptr prev_i(NodeTraits::get_previous(i)); + NodeTraits::set_next(prev_p, i); + NodeTraits::set_previous(i, prev_p); + NodeTraits::set_next(i, p); + NodeTraits::set_previous(p, i); + NodeTraits::set_previous(n, prev_i); + NodeTraits::set_next(prev_i, n); + + } + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + static void reverse(node_ptr p) + { + node_ptr f(NodeTraits::get_next(p)); + node_ptr i(NodeTraits::get_next(f)), e(p); + + while(i != e) { + node_ptr n = i; + i = NodeTraits::get_next(i); + transfer(f, n, i); + f = n; + } + } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP diff --git a/include/boost/intrusive/circular_slist_algorithms.hpp b/include/boost/intrusive/circular_slist_algorithms.hpp new file mode 100644 index 0000000..7ae0d15 --- /dev/null +++ b/include/boost/intrusive/circular_slist_algorithms.hpp @@ -0,0 +1,291 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_CIRCULAR_SLIST_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! circular_slist_algorithms provides basic algorithms to manipulate nodes +//! 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 +//! information about the node to be manipulated. NodeTraits must support the +//! following interface: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the circular 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 circular_slist_algorithms +{ + public: + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + + //! 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 get_previous_node(this_node, this_node); } + + + //! Requires: this_node and prev_init_node must be in the same circular list. + //! + //! Effects: Returns the previous node of this_node in the circular list starting. + //! the search from prev_init_node. The first node checked for equality + //! is NodeTraits::get_next(prev_init_node). + //! + //! Complexity: Linear to the number of elements between prev_init_node and this_node. + //! + //! Throws: Nothing. + static node_ptr get_previous_node(node_ptr prev_init_node, node_ptr this_node) + { + node_ptr p = prev_init_node; + for( node_ptr p_next + ; this_node != (p_next = NodeTraits::get_next(p)) + ; p = p_next){ + //empty + } + return p; + } + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Returns the previous node of 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_previous_node(node_ptr this_node) + { return get_previous_previous_node(this_node, this_node); } + + //! Requires: this_node and prev_prev_init_node must be in the same circular list. + //! + //! Effects: Returns the previous node of the previous node of this_node in the + //! circular list starting. the search from prev_init_node. The first node checked + //! for equality is NodeTraits::get_next((NodeTraits::get_next(prev_prev_init_node)). + //! + //! Complexity: Linear to the number of elements in the circular list. + //! + //! Throws: Nothing. + static node_ptr get_previous_previous_node(node_ptr prev_prev_init_node, node_ptr this_node) + { + node_ptr p = prev_prev_init_node; + node_ptr p_next = NodeTraits::get_next(p); + node_ptr p_next_next = NodeTraits::get_next(p_next); + while (this_node != p_next_next){ + p = p_next; + p_next = p_next_next; + p_next_next = NodeTraits::get_next(p_next); + } + 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 + //! 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 != this_node); + 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. + //! + //! Effects: Unlinks the node from the circular list. + //! + //! Complexity: Linear to the number of elements in the circular list + //! + //! 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) + { + NodeTraits::set_next(this_node, NodeTraits::get_next(prev_node)); + NodeTraits::set_next(prev_node, this_node); + } + + //! Requires: nxt_node must be a node of a circular list. + //! + //! Effects: Links this_node before nxt_node in the circular list. + //! + //! Complexity: Linear to the number of elements in the circular list. + //! + //! Throws: Nothing. + static void link_before (node_ptr nxt_node, node_ptr this_node) + { 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. + //! + //! Effects: Swaps the position of the nodes: this_node is inserted in + //! other_nodes position in the second circular list and the other_node is inserted + //! in this_node's position in the first circular list. + //! + //! Complexity: Linear to number of elements of both lists + //! + //! Throws: Nothing. + static void swap_nodes(node_ptr this_node, node_ptr other_node) + { + if (other_node == this_node) + return; + bool empty1 = unique(this_node); + bool empty2 = unique(other_node); + node_ptr prev_this (get_previous_node(this_node)); + node_ptr prev_other(get_previous_node(other_node)); + + node_ptr this_next (NodeTraits::get_next(this_node)); + node_ptr other_next(NodeTraits::get_next(other_node)); + NodeTraits::set_next(this_node, other_next); + 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); + } + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear to the contained elements. + static void reverse(node_ptr p) + { + node_ptr i = NodeTraits::get_next(p), e(p); + for (;;) { + node_ptr nxt(NodeTraits::get_next(i)); + if (nxt == e) + break; + transfer_after(e, i, nxt); + } + } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP diff --git a/include/boost/intrusive/detail/config_begin.hpp b/include/boost/intrusive/detail/config_begin.hpp new file mode 100644 index 0000000..1ef01d3 --- /dev/null +++ b/include/boost/intrusive/detail/config_begin.hpp @@ -0,0 +1,48 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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. +// +///////////////////////////////////////////////////////////////////////////// +#include + +#ifdef BOOST_MSVC + #pragma warning (push) + // + //'function' : resolved overload was found by argument-dependent lookup + //A function found by argument-dependent lookup (Koenig lookup) was eventually + //chosen by overload resolution. + // + //In Visual C++ .NET and earlier compilers, a different function would have + //been called. To pick the original function, use an explicitly qualified name. + // + + //warning C4275: non dll-interface class 'x' used as base for + //dll-interface class 'Y' + #pragma warning (disable : 4275) + //warning C4251: 'x' : class 'y' needs to have dll-interface to + //be used by clients of class 'z' + #pragma warning (disable : 4251) + #pragma warning (disable : 4675) + #pragma warning (disable : 4996) + #pragma warning (disable : 4503) + #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4244) // possible loss of data + #pragma warning (disable : 4521) ////Disable "multiple copy constructors specified" + #pragma warning (disable : 4522) + #pragma warning (disable : 4146) + #pragma warning (disable : 4267) //conversion from 'X' to 'Y', possible loss of data +#endif + +#include +#include + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# pragma warn -8026 // shut up warning "cannot inline function because ..." +# pragma warn -8027 // shut up warning "cannot inline function because ..." +#endif diff --git a/include/boost/intrusive/detail/config_end.hpp b/include/boost/intrusive/detail/config_end.hpp new file mode 100644 index 0000000..376ea57 --- /dev/null +++ b/include/boost/intrusive/detail/config_end.hpp @@ -0,0 +1,22 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include + +#if defined _MSC_VER + #pragma warning (pop) +#endif + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# pragma warn .8026 +# pragma warn .8027 +#endif diff --git a/include/boost/intrusive/detail/ebo_holder.hpp b/include/boost/intrusive/detail/ebo_holder.hpp new file mode 100644 index 0000000..3239a27 --- /dev/null +++ b/include/boost/intrusive/detail/ebo_holder.hpp @@ -0,0 +1,71 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Joaquín M López Muņoz 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_DETAIL_EBO_HOLDER_HPP +#define BOOST_INTRUSIVE_DETAIL_EBO_HOLDER_HPP + +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +class ebo_holder_impl +{ + public: + ebo_holder_impl(){} + ebo_holder_impl(const T& t):t(t){} + + T& get(){return t;} + const T& get()const{return t;} + + private: + T t; +}; + +template +class ebo_holder_impl + : private T +{ + public: + ebo_holder_impl(){} + ebo_holder_impl(const T& t):T(t){} + + T& get(){return *this;} + const T& get()const{return *this;} +}; + +template +class ebo_holder + : public ebo_holder_impl::value> +{ + private: + typedef ebo_holder_impl::value> super; + + public: + ebo_holder(){} + ebo_holder(const T& t):super(t){} + + ebo_holder& operator=(const ebo_holder& x) + { + this->get()=x.get(); + return *this; + } +}; + + +} //namespace detail { +} //namespace intrusive { +} //namespace boost { + +#endif //#ifndef BOOST_INTRUSIVE_DETAIL_EBO_HOLDER_HPP diff --git a/include/boost/intrusive/detail/hashtable_node.hpp b/include/boost/intrusive/detail/hashtable_node.hpp new file mode 100644 index 0000000..c807454 --- /dev/null +++ b/include/boost/intrusive/detail/hashtable_node.hpp @@ -0,0 +1,205 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaïŋ―ga 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_HASHTABLE_NODE_HPP +#define BOOST_INTRUSIVE_HASHTABLE_NODE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +struct prime_list_holder +{ + static const std::size_t prime_list[]; + static const std::size_t prime_list_size; +}; + +template +const std::size_t prime_list_holder::prime_list[] = { + 53ul, 97ul, 193ul, 389ul, 769ul, + 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, + 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, + 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, + 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, + 1610612741ul, 3221225473ul, 4294967291ul }; + +template +const std::size_t prime_list_holder::prime_list_size + = sizeof(prime_list)/sizeof(std::size_t); + +template +struct bucket_type_impl + : public SlistImpl +{ + bucket_type_impl() + {} + + bucket_type_impl(const bucket_type_impl &) + {} + + bucket_type_impl &operator=(const bucket_type_impl&) + { SlistImpl::clear(); } + + static typename std::iterator_traits + ::difference_type + get_bucket_num + ( typename SlistImpl::const_iterator it + , const bucket_type_impl &first_bucket + , const bucket_type_impl &last_bucket) + { + typename SlistImpl::const_iterator + first(first_bucket.cend()), last(last_bucket.cend()); + + //The end node is embedded in the singly linked list: + //iterate until we reach it. + while(!(first.pointed_node() <= it.pointed_node() && + it.pointed_node() <= last.pointed_node())){ + ++it; + } + //Now get the bucket_type_impl from the iterator + const bucket_type_impl &b = static_cast + (SlistImpl::container_from_end_iterator(it)); + + //Now just calculate the index b has in the bucket array + return &b - &first_bucket; + } + + static SlistImpl &bucket_to_slist(bucket_type_impl &b) + { return static_cast(b); } + + static const SlistImpl &bucket_to_slist(const bucket_type_impl &b) + { return static_cast(b); } +}; + +template +struct bucket_info_impl +{ + typedef typename boost::pointer_to_other + < typename SlistImpl::pointer + , bucket_type_impl >::type bucket_ptr; + typedef typename SlistImpl::size_type size_type; + bucket_ptr buckets_; + size_type buckets_len_; +}; + +template +class hashtable_iterator + : public boost::iterator_facade + < hashtable_iterator + , Value + , boost::forward_traversal_tag + , Value& + , typename std::iterator_traits::difference_type + > +{ + typedef typename SlistImpl::iterator local_iterator; + typedef typename SlistImpl::const_iterator const_local_iterator; + typedef typename SlistImpl::value_traits::node_ptr node_ptr; + typedef typename SlistImpl::value_traits::const_node_ptr const_node_ptr; + + typedef bucket_type_impl bucket_type; + typedef typename boost::pointer_to_other + < typename SlistImpl::pointer, bucket_type>::type bucket_ptr; + typedef typename boost::pointer_to_other + < typename SlistImpl::pointer, const bucket_type>::type const_bucket_ptr; + typedef detail::bucket_info_impl bucket_info_t; + typedef typename boost::pointer_to_other + ::type bucket_info_ptr; + typedef typename boost::pointer_to_other + ::type const_bucket_info_ptr; + typedef typename SlistImpl::size_type size_type; + struct enabler {}; + + public: + hashtable_iterator () + {} + + explicit hashtable_iterator(local_iterator ptr, const_bucket_info_ptr bucket_info) + : local_it_ (ptr), bucket_info_ (bucket_info) + {} + + template + hashtable_iterator(hashtable_iterator const& other + ,typename boost::enable_if< + boost::is_convertible + , enabler + >::type = enabler() + ) + : local_it_(other.local_it_), bucket_info_(other.bucket_info_) + {} + + const local_iterator &local() const + { return local_it_; } + + const_node_ptr pointed_node() const + { return local_it_.pointed_node(); } + + const const_bucket_info_ptr &bucket_info() const + { return bucket_info_; } + + private: + friend class boost::iterator_core_access; + template friend class hashtable_iterator; + + template + bool equal(hashtable_iterator const& other) const + { return other.local() == local_it_; } + + void increment() + { + using boost::get_pointer; + size_type buckets_len = bucket_info_->buckets_len_; + const_bucket_ptr buckets = bucket_info_->buckets_; + const_local_iterator first = bucket_type::bucket_to_slist(buckets[0]).cend(); + const_local_iterator last = bucket_type::bucket_to_slist(buckets[buckets_len]).cend(); + + ++local_it_; + if(first.pointed_node() <= local_it_.pointed_node() && + local_it_.pointed_node() <= last.pointed_node()){ + size_type n_bucket = (size_type) + bucket_type::get_bucket_num(local_it_, buckets[0], buckets[buckets_len]); + do{ + if (++n_bucket == buckets_len){ + local_it_ = bucket_info_->buckets_->end(); + break; + } + local_it_ = bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).begin(); + } + while (local_it_ == bucket_type::bucket_to_slist(bucket_info_->buckets_[n_bucket]).end()); + } + } + + Value& dereference() const + { return *local_it_; } + + local_iterator local_it_; + const_bucket_info_ptr bucket_info_; +}; + +} //namespace detail { +} //namespace intrusive { +} //namespace boost { + +#endif diff --git a/include/boost/intrusive/detail/list_node.hpp b/include/boost/intrusive/detail/list_node.hpp new file mode 100644 index 0000000..7ddd474 --- /dev/null +++ b/include/boost/intrusive/detail/list_node.hpp @@ -0,0 +1,132 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_LIST_NODE_HPP +#define BOOST_INTRUSIVE_LIST_NODE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +// list_node_traits can be used with circular_list_algorithms and supplies +// a list_node holding the pointers needed for a double-linked list +// it is used by list_derived_node and list_member_node +template +struct list_node_traits +{ + struct node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + + struct node + { + node_ptr prev_, next_; + }; + + static node_ptr get_previous(const_node_ptr n) + { return n->prev_; } + + static void set_previous(node_ptr n, node_ptr prev) + { n->prev_ = prev; } + + static node_ptr get_next(const_node_ptr n) + { return n->next_; } + + static void set_next(node_ptr n, node_ptr next) + { n->next_ = next; } +}; + +// list_iterator provides some basic functions for a +// node oriented forward iterator: +template +class list_iterator + : public boost::iterator_facade + < list_iterator + , T + , boost::bidirectional_traversal_tag + , T& + , typename std::iterator_traits::difference_type + > +{ + typedef typename ValueTraits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + struct enabler{}; + + public: + typedef typename pointer_to_other::type pointer; + typedef typename std::iterator_traits::difference_type difference_type; + + list_iterator () + : node_ (0) + {} + + explicit list_iterator(node_ptr node) + : node_ (node) + {} + + template + list_iterator(list_iterator const& other + ,typename boost::enable_if< + boost::is_convertible + , enabler + >::type = enabler() + ) + : node_(other.pointed_node()) + {} + + const node_ptr &pointed_node() const + { return node_; } + + private: + friend class boost::iterator_core_access; + template friend class list_iterator; + + template + bool equal(list_iterator const& other) const + { return other.pointed_node() == node_; } + + void increment() + { node_ = node_traits::get_next(node_); } + + void decrement() + { node_ = node_traits::get_previous(node_); } + + T& dereference() const + { return *ValueTraits::to_value_ptr(node_); } + + node_ptr node_; +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_LIST_NODE_HPP diff --git a/include/boost/intrusive/detail/parent_from_member.hpp b/include/boost/intrusive/detail/parent_from_member.hpp new file mode 100644 index 0000000..93af87a --- /dev/null +++ b/include/boost/intrusive/detail/parent_from_member.hpp @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_PARENT_FROM_MEMBER_HPP +#define BOOST_INTRUSIVE_PARENT_FROM_MEMBER_HPP + +namespace boost { +namespace intrusive { +namespace detail { + +template +std::size_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member) +{ + //This works with gcc and msvc + return *(const std::size_t*)(const void*)&ptr_to_member; + //Other compilers might need other transformation, depending how a + //pointer to data member is implemented. +} + +template +Parent *parent_from_member(Member *member, const Member Parent::* ptr_to_member) +{ + return (Parent*)((char*)member - + offset_from_pointer_to_member(ptr_to_member)); +} + +template +const Parent *parent_from_member(const Member *member, const Member Parent::* ptr_to_member) +{ + return (const Parent*)((const char*)member - + offset_from_pointer_to_member(ptr_to_member)); +} + +} //namespace detail { +} //namespace intrusive { +} //namespace boost { + +#endif //#ifndef BOOST_INTRUSIVE_PARENT_FROM_MEMBER_HPP diff --git a/include/boost/intrusive/detail/pointer_to_other.hpp b/include/boost/intrusive/detail/pointer_to_other.hpp new file mode 100644 index 0000000..3d02450 --- /dev/null +++ b/include/boost/intrusive/detail/pointer_to_other.hpp @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 2006. 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_POINTER_TO_OTHER_HPP +#define BOOST_INTRUSIVE_POINTER_TO_OTHER_HPP + +#include +#include + +#if (BOOST_VERSION < 103400) + +#ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED +#define BOOST_POINTER_TO_OTHER_HPP_INCLUDED + +namespace boost { + +template + struct pointer_to_other; + +template class Sp> + struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> + struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template +struct pointer_to_other< T*, U > +{ + typedef U* type; +}; + +} // namespace boost + +#endif + +#else + +#include + +#endif //#ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED + +#include + +#endif //#ifndef BOOST_INTRUSIVE_POINTER_TO_OTHER_HPP diff --git a/include/boost/intrusive/detail/pointer_type.hpp b/include/boost/intrusive/detail/pointer_type.hpp new file mode 100644 index 0000000..80f73c6 --- /dev/null +++ b/include/boost/intrusive/detail/pointer_type.hpp @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 2006. 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_POINTER_TYPE_HPP +#define BOOST_INTRUSIVE_POINTER_TYPE_HPP + +#include + +namespace boost { +namespace intrusive { +namespace detail { + +struct two {char _[2];}; + +namespace pointer_type_imp +{ + +template static two test(...); +template static char test(typename U::pointer* = 0); + +} //namespace pointer_type_imp + +template +struct has_pointer_type +{ + static const bool value = sizeof(pointer_type_imp::test(0)) == 1; +}; + +template ::value> +struct pointer_type +{ + typedef typename A::pointer type; +}; + +template +struct pointer_type +{ + typedef T* type; +}; + +} //namespace detail +} //namespace intrusive +} // namespace boost + +#include + +#endif //#ifndef BOOST_INTRUSIVE_POINTER_TYPE_HPP diff --git a/include/boost/intrusive/detail/rbtree_node.hpp b/include/boost/intrusive/detail/rbtree_node.hpp new file mode 100644 index 0000000..c25fad9 --- /dev/null +++ b/include/boost/intrusive/detail/rbtree_node.hpp @@ -0,0 +1,257 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_RBTREE_NODE_HPP +#define BOOST_INTRUSIVE_RBTREE_NODE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +namespace detail { + +///////////////////////////////////////////////////////////////////////////// +// // +// Generic node_traits for any pointer type // +// // +///////////////////////////////////////////////////////////////////////////// + +//This is the compact representation: 3 pointers +template +struct compact_rbtree_node +{ + typedef typename pointer_to_other + >::type node_ptr; + enum color { red_t, black_t }; + node_ptr parent_, left_, right_; +}; + +//This is the normal representation: 3 pointers + enum +template +struct rbtree_node +{ + typedef typename pointer_to_other + >::type node_ptr; + + enum color { red_t, black_t }; + node_ptr parent_, left_, right_; + color color_; +}; + +//This is the default node traits implementation +//using a node with 3 generic pointers plus an enum +template +struct default_rbtree_node_traits_impl +{ + typedef rbtree_node node; + + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + + typedef typename node::color color; + + static node_ptr get_parent(const_node_ptr n) + { return n->parent_; } + + static void set_parent(node_ptr n, node_ptr p) + { n->parent_ = p; } + + static node_ptr get_left(const_node_ptr n) + { return n->left_; } + + static void set_left(node_ptr n, node_ptr l) + { n->left_ = l; } + + static node_ptr get_right(const_node_ptr n) + { return n->right_; } + + static void set_right(node_ptr n, node_ptr r) + { n->right_ = r; } + + static color get_color(const_node_ptr n) + { return n->color_; } + + static void set_color(node_ptr n, color c) + { n->color_ = c; } + + static color black() + { return node::black_t; } + + static color red() + { return node::red_t; } +}; + +//This is the compact node traits implementation +//using a node with 3 generic pointers +template +struct compact_rbtree_node_traits_impl +{ + typedef compact_rbtree_node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + + typedef pointer_plus_bit ptr_bit; + + typedef typename node::color color; + + static node_ptr get_parent(const_node_ptr n) + { return ptr_bit::get_pointer(n->parent_); } + + static void set_parent(node_ptr n, node_ptr p) + { ptr_bit::set_pointer(n->parent_, p); } + + static node_ptr get_left(const_node_ptr n) + { return n->left_; } + + static void set_left(node_ptr n, node_ptr l) + { n->left_ = l; } + + static node_ptr get_right(const_node_ptr n) + { return n->right_; } + + static void set_right(node_ptr n, node_ptr r) + { n->right_ = r; } + + static color get_color(const_node_ptr n) + { return (color)ptr_bit::get_bit(n->parent_); } + + static void set_color(node_ptr n, color c) + { ptr_bit::set_bit(n->parent_, c != 0); } + + static color black() + { return node::black_t; } + + static color red() + { return node::red_t; } +}; + +//Dispatches the implementation based on the boolean +template +struct rbtree_node_traits_dispatch + : public default_rbtree_node_traits_impl +{}; + +template +struct rbtree_node_traits_dispatch + : public compact_rbtree_node_traits_impl +{}; + +//Inherit from the dispatcher depending on the embedding capabilities +template +struct rbtree_node_traits + : public rbtree_node_traits_dispatch + + >::type + >::value + > +{}; + +///////////////////////////////////////////////////////////////////////////// +// // +// Implementation of the rbtree iterator // +// // +///////////////////////////////////////////////////////////////////////////// + +template +class rbtree_iterator + : public boost::iterator_facade + < rbtree_iterator + , T + , boost::bidirectional_traversal_tag + , T& + , typename std::iterator_traits::difference_type + > +{ + typedef typename ValueTraits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef rbtree_algorithms node_algorithms; + struct enabler{}; + + public: + typedef typename pointer_to_other::type pointer; + typedef typename std::iterator_traits::difference_type difference_type; + + rbtree_iterator () + : node_ (0) + {} + + explicit rbtree_iterator(node_ptr node) + : node_ (node) + {} + + template + rbtree_iterator(rbtree_iterator const& other + ,typename boost::enable_if< + boost::is_convertible + , enabler + >::type = enabler() + ) + : node_(other.pointed_node()) + {} + + const node_ptr &pointed_node() const + { return node_; } + + private: + friend class boost::iterator_core_access; + template friend class rbtree_iterator; + + template + bool equal(rbtree_iterator const& other) const + { return other.pointed_node() == node_; } + + void increment() + { node_ = node_algorithms::next_node(node_); } + + void decrement() + { node_ = node_algorithms::prev_node(node_); } + + T& dereference() const + { return *ValueTraits::to_value_ptr(node_); } + + node_ptr node_; +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_RBTREE_NODE_HPP diff --git a/include/boost/intrusive/detail/slist_node.hpp b/include/boost/intrusive/detail/slist_node.hpp new file mode 100644 index 0000000..f8b2089 --- /dev/null +++ b/include/boost/intrusive/detail/slist_node.hpp @@ -0,0 +1,125 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_SLIST_NODE_HPP +#define BOOST_INTRUSIVE_SLIST_NODE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +// slist_node_traits can be used with circular_slist_algorithms and supplies +// a slist_node holding the pointers needed for a singly-linked list +// it is used by slist_base_hook and slist_member_hook +template +struct slist_node_traits +{ + struct node; + + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + + struct node + { + node_ptr next_; + }; + + static node_ptr get_next(const_node_ptr n) + { return n->next_; } + + static void set_next(node_ptr n, node_ptr next) + { n->next_ = next; } +}; + + +// slist_iterator provides some basic functions for a +// node oriented forward iterator: +template +class slist_iterator + : public boost::iterator_facade + < slist_iterator + , T + , boost::forward_traversal_tag + , T& + , typename std::iterator_traits::difference_type + > +{ + typedef typename ValueTraits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + struct enabler{}; + + public: + typedef typename pointer_to_other::type pointer; + typedef typename std::iterator_traits::difference_type difference_type; + + slist_iterator () + : node_ (0) + {} + + explicit slist_iterator(node_ptr node) + : node_ (node) + {} + + template + slist_iterator(slist_iterator const& other + ,typename boost::enable_if< + boost::is_convertible + , enabler + >::type = enabler() + ) + : node_(other.pointed_node()) + {} + + const node_ptr &pointed_node() const + { return node_; } + + private: + friend class boost::iterator_core_access; + template friend class slist_iterator; + + template + bool equal(slist_iterator const& other) const + { return other.pointed_node() == node_; } + + void increment() + { node_ = node_traits::get_next(node_); } + + T& dereference() const + { return *ValueTraits::to_value_ptr(node_); } + + node_ptr node_; +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SLIST_NODE_HPP diff --git a/include/boost/intrusive/detail/utilities.hpp b/include/boost/intrusive/detail/utilities.hpp new file mode 100644 index 0000000..8fab221 --- /dev/null +++ b/include/boost/intrusive/detail/utilities.hpp @@ -0,0 +1,293 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_DETAIL_UTILITIES_HPP +#define BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +//This functor compares a stored value +//and the one passed as an argument +template +class equal_to_value +{ + ConstReference t_; + + public: + equal_to_value(ConstReference t) + : t_(t) + {} + + bool operator()(ConstReference t)const + { return t_ == t; } +}; + +class null_destroyer +{ + public: + template + void operator()(Pointer) + {} +}; + +template +struct size_holder +{ + enum { constant_time_size = ConstantSize }; + typedef SizeType size_type; + + SizeType get_size() const + { return size_; } + + void set_size(SizeType size) + { size_ = size; } + + void decrement() + { --size_; } + + void increment() + { ++size_; } + + SizeType size_; +}; + +template +struct size_holder +{ + enum { constant_time_size = false }; + typedef SizeType size_type; + + size_type get_size() const + { return 0; } + + void set_size(size_type) + {} + + void decrement() + {} + + void increment() + {} +}; + +template +struct derivation_value_traits +{ + public: + typedef typename DerivationHookType::node_traits node_traits; + typedef T value_type; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef typename boost::pointer_to_other::type pointer; + typedef typename boost::pointer_to_other::type const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + enum { linking_policy = DerivationHookType::linking_policy }; + + static node_ptr to_node_ptr(reference value) + { return static_cast(value).to_node_ptr(); } + + static const_node_ptr to_node_ptr(const_reference value) + { return static_cast(value).to_node_ptr(); } + + static pointer to_value_ptr(node_ptr n) + { + using boost::get_pointer; + return static_cast(get_pointer(DerivationHookType::to_hook_ptr(n))); + } + + static const_pointer to_value_ptr(const_node_ptr n) + { + using boost::get_pointer; + return static_cast(get_pointer(DerivationHookType::to_hook_ptr(n))); + } +}; + + +template +struct member_value_traits +{ + public: + typedef typename MemberHookType::node_traits node_traits; + typedef T value_type; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef typename boost::pointer_to_other::type pointer; + typedef typename boost::pointer_to_other::type const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + enum { linking_policy = MemberHookType::linking_policy }; + + public: + static node_ptr to_node_ptr(reference value) + { + MemberHookType* result = &(value.*P); + return result->to_node_ptr(); + } + + static const_node_ptr to_node_ptr(const_reference value) + { + const MemberHookType* result = &(value.*P); + return result->to_node_ptr(); + } + + //Now let's be nasty. A pointer to member is usually implemented + //as an offset from the start of the class. + //get the offset in bytes and go + //backwards from n to the value subtracting + //the needed bytes. + static pointer to_value_ptr(node_ptr n) + { + using boost::get_pointer; + return pointer(parent_from_member((MemberHookType*)get_pointer(n), P)); + } + + static const_pointer to_value_ptr(const_node_ptr n) + { + using boost::get_pointer; + const_pointer(parent_from_member((const MemberHookType*)get_pointer(n), P)); + } + + private: + //This function converts a pointer to data member into an offset. + //This function is not standard and it's compiler-dependent. + static std::size_t value_to_node_offset() + { + const MemberHookType T::* const p = P; + return *(const std::size_t*)(const void *)(&p); +// using boost::get_pointer; +// const typename node_traits::node *np = +// get_pointer((((const value_type *)get_pointer(n))->*P).to_node_ptr()); +// return ((const char*)np - (const char*)(const value_type *)get_pointer(n)); + } +}; + +template +struct key_node_ptr_compare + : private detail::ebo_holder +{ + typedef typename ValueTraits::node_ptr node_ptr; + typedef detail::ebo_holder base_t; + key_node_ptr_compare(KeyValueCompare kcomp) + : base_t(kcomp) + {} + + template + bool operator()(node_ptr node, const KeyType &key) const + { return base_t::get()(*ValueTraits::to_value_ptr(node), key); } + + template + bool operator()(const KeyType &key, node_ptr node) const + { return base_t::get()(key, *ValueTraits::to_value_ptr(node)); } + + bool operator()(node_ptr node1, node_ptr node2) const + { + return base_t::get() + (*ValueTraits::to_value_ptr(node1), *ValueTraits::to_value_ptr(node2)); + } +}; + + +template +struct value_to_node_cloner + : private detail::ebo_holder +{ + typedef typename ValueTraits::node_ptr node_ptr; + typedef detail::ebo_holder base_t; + + value_to_node_cloner(F f) + : base_t(f) + {} + + node_ptr operator()(node_ptr p) + { return ValueTraits::to_node_ptr(*base_t::get()(*ValueTraits::to_value_ptr(p))); } +}; + +template +struct value_to_node_destroyer + : private detail::ebo_holder +{ + typedef typename ValueTraits::node_ptr node_ptr; + typedef detail::ebo_holder base_t; + value_to_node_destroyer(F f) + : base_t(f) + {} + + void operator()(node_ptr p) + { base_t::get()(ValueTraits::to_value_ptr(p)); } +}; + +template +struct dispatcher +{}; + +template +void destructor_impl(Container &cont, dispatcher) +{ BOOST_ASSERT(!cont.is_linked()); } + +template +void destructor_impl(Container &cont, dispatcher) +{ cont.unlink(); } + +template +void destructor_impl(Container &cont, dispatcher) +{} + +template +struct node_plus_pred + : public ebo_holder + , public Node +{ + node_plus_pred() + {} + + node_plus_pred(const Node &x, const MaybeClass &y) + : Node(x), ebo_holder(y) {} + + node_plus_pred(const MaybeClass &y) + : ebo_holder(y) {} + + Node &first() + { return *this; } + const Node &first() const + { return *this; } + MaybeClass &second() + { return ebo_holder::get(); } + const MaybeClass &second() const + { return ebo_holder::get(); } + + static node_plus_pred *this_from_node(Node *n) + { return static_cast(n); } + + static node_plus_pred *this_from_node(const Node *n) + { return static_cast(n); } +}; + + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp new file mode 100644 index 0000000..412c961 --- /dev/null +++ b/include/boost/intrusive/hashtable.hpp @@ -0,0 +1,852 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_HASHTABLE_HPP +#define BOOST_INTRUSIVE_HASHTABLE_HPP + +#include +//std C++ +#include +#include +#include +#include +//boost +#include +#include +#include +#include +#include +//General intrusive utilities +#include +#include +#include +#include +#include +//Implementation utilities +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template hashtable is an intrusive hash table container, that +//! is used to construct intrusive unordered_set and unordered_multiset containers. The +//! no-throw guarantee holds only, if the Equal object and Hasher don't throw. +template< class ValueTraits + , class Hash //= boost::hash + , class Equal //= std::equal_to + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class hashtable + : private detail::size_holder +{ + /// @cond + private: + typedef slist slist_impl; + typedef hashtable this_type; + typedef typename ValueTraits::node_traits node_traits; + typedef detail::size_holder size_traits; + + //noncopyable + hashtable (const hashtable&); + hashtable operator =(const hashtable&); + /// @endcond + + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef value_type key_type; + typedef Hash hasher; + typedef Equal key_equal; + typedef detail::bucket_type_impl bucket_type; + typedef typename boost::pointer_to_other + ::type bucket_ptr; + typedef typename slist_impl::iterator local_iterator; + typedef typename slist_impl::const_iterator const_local_iterator; + + typedef detail::hashtable_iterator iterator; + typedef detail::hashtable_iterator const_iterator; + + /// @cond + private: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + + enum { safemode_or_autounlink = + (int)ValueTraits::linking_policy == (int)auto_unlink || + (int)ValueTraits::linking_policy == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink))); + + typedef detail::bucket_info_impl bucket_info_t; + typedef typename boost::pointer_to_other + ::type bucket_info_ptr; + typedef typename boost::pointer_to_other + ::type const_bucket_info_ptr; + + //User scattered boost::compressed pair to get EBO all compilers + boost::compressed_pair + + ,Equal> members_; + + const Equal &priv_equal() const + { return members_.second(); } + + Equal &priv_equal() + { return members_.second(); } + + const_bucket_info_ptr priv_bucket_info() const + { return &members_.first().first(); } + + bucket_info_ptr priv_bucket_info() + { return &members_.first().first(); } + + const Hash &priv_hasher() const + { return members_.first().second(); } + + Hash &priv_hasher() + { return members_.first().second(); } + + const bucket_ptr &priv_buckets() const + { return members_.first().first().buckets_; } + + bucket_ptr &priv_buckets() + { return members_.first().first().buckets_; } + + const size_type &priv_buckets_len() const + { return members_.first().first().buckets_len_; } + + size_type &priv_buckets_len() + { return members_.first().first().buckets_len_; } + + static node_ptr uncast(const_node_ptr ptr) + { + using boost::get_pointer; + return node_ptr(const_cast(get_pointer(ptr))); + } + + static bucket_info_ptr uncast(const_bucket_info_ptr ptr) + { + using boost::get_pointer; + return bucket_info_ptr(const_cast(get_pointer(ptr))); + } + + static slist_impl &bucket_to_slist(bucket_type &b) + { return static_cast(b); } + + static const slist_impl &bucket_to_slist(const bucket_type &b) + { return static_cast(b); } + + struct insert_commit_data_impl + { + size_type hash; + }; + /// @endcond + + public: + typedef insert_commit_data_impl insert_commit_data; + + hashtable( bucket_ptr buckets + , size_type buckets_len + , const Hash & hasher = Hash() + , const Equal &equal = Equal()) + : members_(boost::compressed_pair(hasher), equal) + { + + BOOST_ASSERT(buckets_len != 0); + priv_buckets() = buckets; + priv_buckets_len() = buckets_len; + priv_clear_buckets(); + size_traits::set_size(size_type(0)); + } + + ~hashtable() + { this->clear(); } + + iterator begin() + { + size_type bucket_num; + local_iterator local_it = priv_begin(bucket_num); + return iterator( local_it, this->priv_bucket_info()); + } + + const_iterator begin() const + { return cbegin(); } + + const_iterator cbegin() const + { + size_type bucket_num; + local_iterator local_it = priv_begin(bucket_num); + return const_iterator( local_it, this->priv_bucket_info()); + } + + iterator end() + { + using boost::get_pointer; + bucket_info_t *info = get_pointer(this->priv_bucket_info()); + return iterator(invalid_local_it(*info), 0); + } + + const_iterator end() const + { return cend(); } + + const_iterator cend() const + { + using boost::get_pointer; + const bucket_info_t *info = get_pointer(this->priv_bucket_info()); + return const_iterator(invalid_local_it(*info), 0); + } + + hasher hash_function() const + { return this->priv_hasher(); } + + key_equal key_eq() const + { return this->priv_equal(); } + + bool empty() const + { + if(ConstantTimeSize){ + return !size(); + } + else{ + using boost::get_pointer; + size_type buckets_len = this->priv_buckets_len(); + const bucket_type *b = get_pointer(this->priv_buckets()); + for (size_type n = 0; n < buckets_len; ++n, ++b){ + if(!b->empty()){ + return false; + } + } + return true; + } + } + + size_type size() const + { + if(ConstantTimeSize) + return size_traits::get_size(); + else{ + size_type len = 0; + using boost::get_pointer; + size_type buckets_len = this->priv_buckets_len(); + const bucket_type *b = get_pointer(this->priv_buckets()); + for (size_type n = 0; n < buckets_len; ++n, ++b){ + len += b->size(); + } + return len; + } + } + + void swap(hashtable& other) + { + using std::swap; + //These can throw + swap(this->priv_equal(), other.priv_equal()); + swap(this->priv_hasher(), other.priv_hasher()); + //These can't throw + swap(this->priv_buckets(), other.priv_buckets()); + swap(this->priv_buckets_len(), other.priv_buckets_len()); + if(ConstantTimeSize){ + size_type backup = size_traits::get_size(); + size_traits::set_size(other.get_size()); + other.set_size(backup); + } + } + + template + void clone_from(const hashtable &src, Cloner cloner, Destroyer destroyer) + { + this->clear_and_destroy(destroyer); + if(!ConstantTimeSize || !src.empty()){ + const size_type src_bucket_count = src.bucket_count(); + const size_type dst_bucket_count = this->bucket_count(); + + //If src bucket count is bigger or equal, structural copy is possible + if(src_bucket_count >= dst_bucket_count){ + //First clone the first ones + const bucket_ptr src_buckets = src.priv_buckets(); + const bucket_ptr dst_buckets = this->priv_buckets(); + size_type constructed; + try{ + for( constructed = 0 + ; constructed < dst_bucket_count + ; ++constructed){ + dst_buckets[constructed].clone_from(src_buckets[constructed], cloner, destroyer); + } + if(src_bucket_count != dst_bucket_count){ + //Now insert the remaining ones using the modulo trick + for(//"constructed" comes from the previous loop + ; constructed < src_bucket_count + ; ++constructed){ + bucket_type &dst_b = dst_buckets[constructed % dst_bucket_count]; + bucket_type &src_b = src_buckets[constructed]; + for( local_iterator b(src_b.begin()), e(src_b.end()) + ; b != e + ; ++b){ + dst_b.push_front(*cloner(*b)); + } + } + } + } + catch(...){ + while(constructed--){ + dst_buckets[constructed].clear_and_destroy(destroyer); + } + throw; + } + size_traits::set_size(src.get_size()); + } + else{ + //Unlike previous cloning algorithm, this can throw + //if cloner, the hasher or comparison functor throw + const_iterator b(src.begin()), e(src.end()); + try{ + for(; b != e; ++b){ + this->insert_equal(*cloner(*b)); + } + } + catch(...){ + this->clear_and_destroy(destroyer); + throw; + } + } + } + } + + iterator insert_equal(reference value) + { + size_type bucket_num, hash; + local_iterator it = priv_find(value, this->priv_hasher(), this->priv_equal(), bucket_num, hash); + bucket_type &b = this->priv_buckets()[bucket_num]; + if(it == invalid_local_it(*this->priv_bucket_info())){ + it = b.before_begin(); + } + size_traits::increment(); + return iterator(b.insert_after(it, value), this->priv_bucket_info()); + } + + template + void insert_equal(Iterator b, Iterator e) + { + for (; b != e; ++b) + this->insert_equal(*b); + } + + std::pair insert_unique(reference value) + { + insert_commit_data commit_data; + std::pair ret = insert_unique_check(value, commit_data); + if(!ret.second) + return ret; + return std::pair (insert_unique_commit(value, commit_data), true); + } + + template + void insert_unique(Iterator b, Iterator e) + { + for (; b != e; ++b) + this->insert_unique(*b); + } + + std::pair insert_unique_check + (const_reference value, insert_commit_data &commit_data) + { return insert_unique_check(value, this->priv_hasher(), this->priv_equal(), commit_data); } + + template + std::pair insert_unique_check + ( const KeyType &key + , KeyHasher hasher + , KeyValueEqual key_value_eq + , insert_commit_data &commit_data) + { + size_type bucket_num; + local_iterator prev_pos = + priv_find(key, hasher, key_value_eq, bucket_num, commit_data.hash); + bool success = prev_pos == invalid_local_it(*this->priv_bucket_info()); + if(success){ + prev_pos = this->priv_buckets()[bucket_num].before_begin(); + } + return std::pair + (iterator(prev_pos, this->priv_bucket_info()) + ,success); + } + + iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) + { + size_type bucket_num = commit_data.hash % this->priv_buckets_len(); + bucket_type &b = this->priv_buckets()[bucket_num]; + size_traits::increment(); + return iterator( b.insert_after(b.before_begin(), value) + , this->priv_bucket_info()); + } + + void erase(const_iterator i) + { erase_and_destroy(i, detail::null_destroyer()); } + + void erase(const_iterator b, const_iterator e) + { erase_and_destroy(b, e, detail::null_destroyer()); } + + size_type erase(const_reference value) + { return this->erase(value, this->priv_hasher(), this->priv_equal()); } + + template + size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) + { return erase_and_destroy(key, hasher, equal, detail::null_destroyer()); } + + template + void erase_and_destroy(const_iterator i, Destroyer destroyer) + { + local_iterator to_erase(i.local()); + bucket_ptr f(priv_buckets()), l(f + priv_buckets_len()); + bucket_type &b = this->priv_buckets()[bucket_type::get_bucket_num(to_erase, *f, *l)]; + b.erase_after_and_destroy(b.previous(to_erase), destroyer); + size_traits::decrement(); + } + + template + void erase_and_destroy(const_iterator b, const_iterator e, Destroyer destroyer) + { + if(b == e) return; + + //Get the bucket number and local iterator for both iterators + bucket_ptr f(priv_buckets()), l(f + priv_buckets_len()); + size_type first_bucket_num = bucket_type::get_bucket_num(b.local(), *f, *l); + + local_iterator before_first_local_it + = priv_buckets()[first_bucket_num].previous(b.local()); + size_type last_bucket_num; + local_iterator last_local_it; + + //For the end iterator, we will assign the end iterator + //of the last bucket + if(e == end()){ + last_bucket_num = this->bucket_count() - 1; + last_local_it = priv_buckets()[last_bucket_num].end(); + } + else{ + last_local_it = e.local(); + last_bucket_num = bucket_type::get_bucket_num(last_local_it, *f, *l); + } + + const bucket_ptr buckets = priv_buckets(); + //First erase the nodes of the first bucket + { + bucket_type &first_b = buckets[first_bucket_num]; + local_iterator nxt(before_first_local_it); ++nxt; + local_iterator end = first_b.end(); + while(nxt != end){ + nxt = first_b.erase_after_and_destroy(before_first_local_it, destroyer); + size_traits::decrement(); + } + } + + //Now fully clear the intermediate buckets + for(size_type i = first_bucket_num+1; i < last_bucket_num; ++i){ + bucket_type &b = buckets[i]; + if(b.empty()) + continue; + local_iterator b_begin(b.before_begin()); + local_iterator nxt(b_begin); ++nxt; + local_iterator end = b.end(); + while(nxt != end){ + nxt = b.erase_after_and_destroy(b_begin, destroyer); + size_traits::decrement(); + } + } + + //Now erase nodes from the last bucket + { + bucket_type &last_b = buckets[last_bucket_num]; + local_iterator b_begin(last_b.before_begin()); + local_iterator nxt(b_begin); ++nxt; + while(nxt != last_local_it){ + nxt = last_b.erase_after_and_destroy(b_begin, destroyer); + size_traits::decrement(); + } + } + } + + template + size_type erase_and_destroy(const_reference value, Destroyer destroyer) + { return erase_and_destroy(value, priv_hasher(), priv_equal(), destroyer); } + + template + size_type erase_and_destroy(const KeyType& key, KeyHasher hasher + ,KeyValueEqual equal, Destroyer destroyer) + { + size_type count(0); + + if(ConstantTimeSize && this->empty()){ + return 0; + } + + bucket_type &b = this->priv_buckets()[hasher(key) % this->priv_buckets_len()]; + local_iterator it = b.begin(); + local_iterator prev = b.before_begin(); + + bool found = false; + //Find equal value + while(it != b.end()){ + if(equal(key, *it)){ + found = true; + break; + } + ++prev; + ++it; + } + + if(!found) + return 0; + + //If found erase all equal values + for(local_iterator end = b.end(); it != end && equal(key, *it); ++count){ + it = b.erase_after_and_destroy(prev, destroyer); + size_traits::decrement(); + } + return count; + } + + void clear() + { + if(safemode_or_autounlink){ + priv_clear_buckets(); + } + size_traits::set_size(size_type(0)); + } + + template + void clear_and_destroy(Destroyer destroyer) + { + if(!ConstantTimeSize || !this->empty()){ + size_type num_buckets = this->bucket_count(); + bucket_ptr b = this->priv_buckets(); + for(; num_buckets--; ++b){ + b->clear_and_destroy(destroyer); + } + size_traits::set_size(size_type(0)); + } + } + + size_type count(const_reference value) const + { return this->count(value, this->priv_hasher(), this->priv_equal()); } + + template + size_type count(const KeyType &key, const KeyHasher &hasher, const KeyValueEqual &equal) const + { + size_type bucket_n1, bucket_n2, count; + priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count); + return count; + } + + iterator find(const_reference value) + { return find(value, this->priv_hasher(), this->priv_equal()); } + + template + iterator find(const KeyType &key, KeyHasher hasher, KeyValueEqual equal) + { + size_type bucket_n, hash; + local_iterator local_it = priv_find(key, hasher, equal, bucket_n, hash); + return iterator( local_it + , this->priv_bucket_info()); + } + + const_iterator find(const_reference value) const + { return find(value, this->priv_hasher(), this->priv_equal()); } + + template + const_iterator find + (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const + { + size_type bucket_n, hash; + local_iterator local_it = priv_find(key, hasher, equal, bucket_n, hash); + return const_iterator( local_it + , uncast(this->priv_bucket_info())); + } + + std::pair equal_range(const_reference value) + { return this->equal_range(value, this->priv_hasher(), this->priv_equal()); } + + template + std::pair equal_range + (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) + { + size_type bucket_n1, bucket_n2, count; + std::pair ret + = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count); + return std::pair + ( iterator( ret.first, this->priv_bucket_info() ) + , iterator( ret.second, this->priv_bucket_info()) ); + } + + std::pair + equal_range(const_reference value) const + { return this->equal_range(value, this->priv_hasher(), this->priv_equal()); } + + template + std::pair equal_range + (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const + { + size_type bucket_n1, bucket_n2, count; + std::pair ret + = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count); + return std::pair + ( const_iterator( ret.first, uncast(this->priv_bucket_info()) ) + , const_iterator( ret.second, uncast(this->priv_bucket_info()) ) ); + } + + size_type bucket_count() const + { return this->priv_buckets_len(); } + + size_type bucket_size(size_type n) const + { return this->priv_buckets()[n].size(); } + + size_type bucket(const key_type& k) const + { return this->bucket(k, this->priv_hasher()); } + + template + size_type bucket(const KeyType& k, const KeyHasher &hasher) const + { return hasher(k) % this->priv_buckets_len(); } + + bucket_ptr bucket_pointer() const + { return this->priv_buckets(); } + + local_iterator begin(size_type n) + { return this->priv_buckets()[n].begin(); } + + const_local_iterator begin(size_type n) const + { return this->cbegin(n); } + + const_local_iterator cbegin(size_type n) const + { return const_cast(this->priv_buckets()[n]).begin(); } + + local_iterator end(size_type n) + { return this->priv_buckets()[n].end(); } + + const_local_iterator end(size_type n) const + { return this->cend(n); } + + const_local_iterator cend(size_type n) const + { return const_cast(this->priv_buckets()[n]).end(); } + + void rehash(bucket_ptr new_buckets, size_type new_buckets_len) + { + bucket_ptr old_buckets = this->priv_buckets(); + size_type old_buckets_len = this->priv_buckets_len(); + + try{ + size_type n = 0; + bool same_buffer = old_buckets == new_buckets; + //If we are shrinking the bucket array, just rehash the last nodes + if(same_buffer && (old_buckets_len > new_buckets_len)){ + n = new_buckets_len; + } + + //Iterate through nodes + for(; n < old_buckets_len; ++n){ + bucket_type &old_bucket = old_buckets[n]; + local_iterator before_i(old_bucket.before_begin()); + local_iterator end(old_bucket.end()); + local_iterator i(old_bucket.begin()); + for(;i != end; ++i){ + size_type new_n = this->priv_hasher()(*i) % new_buckets_len; + //If this is a buffer expansion don't move if it's not necessary + if(same_buffer && new_n == n){ + ++before_i; + } + else{ + bucket_type &new_b = new_buckets[new_n]; + new_b.splice_after(new_b.before_begin(), old_bucket, before_i); + i = before_i; + } + } + } + + this->priv_buckets() = new_buckets; + this->priv_buckets_len() = new_buckets_len; + } + catch(...){ + for(size_type n = 0; n < new_buckets_len; ++n){ + new_buckets[n].clear(); + old_buckets[n].clear(); + } + size_traits::set_size(size_type(0)); + throw; + } + } + + iterator iterator_to(reference value) + { + return iterator( bucket_type::iterator_to(value) + , this->priv_bucket_info()); + } + + const_iterator iterator_to(const_reference value) const + { + return const_iterator( bucket_type::iterator_to(const_cast(value)) + , uncast(this->priv_bucket_info())); + } + + static local_iterator local_iterator_to(reference value) + { return bucket_type::iterator_to(value); } + + static const_local_iterator local_iterator_to(const_reference value) + { return bucket_type::iterator_to(value); } + + // no throw + static size_type suggested_upper_bucket_count(size_type n) + { + const std::size_t *primes = &detail::prime_list_holder<0>::prime_list[0]; + const std::size_t *primes_end = primes + detail::prime_list_holder<0>::prime_list_size; + size_type const* bound = + std::lower_bound(primes, primes_end, n); + if(bound == primes_end) + bound--; + return size_type(*bound); + } + + // no throw + static size_type suggested_lower_bucket_count(size_type n) + { + const std::size_t *primes = &detail::prime_list_holder<0>::prime_list[0]; + const std::size_t *primes_end = primes + detail::prime_list_holder<0>::prime_list_size; + size_type const* bound = + std::upper_bound(primes, primes_end, n); + if(bound != primes_end) + bound--; + return size_type(*bound); + } + + /// @cond + private: + static local_iterator invalid_local_it(const bucket_info_t &b) + { return b.buckets_->end(); } + + local_iterator priv_begin(size_type &bucket_num) const + { + size_type buckets_len = this->priv_buckets_len(); + for (bucket_num = 0; bucket_num < buckets_len; ++bucket_num){ + bucket_type &b = this->priv_buckets()[bucket_num]; + if(!b.empty()) + return b.begin(); + } + return invalid_local_it(*this->priv_bucket_info()); + } + + void priv_clear_buckets() + { priv_clear_buckets(this->priv_buckets(), this->priv_buckets_len()); } + + static void priv_clear_buckets(bucket_ptr buckets_ptr, size_type buckets_len) + { + for(; buckets_len--; ++buckets_ptr){ + buckets_ptr->clear(); + } + } + + template + local_iterator priv_find + ( const KeyType &key, KeyHasher hasher + , KeyValueEqual equal, size_type &bucket_number, size_type &hash) const + { + size_type b_len(this->priv_buckets_len()); + hash = hasher(key); + bucket_number = hash % b_len; + + if(ConstantTimeSize && this->empty()){ + return invalid_local_it(*this->priv_bucket_info()); + } + + bucket_type &b = this->priv_buckets()[bucket_number]; + local_iterator it = b.begin(); + + while(it != b.end()){ + if(equal(key, *it)){ + return it; + } + ++it; + } + + return invalid_local_it(*this->priv_bucket_info()); + } + + template + std::pair priv_equal_range + ( const KeyType &key + , KeyHasher hasher + , KeyValueEqual equal + , size_type &bucket_number_first + , size_type &bucket_number_second + , size_type &count) const + { + size_type hash; + count = 0; + //Let's see if the element is present + std::pair to_return + ( priv_find(key, hasher, equal, bucket_number_first, hash) + , invalid_local_it(*this->priv_bucket_info())); + if(to_return.first == to_return.second){ + bucket_number_second = bucket_number_first; + return to_return; + } + ++count; + //If it's present, find the first that it's not equal in + //the same bucket + bucket_type &b = this->priv_buckets()[bucket_number_first]; + local_iterator it = to_return.first; + ++it; + + while(it != b.end()){ + if(!equal(key, *it)){ + to_return.second = it; + bucket_number_second = bucket_number_first; + return to_return; + } + ++it; + ++count; + } + + //If we reached the end, find the first, non-empty bucket + for(bucket_number_second = bucket_number_first+1 + ; bucket_number_second != this->priv_buckets_len() + ; ++bucket_number_second){ + bucket_type &b = this->priv_buckets()[bucket_number_second]; + if(!b.empty()){ + to_return.second = b.begin(); + return to_return; + } + } + + //Otherwise, return the end node + to_return.second = invalid_local_it(*this->priv_bucket_info()); + return to_return; + } + /// @endcond +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_HASHTABLE_HPP diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp new file mode 100644 index 0000000..c7cc71a --- /dev/null +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -0,0 +1,154 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_FWD_HPP +#define BOOST_INTRUSIVE_FWD_HPP + +#include +#include +#include +#include + +//std predeclarations +namespace std{ + +template +struct equal_to; + +template +struct less; + +} //namespace std{ + +namespace boost { +namespace intrusive { + +//////////////////////////// +// Node algorithms +//////////////////////////// + +//Algorithms predeclarations +template +class circular_list_algorithms; + +template +class circular_slist_algorithms; + +template +class rbtree_algorithms; + +//////////////////////////// +// Containers +//////////////////////////// + +//slist +template < class ValueTraits + , bool ConstantTimeSize = true + , class SizeType = std::size_t> +class slist; + +template< class Tag = tag + , linking_policy Policy = safe_link + , class VoidPointer = void * + > +class slist_base_hook; + +template< linking_policy Policy = safe_link + , class VoidPointer = void *> +class slist_member_hook; + +//list +template< class ValueTraits + , bool ConstantTimeSize = true + , class SizeType = std::size_t> +class list; + +template< class Tag = tag + , linking_policy Policy = safe_link + , class VoidPointer = void * + > +class list_base_hook; + +template< linking_policy Policy = safe_link + , class VoidPointer = void *> +class list_member_hook; + +//hash/unordered +template< class ValueTraits + , class Hash = boost::hash + , class Equal = std::equal_to + , bool ConstantTimeSize = true + , class SizeType = std::size_t + > +class hashtable; + +template< class ValueTraits + , class Hash = boost::hash + , class Equal = std::equal_to + , bool ConstantTimeSize = true + , class SizeType = std::size_t + > +class unordered_set; + +template< class ValueTraits + , class Hash = boost::hash + , class Equal = std::equal_to + , bool ConstantTimeSize = true + , class SizeType = std::size_t + > +class unordered_multiset; + +template< class Tag = tag + , linking_policy Policy = safe_link + , class VoidPointer = void * + > +class unordered_set_base_hook; + +template< linking_policy Policy = safe_link + , class VoidPointer = void *> +class unordered_set_member_hook; + + +//rbtree/set +template < class ValueTraits + , class Compare = std::less + , bool ConstantTimeSize = true + , class SizeType = std::size_t + > +class rbtree; + +template < class ValueTraits + , class Compare = std::less + , bool ConstantTimeSize = true + , class SizeType = std::size_t> +class set; + +template < class ValueTraits + , class Compare = std::less + , bool ConstantTimeSize = true + , class SizeType = std::size_t> +class multiset; + +template< class Tag = tag + , linking_policy Policy = safe_link + , class VoidPointer = void * + > +class set_base_hook; + +template< linking_policy Policy = safe_link + , class VoidPointer = void *> +class set_member_hook; + +} //namespace intrusive { +} //namespace boost { + +#endif //#ifndef BOOST_INTRUSIVE_FWD_HPP diff --git a/include/boost/intrusive/linking_policy.hpp b/include/boost/intrusive/linking_policy.hpp new file mode 100644 index 0000000..75d46fa --- /dev/null +++ b/include/boost/intrusive/linking_policy.hpp @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_VALUE_LINKING_POLICY_HPP +#define BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP + +namespace boost { +namespace intrusive { + +//!This enumeration defines the type of value_traits that can be defined +//!for Boost.Intrusive containers +enum linking_policy{ + //!If this linking policy is specified in a value_traits class + //!as the linking_policy, containers + //!configured with such value_traits won't set the hooks + //!of the erased values to a default state. Containers also won't + //!check that the hooks of the new values are default initialized. + normal_link, + + //!If this linking policy is specified in a value_traits class + //!as the linking_policy, containers + //!configured with such value_traits will set the hooks + //!of the erased values to a default state. Containers also will + //!check that the hooks of the new values are default initialized. + safe_link, + + //!Same as "safe_link" but the user type is an auto-unlink + //!type, so the containers with constant-time size features won't be + //!compatible with value_traits configured with this policy. + //!Containers also know that the a value can be silently erased from + //!the container without using any function provided by the containers. + auto_unlink +}; +} //namespace intrusive +} //namespace boost + +#endif //BOOST_INTRUSIVE_VALUE_LINKING_POLICY_HPP diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp new file mode 100644 index 0000000..d46c793 --- /dev/null +++ b/include/boost/intrusive/list.hpp @@ -0,0 +1,1214 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_LIST_HPP +#define BOOST_INTRUSIVE_LIST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template list is an intrusive container that mimics most of the +//! interface of std::list as described in the C++ standard. +//! +//! The template parameter ValueTraits is called "value traits". It stores +//! information and operations about the type to be stored in the container. +//! +//! If the user specifies ConstantTimeSize as "true", a member of type SizeType +//! will be embedded in the class, that will keep track of the number of stored objects. +//! This will allow constant-time O(1) size() member, instead of default O(N) size. +template< class ValueTraits + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class list + : private detail::size_holder + , private ValueTraits::node_traits::node +{ + /// @cond + private: + typedef list this_type; + typedef typename ValueTraits::node_traits node_traits; + typedef detail::size_holder size_traits; + + //! This class is + //! non-copyable + list (const list&); + + //! This class is + //! non-assignable + list &operator =(const list&); + /// @endcond + + //Public typedefs + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef detail::list_iterator iterator; + typedef detail::list_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + /// @cond + private: + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef circular_list_algorithms node_algorithms; + enum { safemode_or_autounlink = + (int)ValueTraits::linking_policy == (int)auto_unlink || + (int)ValueTraits::linking_policy == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink))); + + //Const cast emulation for smart pointers + static node_ptr uncast(const_node_ptr ptr) + { + using boost::get_pointer; + return node_ptr(const_cast(get_pointer(ptr))); + } + + node_ptr get_root_node() + { return node_ptr(&static_cast(*this)); } + + const_node_ptr get_root_node() const + { return const_node_ptr(&static_cast(*this)); } + /// @endcond + + public: + //! Effects: constructs an empty list. + //! + //! Complexity: Constant + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). + list() + { + size_traits::set_size(size_type(0)); + node_algorithms::init(get_root_node()); + } + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! + //! Effects: Constructs a list equal to the range [first,last). + //! + //! Complexity: Linear in std::distance(b, e). No copy constructors are called. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). + template + list(Iterator b, Iterator e) + { + size_traits::set_size(size_type(0)); + node_algorithms::init(get_root_node()); + this->insert(this->end(), b, e); + } + + //! Effects: If it's not a safe-mode or an auto-unlink value_type + //! the destructor does nothing + //! (ie. no code is generated). Otherwise it detaches all elements from this. + //! In this case the objects in the list are not deleted (i.e. no destructors + //! are called), but the hooks according to the ValueTraits template parameter + //! are set to their default value. + //! + //! Complexity: Linear to the number of elements in the list, if + //! it's a safe-mode or auto-unlink value . Otherwise constant. + ~list() + { + if(safemode_or_autounlink){ + this->clear(); + } + } + + //! 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. + void push_back(reference value) + { + node_ptr to_insert = ValueTraits::to_node_ptr(value); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + node_algorithms::link_before(get_root_node(), to_insert); + size_traits::increment(); + } + + //! Requires: value must be an lvalue. + //! + //! Effects: Inserts the value in the front of the list. + //! No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + void push_front(reference value) + { + node_ptr to_insert = ValueTraits::to_node_ptr(value); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + node_algorithms::link_before(node_traits::get_next(get_root_node()), to_insert); + size_traits::increment(); + } + + //! Effects: Erases the last element of the list. + //! No destructors are called. + //! + //! Throws: Nothing. + //! + //! 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(get_root_node()); + node_algorithms::unlink(to_erase); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the last element of the list. + //! No destructors are called. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators to the erased element. + template + void pop_back_and_destroy(Destroyer destroyer) + { + node_ptr to_erase = node_traits::get_previous(get_root_node()); + node_algorithms::unlink(to_erase); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + destroyer(ValueTraits::to_value_ptr(to_erase)); + } + + //! Effects: Erases the first element of the list. + //! No destructors are called. + //! + //! Throws: Nothing. + //! + //! 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(get_root_node()); + node_algorithms::unlink(to_erase); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the first element of the list. + //! No destructors are called. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators to the erased element. + template + void pop_front_and_destroy(Destroyer destroyer) + { + node_ptr to_erase = node_traits::get_next(get_root_node()); + node_algorithms::unlink(to_erase); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + destroyer(ValueTraits::to_value_ptr(to_erase)); + } + + //! Effects: Returns a reference to the first element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *ValueTraits::to_value_ptr(node_traits::get_next(get_root_node())); } + + //! Effects: Returns a const_reference to the first element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(get_root_node()))); } + + //! Effects: Returns a reference to the last element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return *ValueTraits::to_value_ptr(node_traits::get_previous(get_root_node())); } + + //! Effects: Returns a const_reference to the last element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const + { return *ValueTraits::to_value_ptr(uncast(node_traits::get_previous(get_root_node()))); } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(node_traits::get_next(get_root_node())); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return cbegin(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(node_traits::get_next(get_root_node())); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(get_root_node()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return cend(); } + + //! Effects: Returns a constant iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(uncast(get_root_node())); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(end()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return crend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(begin()); } + + //! Precondition: end_iterator must be a valid end iterator + //! of list. + //! + //! Effects: Returns a const reference to the list associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static list &container_from_end_iterator(iterator end_iterator) + { return static_cast(*end_iterator.pointed_node()); } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of list. + //! + //! Effects: Returns a const reference to the list associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const list &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(*end_iterator.pointed_node()); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements contained in the list. + //! if ConstantTimeSize is false. Constant time otherwise. + //! + //! Note: Does not affect the validity of iterators and references. + size_type size() const + { + if(ConstantTimeSize) + return size_traits::get_size(); + else + return node_algorithms::count(get_root_node()) - 1; + } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + bool empty() const + { return node_algorithms::unique(get_root_node()); } + + //! Effects: Swaps the elements of x and *this. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + void swap(list& other) + { + node_algorithms::swap_nodes(get_root_node(), other.get_root_node()); + if(ConstantTimeSize){ + size_type backup = size_traits::get_size(); + size_traits::set_size(other.get_size()); + other.set_size(backup); + } + } + + //! Effects: Moves backwards all the elements, so that the first + //! element becomes the second, the second becomes the third... + //! the last element becomes the first one. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of shifts. + //! + //! 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 = 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); + } + + //! Effects: Moves forward all the elements, so that the second + //! element becomes the first, the third becomes the second... + //! the first element becomes the last one. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of shifts. + //! + //! 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 = 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); + } + + //! Effects: Erases the element pointed by i of the list. + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed element, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! 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); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + return i; + } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the element range pointed by b and e + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements erased if it's a safe-mode + //! or auto-unlink value. Constant time otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased elements. + iterator erase(iterator b, iterator e) + { + if(safemode_or_autounlink || ConstantTimeSize){ + while(b != e){ + b = this->erase(b); + } + return b; + } + else{ + node_algorithms::unlink(b.pointed_node(), e.pointed_node()); + return e; + } + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed by i of the list. + //! No destructors are called. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Returns: the first element remaining beyond the removed element, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators to the erased element. + template + iterator erase_and_destroy(iterator i, Destroyer destroyer) + { + iterator erase = i; + ++i; + node_ptr to_erase = erase.pointed_node(); + node_algorithms::unlink(to_erase); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + destroyer(ValueTraits::to_value_ptr(to_erase)); + return i; + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element range pointed by b and e + //! No destructors are called. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements erased. + //! + //! Note: Invalidates the iterators to the erased elements. + template + iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer) + { + while(b != e){ + b = this->erase_and_destroy(b, destroyer); + } + return b; + } + + //! Effects: Erases all the elements of the container. + //! No destructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of the list. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the erased elements. + void clear() + { + if(safemode_or_autounlink){ + this->erase(this->begin(), this->end()); + } + else{ + node_algorithms::init(get_root_node()); + size_traits::set_size(size_type(0)); + } + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! No destructors are called. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of the list. + //! + //! Note: Invalidates the iterators to the erased elements. + template + void clear_and_destroy(Destroyer destroyer) + { this->erase_and_destroy(this->begin(), this->end(), destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Destroyer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. + //! + //! If cloner throws, all cloned elements are unlinked and destroyed + //! calling Destroyer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. Basic guarantee. + template + void clone_from(const list &src, Cloner cloner, Destroyer destroyer) + { + this->clear_and_destroy(destroyer); + try{ + const_iterator b(src.begin()), e(src.end()); + for(; b != e; ++b){ + this->push_back(*cloner(*b)); + } + } + catch(...){ + clear_and_destroy(destroyer); + throw; + } + } + + //! Requires: value must be an lvalue and p must be a valid iterator of *this. + //! + //! Effects: Inserts the value before the position pointed by p. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. No copy constructors are called. + //! + //! Note: Does not affect the validity of iterators and references. + iterator insert(iterator p, reference value) + { + node_ptr to_insert = ValueTraits::to_node_ptr(value); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + node_algorithms::link_before(p.pointed_node(), to_insert); + size_traits::increment(); + return iterator(to_insert); + } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type and p must be a valid iterator of *this. + //! + //! Effects: Inserts the range pointed by b and e before the position p. + //! No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted. + //! + //! Note: Does not affect the validity of iterators and references. + template + void insert(iterator p, Iterator b, Iterator e) + { + for (; b != e; ++b) + this->insert(p, *b); + } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type. + //! + //! Effects: Clears the list and inserts the range pointed by b and e. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus + //! linear to the elements contained in the list if it's a safe-mode + //! or auto-unlink value. + //! Linear to the number of elements inserted in the list otherwise. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. + template + void assign(Iterator b, Iterator e) + { + this->clear(); + this->insert(this->end(), b, e); + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type. + //! + //! Effects: Clears the list and inserts the range pointed by b and e. + //! No destructors or copy constructors are called. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus + //! linear to the elements contained in the list. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. + template + void destroy_and_assign(Destroyer destroyer, Iterator b, Iterator e) + { + this->clear(destroyer); + this->insert(this->end(), b, e); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! 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 p, list& x) + { + if(!x.empty()){ + node_algorithms::transfer + (p.pointed_node(), x.begin().pointed_node(), x.end().pointed_node()); + size_traits::set_size(size_traits::get_size() + x.get_size()); + x.set_size(size_type(0)); + } + } + + //! Requires: p must be a valid iterator of *this. + //! new_ele must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by new_ele, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == new_ele or p == ++new_ele, this function is a null operation. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! 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 p, list&x, iterator new_ele) + { + node_algorithms::transfer(p.pointed_node(), new_ele.pointed_node()); + x.decrement(); + size_traits::increment(); + } + + //! Requires: p must be a valid iterator of *this. + //! start and end must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by start and end from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements transferred + //! if ConstantTimeSize is true. Constant-time otherwise. + //! + //! 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 p, list&x, iterator start, iterator end) + { + if(start != end){ + if(ConstantTimeSize){ + size_type increment = std::distance(start, end); + node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); + size_traits::set_size(size_traits::get_size() + increment); + x.set_size(x.get_size() - increment); + } + else{ + node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); + } + } + } + + //! Requires: p must be a valid iterator of *this. + //! start and end must point to elements contained in list x. + //! n == std::distance(start, end) + //! + //! Effects: Transfers the range pointed by start and end from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! 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 p, list&x, iterator start, iterator end, difference_type n) + { + if(n){ + if(ConstantTimeSize){ + BOOST_ASSERT(n == std::distance(start, end)); + node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); + size_traits::set_size(size_traits::get_size() + n); + x.set_size(x.get_size() - n); + } + else{ + node_algorithms::transfer(p.pointed_node(), start.pointed_node(), end.pointed_node()); + } + } + } + + //! 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. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or std::less throws. Basic guarantee. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + void sort() + { sort(std::less()); } + + //! Requires: p must be a comparison function that induces a strict weak ordering + //! + //! Effects: This function sorts the list *this according to p. The sort is + //! stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the predicate throws. Basic guarantee. + //! + //! Notes: This won't throw if list_base_hook<>::value_traits or + //! list_member_hook::::value_traits are used as value traits. + //! Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + template + void sort(Predicate p) + { + if(node_traits::get_next(get_root_node()) + != node_traits::get_previous(get_root_node())){ + list carry; + list counter[64]; + int fill = 0; + while(!this->empty()){ + carry.splice(carry.begin(), *this, this->begin()); + int i = 0; + while(i < fill && !counter[i].empty()) { + carry.merge(counter[i++], p); + } + carry.swap(counter[i]); + if(i == fill) + ++fill; + } + for (int i = 1; i < fill; ++i) + counter[i].merge(counter[i-1], p); + this->swap(counter[fill-1]); + } + } + + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: If std::less throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated + void merge(list& x) + { 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 + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: If the predicate throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated. + template + void merge(list& x, Predicate p) + { + iterator e = this->end(); + iterator bx = x.begin(); + iterator ex = x.end(); + + for (iterator b = this->begin(); b != e; ++b) { + size_type n(0); + iterator ix(bx); + while(ix != ex && p(*ix, *b)){ + ++ix; ++n; + } + this->splice(b, x, bx, ix, n); + bx = ix; + } + //Now transfer the rest at the end of the container + this->splice(e, x); + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { node_algorithms::reverse(get_root_node()); } + + //! Effects: Removes all the elements that compare equal to value. + //! No destructors are called. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! 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)); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes all the elements that compare equal to value. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_and_destroy(const_reference value, Destroyer destroyer) + { remove_and_destroy_if(detail::equal_to_value(value), destroyer); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. No destructors are called. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { remove_and_destroy_if(pred, detail::null_destroyer()); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_and_destroy_if(Pred pred, Destroyer destroyer) + { + iterator first = begin(); + iterator last = end(); + while(first != last) { + iterator next = first; + ++next; + if(pred(*first)){ + pointer p = first.operator->(); + this->erase(first); + destroyer(p); + } + first = next; + } + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. No destructors are called. + //! + //! Throws: If std::equal_toComplexity: Linear time (size()-1 comparisons calls to pred()). + //! + //! 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_destroy(std::equal_to(), detail::null_destroyer()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! No destructors are called. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1 comparisons equality comparisons). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(BinaryPredicate pred) + { unique_and_destroy(pred, detail::null_destroyer()); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If std::equal_toComplexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique_and_destroy(Destroyer destroyer) + { unique_and_destroy(std::equal_to(), destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique_and_destroy(BinaryPredicate pred, Destroyer destroyer) + { + if(!this->empty()){ + iterator first = begin(); + iterator after = first; + ++after; + while(after != this->end()){ + if(pred(*first, *after)){ + pointer p = after.operator->(); + after = erase(after); + destroyer(p); + } + else{ + first = after++; + } + } + } + } + + //! Requires: value must be a reference to a value inserted in a list. + //! + //! Effects: This function returns a const_iterator pointing to the element + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + static iterator iterator_to(reference value) + { + BOOST_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(value))); + return iterator(ValueTraits::to_node_ptr(value)); + } + + //! Requires: value must be a const reference to a value inserted in a list. + //! + //! Effects: This function returns an iterator pointing to the element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + static const_iterator iterator_to(const_reference value) + { + BOOST_ASSERT(!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast (value)))); + return const_iterator(ValueTraits::to_node_ptr(const_cast (value))); + } +}; + +template +inline bool operator==(const list& x, const list& y) +{ + if(C && x.size() != y.size()){ + return false; + } + typedef typename list::const_iterator const_iterator; + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + if(C){ + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; + } + else{ + const_iterator end2 = y.end(); + while (i1 != end1 && i2 != end2 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1 && i2 == end2; + } +} + +template +inline bool operator<(const list& x, + const list& y) +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +template +inline bool operator!=(const list& x, const list& y) +{ return !(x == y); } + +template +inline bool operator>(const list& x, const list& y) +{ return y < x; } + +template +inline bool operator<=(const list& x, const list& y) +{ return !(y < x); } + +template +inline bool operator>=(const list& x, const list& y) +{ return !(x < y); } + +template +inline void swap(list& x, list& y) +{ x.swap(y); } + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_LIST_HPP diff --git a/include/boost/intrusive/list_hook.hpp b/include/boost/intrusive/list_hook.hpp new file mode 100644 index 0000000..4a23fc0 --- /dev/null +++ b/include/boost/intrusive/list_hook.hpp @@ -0,0 +1,400 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_LIST_HOOK_HPP +#define BOOST_INTRUSIVE_LIST_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! Derive a class from list_base_hook in order to store objects in +//! in an list. list_base_hook holds the data necessary to maintain the +//! list and provides an appropriate value_traits class for list. +//! +//! The first integer template argument defines a tag to identify the node. +//! The same tag value can be used in different classes, but if a class is +//! derived from more than one list_base_hook, then each list_base_hook needs its +//! unique tag. +//! +//! The second boolean template parameter will specify the linking mode of the hook. +//! +//! The third argument is the pointer type that will be used internally in the hook +//! and the list configured from this hook. +template< class Tag //= tag + , linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class list_base_hook + : private detail::list_node_traits::node +{ + public: + typedef detail::list_node_traits node_traits; + enum { linking_policy = Policy }; + + /// @cond + private: + typedef circular_list_algorithms node_algorithms; + + public: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef list_base_hook + this_type; + + typedef typename boost::pointer_to_other + ::type this_type_ptr; + + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + private: + node_ptr this_as_node() + { return node_ptr(static_cast(this)); } + + const_node_ptr this_as_node() const + { return const_node_ptr(static_cast(this)); } + /// @endcond + + public: + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + list_base_hook() + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using list_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + list_base_hook(const list_base_hook& ) + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using list_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + list_base_hook& operator=(const list_base_hook& ) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~list_base_hook() + { detail::destructor_impl(*this, detail::dispatcher()); } + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(list_base_hook &other) + { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); } + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether list::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const + { + //is_linked() can be only used in safe-mode or auto-unlink + BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink)); + return !node_algorithms::unique(this_as_node()); + } + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if Policy is auto_unlink. + //! + //! Throws: Nothing. + void unlink() + { + BOOST_STATIC_ASSERT((Policy == auto_unlink)); + node_algorithms::unlink(this_as_node()); + node_algorithms::init(this_as_node()); + } + + //! The value_traits class is used as the first template argument for list. + //! The template argument T defines the class type stored in list. Objects + //! of type T and of types derived from T can be stored. T doesn't need to be + //! copy-constructible or assignable. + template + struct value_traits + : detail::derivation_value_traits + {}; + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return this_as_node(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return this_as_node(); } +}; + +//! Put a public data member list_member_hook in order to store objects of this class in +//! an list. list_member_hook holds the data necessary for maintaining the list and +//! provides an appropriate value_traits class for list. +//! +//! The first boolean template parameter will specify the linking mode of the hook. +//! +//! The second argument is the pointer type that will be used internally in the hook +//! and the list configured from this hook. +template< linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class list_member_hook + : private detail::list_node_traits::node +{ + public: + typedef detail::list_node_traits node_traits; + enum { linking_policy = Policy }; + + /// @cond + private: + typedef circular_list_algorithms node_algorithms; + /// @endcond + + public: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef list_member_hook + this_type; + + typedef typename boost::pointer_to_other + ::type this_type_ptr; + + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + /// @cond + private: + node_ptr this_as_node() + { return node_ptr(static_cast(this)); } + + const_node_ptr this_as_node() const + { return const_node_ptr(static_cast(this)); } + /// @endcond + + public: + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + list_member_hook() + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using list_member_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + list_member_hook(const list_member_hook& ) + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using list_member_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + list_member_hook& operator=(const list_member_hook& ) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~list_member_hook() + { detail::destructor_impl(*this, detail::dispatcher()); } + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(list_member_hook& other) + { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); } + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether list::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const + { + //is_linked() can be only used in safe-mode or auto-unlink + BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink)); + return !node_algorithms::unique(this_as_node()); + } + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if Policy is auto_unlink. + //! + //! Throws: Nothing. + void unlink() + { + BOOST_STATIC_ASSERT((Policy == auto_unlink)); + node_algorithms::unlink(this_as_node()); + node_algorithms::init(this_as_node()); + } + + //! The value_traits class is used as the first template argument for list. + //! The template argument is a pointer to member pointing to the node in + //! the class. Objects of type T and of types derived from T can be stored. + //! T doesn't need to be copy-constructible or assignable. + template + struct value_traits + : detail::member_value_traits + {}; + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return this_as_node(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return this_as_node(); } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_LIST_HOOK_HPP diff --git a/include/boost/intrusive/pointer_plus_bit.hpp b/include/boost/intrusive/pointer_plus_bit.hpp new file mode 100644 index 0000000..7551869 --- /dev/null +++ b/include/boost/intrusive/pointer_plus_bit.hpp @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_POINTER_PLUS_BIT_HPP +#define BOOST_INTRUSIVE_POINTER_PLUS_BIT_HPP + +#include +#include + +namespace boost { +namespace intrusive { + +//!This trait class is used to know if a pointer +//!can embed an extra bit of information if +//!it's going to be used to point to objects +//!with an alignment of "Alignment" bytes. +template +struct has_pointer_plus_bit +{ + enum { value = false }; +}; + +//!This is an specialization for raw pointers. +//!Raw pointers can embed an extra bit in the lower bit +//!if the alignment is multiple of 2. + +template +struct has_pointer_plus_bit +{ + enum { value = (boost::alignment_of::value % 2u) == 0 }; +}; + +//!This is class that is supposed to have static methods +//!to embed an extra bit of information in a pointer. +//!This is a declaration and there is no default implementation, +//!because operations to embed the bit change with every pointer type. +//! +//!An implementation that detects that a pointer type whose +//!has_pointer_plus_bit<>::value is non-zero can make use of these +//!operations to embed the bit in the pointer. +template +struct pointer_plus_bit; + +//!This is the specialization to embed an extra bit of information +//!in a raw pointer. The extra bit is stored in the lower bit of the pointer. +template +struct pointer_plus_bit +{ + typedef T* pointer; + + //Check that the pointer can embed the bit + BOOST_STATIC_ASSERT((has_pointer_plus_bit::value)); + + static pointer get_pointer(pointer n) + { return pointer(std::size_t(n) & std::size_t(~1u)); } + + static void set_pointer(pointer &n, pointer p) + { + assert(0 == (std::size_t(p) & std::size_t(1u))); + n = pointer(std::size_t(p) | (std::size_t(n) & std::size_t(1u))); + } + + static bool get_bit(pointer n) + { return (std::size_t(n) & std::size_t(1u)) != 0; } + + static void set_bit(pointer &n, bool c) + { n = pointer(std::size_t(get_pointer(n)) | std::size_t(c)); } +}; + +} //namespace intrusive +} //namespace boost + +#endif //BOOST_INTRUSIVE_POINTER_PLUS_BIT_HPP diff --git a/include/boost/intrusive/rbtree.hpp b/include/boost/intrusive/rbtree.hpp new file mode 100644 index 0000000..264cbd7 --- /dev/null +++ b/include/boost/intrusive/rbtree.hpp @@ -0,0 +1,1141 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_RBTREE_HPP +#define BOOST_INTRUSIVE_RBTREE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template rbtree is an intrusive red-black tree container, that +//! is used to construct intrusive set and tree containers. The no-throw +//! guarantee holds only, if the Compare object +//! doesn't throw. +template < class ValueTraits + , class Compare //= std::less + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class rbtree + : private detail::size_holder + , private ValueTraits::node_traits::node +{ + /// @cond + private: + typedef rbtree this_type; + typedef typename ValueTraits::node_traits node_traits; + typedef detail::size_holder size_traits; + + //noncopyable + rbtree (const rbtree&); + rbtree operator =(const rbtree&); + /// @endcond + + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef value_type key_type; + typedef Compare value_compare; + typedef detail::rbtree_iterator iterator; + typedef detail::rbtree_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + /// @cond + private: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef rbtree_algorithms node_algorithms; + enum { safemode_or_autounlink = + (int)ValueTraits::linking_policy == (int)auto_unlink || + (int)ValueTraits::linking_policy == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink))); + + //Use EBO if possible + typedef detail::node_plus_pred members_t; + members_t members_; + + const Compare &priv_comp() const + { return members_.second(); } + + Compare &priv_comp() + { return members_.second(); } + + const node &priv_header() const + { return members_.first(); } + + node &priv_header() + { return members_.first(); } + + static node_ptr uncast(const_node_ptr ptr) + { + using boost::get_pointer; + return node_ptr(const_cast(get_pointer(ptr))); + } + /// @endcond + + public: + typedef typename node_algorithms::insert_commit_data insert_commit_data; + + //! Effects: Constructs an empty tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing unless the copy constructor of the Compare object throws. + rbtree(Compare cmp = Compare()) + : members_(cmp) + { + node_algorithms::init_header(&priv_header()); + size_traits::set_size(size_type(0)); + } + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty tree and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is last ­ first. + //! + //! Throws: Nothing unless the copy constructor of the Compare object throws. + template + rbtree(bool unique, Iterator b, Iterator e, Compare cmp = Compare()) + : members_(cmp) + { + node_algorithms::init_header(&priv_header()); + size_traits::set_size(size_type(0)); + if(unique) + this->insert_unique(b, e); + else + this->insert_equal(b, e); + } + + //! Effects: Detaches all elements from this. The objects in the set + //! are not deleted (i.e. no destructors are called), but the nodes according to + //! the ValueTraits template parameter are reinitialized and thus can be reused. + //! + //! Complexity: Linear to elements contained in *this. + //! + //! Throws: Nothing. + ~rbtree() + { this->clear(); } + + //! Effects: Returns an iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return iterator (node_traits::get_left(node_ptr(&priv_header()))); } + + //! Effects: Returns a const_iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return cbegin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return const_iterator (node_traits::get_left(const_node_ptr(&priv_header()))); } + + //! Effects: Returns an iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return iterator (node_ptr(&priv_header())); } + + //! Effects: Returns a const_iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return cend(); } + + //! Effects: Returns a const_iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return const_iterator (uncast(const_node_ptr(&priv_header()))); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return const_reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(end()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return const_reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return const_reverse_iterator(begin()); } + + //! Precondition: end_iterator must be a valid end iterator + //! of rbtree. + //! + //! Effects: Returns a const reference to the rbtree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static rbtree &container_from_end_iterator(iterator end_iterator) + { + using boost::get_pointer; + return *detail::parent_from_member + ( members_t::this_from_node(get_pointer(end_iterator.pointed_node())) + , &rbtree::members_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of rbtree. + //! + //! Effects: Returns a const reference to the rbtree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const rbtree &container_from_end_iterator(const_iterator end_iterator) + { + using boost::get_pointer; + return *detail::parent_from_member + ( members_t::this_from_node(get_pointer(end_iterator.pointed_node())) + , &rbtree::members_); + } + + //! Effects: Returns the value_compare object used by the tree. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return priv_comp(); } + + //! Effects: Returns true is the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return node_algorithms::unique(const_node_ptr(&priv_header())); } + + //! Effects: Returns the number of elements stored in the tree. + //! + //! Complexity: Linear to elements contained in *this. + //! + //! Throws: Nothing. + size_type size() const + { + if(ConstantTimeSize) + return size_traits::get_size(); + else + return empty() ? 0 : node_algorithms::count(node_traits::get_parent(const_node_ptr(&priv_header()))); + } + + //! Effects: Swaps the contents of two multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the comparison functor's unspecified swap call throws. + void swap(rbtree& other) + { + //This can throw + using std::swap; + swap(priv_comp(), priv_comp()); + //These can't throw + node_algorithms::swap_tree(node_ptr(&priv_header()), node_ptr(&other.priv_header())); + if(ConstantTimeSize){ + size_type backup = size_traits::get_size(); + size_traits::set_size(other.get_size()); + other.set_size(backup); + } + } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the tree before the upper bound. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_equal_upper_bound(reference value) + { + detail::key_node_ptr_compare key_node_comp(priv_comp()); + node_ptr to_insert(ValueTraits::to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + size_traits::increment(); + return iterator(node_algorithms::insert_equal_upper_bound + (node_ptr(&priv_header()), to_insert, key_node_comp)); + } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the tree before the lower bound. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_equal_lower_bound(reference value) + { + detail::key_node_ptr_compare key_node_comp(priv_comp()); + node_ptr to_insert(ValueTraits::to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + size_traits::increment(); + return iterator(node_algorithms::insert_equal_lower_bound + (node_ptr(&priv_header()), to_insert, key_node_comp)); + } + + //! Requires: value must be an lvalue, and "hint" must be + //! a valid iterator. + //! + //! Effects: Inserts x into the tree, using "hint" as a hint to + //! where it will be inserted. If "hint" is the upper_bound + //! the insertion takes constant time (two comparisons in the worst case) + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_equal(const_iterator hint, reference value) + { + detail::key_node_ptr_compare key_node_comp(priv_comp()); + node_ptr to_insert(ValueTraits::to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + size_traits::increment(); + return iterator(node_algorithms::insert_equal + (node_ptr(&priv_header()), hint.pointed_node(), to_insert, key_node_comp)); + } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a each element of a range into the tree + //! before the upper bound of the key of each element. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert_equal(Iterator b, Iterator e) + { + if(this->empty()){ + iterator end(this->end()); + for (; b != e; ++b) + this->insert_equal(end, *b); + } + else{ + for (; b != e; ++b) + this->insert_equal_upper_bound(*b); + } + } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the tree if the value + //! is not already present. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + std::pair insert_unique(reference value) + { + insert_commit_data commit_data; + std::pair ret = insert_unique_check(value, commit_data); + if(!ret.second) + return ret; + return std::pair (insert_unique_commit(value, commit_data), true); + } + + //! Requires: value must be an lvalue, and "hint" must be + //! a valid iterator + //! + //! Effects: Tries to insert x into the tree, using "hint" as a hint + //! to where it will be inserted. + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time (two comparisons in the worst case) + //! if t is inserted immediately before hint. + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_unique(const_iterator hint, reference value) + { + insert_commit_data commit_data; + std::pair ret = insert_unique_check(hint, value, commit_data); + if(!ret.second) + return ret.first; + return insert_unique_commit(value, commit_data); + } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Tries to insert each element of a range into the tree. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert_unique(Iterator b, Iterator e) + { + if(this->empty()){ + iterator end(this->end()); + for (; b != e; ++b) + this->insert_unique(end, *b); + } + else{ + for (; b != e; ++b) + this->insert_unique(*b); + } + } + + std::pair insert_unique_check + (const_reference value, insert_commit_data &commit_data) + { return insert_unique_check(value, priv_comp(), commit_data); } + + template + std::pair insert_unique_check + (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { + detail::key_node_ptr_compare comp(key_value_comp); + std::pair ret = + (node_algorithms::insert_unique_check + (node_ptr(&priv_header()), key, comp, commit_data)); + return std::pair(iterator(ret.first), ret.second); + } + + std::pair insert_unique_check + (const_iterator hint, const_reference value, insert_commit_data &commit_data) + { return insert_unique_check(hint, value, priv_comp(), commit_data); } + + template + std::pair insert_unique_check + (const_iterator hint, const KeyType &key + ,KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { + detail::key_node_ptr_compare comp(key_value_comp); + std::pair ret = + (node_algorithms::insert_unique_check + (node_ptr(&priv_header()), hint.pointed_node(), key, comp, commit_data)); + return std::pair(iterator(ret.first), ret.second); + } + + iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) + { + node_ptr to_insert(ValueTraits::to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + size_traits::increment(); + node_algorithms::insert_unique_commit + (node_ptr(&priv_header()), to_insert, commit_data); + return iterator(to_insert); + } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator i) + { + iterator ret(i); + ++ret; + node_ptr to_erase(i.pointed_node()); + if(safemode_or_autounlink) + BOOST_ASSERT(!node_algorithms::unique(to_erase)); + node_algorithms::erase(&priv_header(), to_erase); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + return ret; + } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator b, iterator e) + { size_type n; return private_erase(b, e, n); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return this->erase(value, priv_comp()); } + + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp) + { + std::pair p = this->equal_range(key, comp); + size_type n; + private_erase(p.first, p.second, n); + return n; + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(iterator i, Destroyer destroyer) + { + node_ptr to_erase(i.pointed_node()); + iterator ret(this->erase(i)); + destroyer(ValueTraits::to_value_ptr(to_erase)); + return ret; + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer) + { size_type n; return private_erase(b, e, n, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_destroy(const_reference value, Destroyer destroyer) + { + std::pair p = this->equal_range(value); + size_type n; + private_erase(p.first, p.second, n, destroyer); + return n; + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_destroy(const KeyType& key, KeyValueCompare comp, Destroyer destroyer) + { + std::pair p = this->equal_range(key, comp); + size_type n; + private_erase(p.first, p.second, n, destroyer); + return n; + } + + //! Effects: Erases all of the elements. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { + if(safemode_or_autounlink){ + while(1){ + node_ptr leftmost + (node_algorithms::unlink_leftmost_without_rebalance + (node_ptr(&priv_header()))); + if(!leftmost) + break; + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(leftmost); + } + } + else{ + node_algorithms::init_header(&priv_header()); + size_traits::set_size(0); + } + } + + //! Effects: Erases all of the elements calling destroyer(p) for + //! each node to be erased. + //! Complexity: Average complexity for is at most O(log(size() + N)), + //! where N is the number of elements in the container. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. Calls N times to destroyer functor. + template + void clear_and_destroy(Destroyer destroyer) + { + while(1){ + node_ptr leftmost + (node_algorithms::unlink_leftmost_without_rebalance + (node_ptr(&priv_header()))); + if(!leftmost) + break; + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(leftmost); + destroyer(ValueTraits::to_value_ptr(leftmost)); + } + } + + //! Effects: Returns the number of contained elements with the given value + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given value. + //! + //! Throws: Nothing. + size_type count(const_reference value) const + { return this->count(value, priv_comp()); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: Nothing. + template + size_type count(const KeyType &key, KeyValueCompare comp) const + { + std::pair ret = this->equal_range(key, comp); + return std::distance(ret.first, ret.second); + } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator lower_bound(const_reference value) + { return this->lower_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator lower_bound(const_reference value) const + { return this->lower_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator lower_bound(const KeyType &key, KeyValueCompare comp) + { + detail::key_node_ptr_compare key_node_comp(comp); + return iterator(node_algorithms::lower_bound + (const_node_ptr(&priv_header()), key, key_node_comp)); + } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator lower_bound(const KeyType &key, KeyValueCompare comp) const + { + detail::key_node_ptr_compare key_node_comp(comp); + return const_iterator(node_algorithms::lower_bound + (const_node_ptr(&priv_header()), key, key_node_comp)); + } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator upper_bound(const_reference value) + { return this->upper_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k according to comp or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator upper_bound(const KeyType &key, KeyValueCompare comp) + { + detail::key_node_ptr_compare key_node_comp(comp); + return iterator(node_algorithms::upper_bound + (const_node_ptr(&priv_header()), key, key_node_comp)); + } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator upper_bound(const_reference value) const + { return this->upper_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k according to comp or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator upper_bound(const KeyType &key, KeyValueCompare comp) const + { + detail::key_node_ptr_compare key_node_comp(comp); + return const_iterator(node_algorithms::upper_bound + (const_node_ptr(&priv_header()), key, key_node_comp)); + } + + //! Effects: Finds an iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator find(const_reference value) + { return this->find(value, priv_comp()); } + + //! Effects: Finds an iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator find(const KeyType &key, KeyValueCompare comp) + { + detail::key_node_ptr_compare key_node_comp(comp); + return iterator + (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp)); + } + + //! Effects: Finds a const_iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator find(const_reference value) const + { return this->find(value, priv_comp()); } + + //! Effects: Finds a const_iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator find(const KeyType &key, KeyValueCompare comp) const + { + detail::key_node_ptr_compare key_node_comp(comp); + return const_iterator + (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp)); + } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + std::pair equal_range(const_reference value) + { return this->equal_range(value, priv_comp()); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + std::pair equal_range(const KeyType &key, KeyValueCompare comp) + { + detail::key_node_ptr_compare key_node_comp(comp); + std::pair ret + (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); + return std::pair(iterator(ret.first), iterator(ret.second)); + } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + std::pair + equal_range(const_reference value) const + { return this->equal_range(value, priv_comp()); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + std::pair + equal_range(const KeyType &key, KeyValueCompare comp) const + { + detail::key_node_ptr_compare key_node_comp(comp); + std::pair ret + (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); + return std::pair(const_iterator(ret.first), const_iterator(ret.second)); + } + + template + void clone_from(const rbtree &src, Cloner cloner, Destroyer destroyer) + { + this->clear_and_destroy(destroyer); + if(!src.empty()){ + node_algorithms::clone_tree + (const_node_ptr(&src.priv_header()) + ,node_ptr(&this->priv_header()) + ,detail::value_to_node_cloner(cloner) + ,detail::value_to_node_destroyer(destroyer)); + size_traits::set_size(src.get_size()); + } + } + + pointer unlink_leftmost_without_rebalance() + { + node_ptr to_destroy(node_algorithms::unlink_leftmost_without_rebalance + (node_ptr(&priv_header()))); + if(!to_destroy) + return 0; + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_destroy); + return ValueTraits::to_value_ptr(to_destroy); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static iterator iterator_to(reference value) + { return iterator (ValueTraits::to_node_ptr(value)); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static const_iterator iterator_to(const_reference value) + { return const_iterator (ValueTraits::to_node_ptr(const_cast (value))); } +/* + //! Requires: value shall not be in a tree of the appropriate type. + //! + //! Effects: init_node post-constructs the node data in x used by multisets of + //! the appropriate type. For the accessors multiset_derived_node and multiset_member_node + //! init_node has no effect, since the constructors of multiset_node_d and multiset_node_m + //! have already initialized the node data. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function is meant to be used mainly with the member value_traits, + //! where no implicit node initialization during construction occurs. + static void init_node(reference value) + { node_algorithms::init(node_ptr(&*ValueTraits::to_node_ptr(value))); } + + //! Effects: removes x from a tree of the appropriate type. It has no effect, + //! if x is not in such a tree. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This static function is only usable with the "safe mode" + //! hook and non-constant time size lists. Otherwise, the user must use + //! the non-static "erase(reference )" member. If the user calls + //! this function with a non "safe mode" or constant time size list + //! a compilation error will be issued. + template + static void remove_node(T& value) + { + //This function is only usable for safe mode hooks and non-constant + //time lists. + //BOOST_STATIC_ASSERT((!(safemode_or_autounlink && ConstantTimeSize))); + BOOST_STATIC_ASSERT((!ConstantTimeSize)); + BOOST_STATIC_ASSERT((boost::is_convertible::value)); + node_ptr to_remove(ValueTraits::to_node_ptr(value)); + node_algorithms::unlink_and_rebalance(to_remove); + if(safemode_or_autounlink) + node_algorithms::init(to_remove); + } +*/ + /// @cond + private: + template + iterator private_erase(iterator b, iterator e, size_type &n, Destroyer destroyer) + { + for(n = 0; b != e; ++n) + this->erase_and_destroy(b++, destroyer); + return b; + } + + iterator private_erase(iterator b, iterator e, size_type &n) + { + for(n = 0; b != e; ++n) + this->erase(b++); + return b; + } + /// @endcond +}; + +template +inline bool operator==(const rbtree& x, const rbtree& y) +{ + if(C && x.size() != y.size()){ + return false; + } + typedef typename rbtree::const_iterator const_iterator; + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + if(C){ + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; + } + else{ + const_iterator end2 = y.end(); + while (i1 != end1 && i2 != end2 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1 && i2 == end2; + } +} + +template +inline bool operator<(const rbtree& x, + const rbtree& y) +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +template +inline bool operator!=(const rbtree& x, const rbtree& y) +{ return !(x == y); } + +template +inline bool operator>(const rbtree& x, const rbtree& y) +{ return y < x; } + +template +inline bool operator<=(const rbtree& x, const rbtree& y) +{ return !(y < x); } + +template +inline bool operator>=(const rbtree& x, const rbtree& y) +{ return !(x < y); } + +template +inline void swap(rbtree& x, rbtree& y) +{ x.swap(y); } + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_RBTREE_HPP diff --git a/include/boost/intrusive/rbtree_algorithms.hpp b/include/boost/intrusive/rbtree_algorithms.hpp new file mode 100644 index 0000000..fbd7d77 --- /dev/null +++ b/include/boost/intrusive/rbtree_algorithms.hpp @@ -0,0 +1,1165 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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. +// +///////////////////////////////////////////////////////////////////////////// +// The internal implementation of red-black trees is based on that of SGI STL +// stl_tree.h file: +// +// Copyright (c) 1996,1997 +// Silicon Graphics Computer Systems, Inc. +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Silicon Graphics makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +// +// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. + +#ifndef BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { +namespace intrusive { + +//! rbtree_algorithms provides basic algorithms to manipulate +//! nodes forming a red-black tree. The insertion and deletion algorithms are +//! based on those in Cormen, Leiserson, and Rivest, Introduction to Algorithms +//! (MIT Press, 1990), except that +//! +//! (1) the header node is maintained with links not only to the root +//! but also to the leftmost node of the tree, to enable constant time +//! begin(), and to the rightmost node of the tree, to enable linear time +//! performance when used with the generic set algorithms (set_union, +//! etc.); +//! +//! (2) when a node being deleted has two children its successor node is +//! relinked into its place, rather than copied, so that the only +//! iterators invalidated are those referring to the deleted node. +//! +//! rbtree_algorithms is configured with a NodeTraits class, which capsulates the +//! information about the node to be manipulated. NodeTraits must support the +//! following interface: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the circular list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! color: The type that can store the color of a node +//! +//! Static functions: +//! +//! static node_ptr get_parent(const_node_ptr n); +//! +//! static void set_parent(node_ptr n, node_ptr parent); +//! +//! static node_ptr get_left(const_node_ptr n); +//! +//! static void set_left(node_ptr n, node_ptr left); +//! +//! static node_ptr get_right(const_node_ptr n); +//! +//! static void set_right(node_ptr n, node_ptr right); +//! +//! static color get_color(const_node_ptr n); +//! +//! static void set_color(node_ptr n, color c); +//! +//! static color black(); +//! +//! static color red(); +template +class rbtree_algorithms +{ + /// @cond + private: + typedef typename NodeTraits::node node; + /// @endcond + + public: + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef typename NodeTraits::color color; + + //! This type is the information that will be filled by insert_unique_check + struct insert_commit_data + { + insert_commit_data() + : link_left(false) + , node(0) + {} + bool link_left; + node_ptr node; + }; + + //! Requires: header1 and header2 must be the header nodes + //! of two trees. + //! + //! Effects: Swaps two trees. After the function header1 will contain + //! links to the second tree and header2 will have links to the first tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static void swap_tree(node_ptr header1, node_ptr header2) + { + if(header1 == header2) + return; + + node_ptr tmp; + + //Parent swap + tmp = NodeTraits::get_parent(header1); + NodeTraits::set_parent(header1, NodeTraits::get_parent(header2)); + NodeTraits::set_parent(header2, tmp); + //Left swap + tmp = NodeTraits::get_left(header1); + NodeTraits::set_left(header1, NodeTraits::get_left(header2)); + NodeTraits::set_left(header2, tmp); + //Right swap + tmp = NodeTraits::get_right(header1); + NodeTraits::set_right(header1, NodeTraits::get_right(header2)); + NodeTraits::set_right(header2, tmp); + + //Now test parent + node_ptr h1_parent(NodeTraits::get_parent(header1)); + if(h1_parent){ + NodeTraits::set_parent(h1_parent, header1); + } + else{ + NodeTraits::set_left(header1, header1); + NodeTraits::set_right(header1, header1); + } + + node_ptr h2_parent(NodeTraits::get_parent(header2)); + if(NodeTraits::get_parent(header2)){ + NodeTraits::set_parent(h2_parent, header2); + } + else{ + NodeTraits::set_left(header2, header2); + NodeTraits::set_right(header2, header2); + } + } + + //! Requires: node is a tree node but not the header. + //! + //! Effects: Unlinks the node and rebalances the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + static void unlink_and_rebalance(node_ptr node) + { + if(NodeTraits::get_parent(node)){ + node_ptr x = NodeTraits::get_parent(node); + while(!is_header(x)) + x = NodeTraits::get_parent(x); + erase(x, node); + } + } + + //! Requires: header is the header of a tree. + //! + //! Effects: Unlinks the leftmost node from the tree, and + //! updates the header link to the new leftmost node. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + static node_ptr unlink_leftmost_without_rebalance(node_ptr header) + { + node_ptr leftmost = NodeTraits::get_left(header); + if (leftmost == header) + return 0; + node_ptr leftmost_parent(NodeTraits::get_parent(leftmost)); + node_ptr leftmost_right (NodeTraits::get_right(leftmost)); + bool is_root = leftmost_parent == header; + + if (leftmost_right){ + NodeTraits::set_parent(leftmost_right, leftmost_parent); + NodeTraits::set_left(header, minimum(leftmost_right)); + + if (is_root) + NodeTraits::set_parent(header, leftmost_right); + else + NodeTraits::set_left(NodeTraits::get_parent(header), leftmost_right); + } + else if (is_root){ + NodeTraits::set_parent(header, 0); + NodeTraits::set_left(header, header); + NodeTraits::set_right(header, header); + } + else{ + NodeTraits::set_left(leftmost_parent, 0); + NodeTraits::set_left(header, leftmost_parent); + } + return leftmost; + } + + //! Requires: node is a node of the tree or an node initialized + //! by init(...). + //! + //! Effects: Returns true if the node is initialized by init(). + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + static bool unique(const_node_ptr node) + { return NodeTraits::get_parent(node) == 0; } + + //! Requires: node is a node of the tree but it's not the header. + //! + //! Effects: Returns the number of nodes of the subtree. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + static std::size_t count(const_node_ptr node) + { + std::size_t result = 1; + if(NodeTraits::get_left(node)) + result += count(NodeTraits::get_left(node)); + if(NodeTraits::get_right(node)) + result += count(NodeTraits::get_right(node)); + return result; + } + + //! Requires: p is a node from the tree except the header. + //! + //! Effects: Returns the next node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr next_node(node_ptr p) + { + node_ptr p_right(NodeTraits::get_right(p)); + if(p_right){ + return minimum(p_right); + } + else { + node_ptr x = NodeTraits::get_parent(p); + while(p == NodeTraits::get_right(x)){ + p = x; + x = NodeTraits::get_parent(x); + } + return NodeTraits::get_right(p) != x ? x : uncast(p); + } + } + + //! Requires: p is a node from the tree except the leftmost node. + //! + //! Effects: Returns the previous node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr prev_node(node_ptr p) + { + if(is_header(p)){ + return NodeTraits::get_right(p); // p is header, return rightmost + } + else if(NodeTraits::get_left(p)){ + return maximum(NodeTraits::get_left(p)); + } + else { + node_ptr x = NodeTraits::get_parent(p); + while(p == NodeTraits::get_left(x)){ + p = x; + x = NodeTraits::get_parent(x); + } + return x; + } + } + + //! Requires: node must not be part of any tree. + //! + //! Effects: After the function unique(node) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init(node_ptr node) + { + NodeTraits::set_parent(node, 0); + NodeTraits::set_left(node, 0); + NodeTraits::set_right(node, 0); + NodeTraits::set_color(node, NodeTraits::black()); + }; + + //! Requires: node must not be part of any tree. + //! + //! Effects: Initializes the header to represent an empty tree. + //! unique(header) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init_header(node_ptr header) + { + NodeTraits::set_parent(header, 0); + NodeTraits::set_left(header, header); + NodeTraits::set_right(header, header); + NodeTraits::set_color(header, NodeTraits::red()); + }; + + //! Requires: header must be the header of a tree, z a node + //! of that tree and z != header. + //! + //! Effects: Erases node "z" from the tree with header "header". + //! + //! Complexity: Amortized constant time. + //! + //! Throws: Nothing. + static node_ptr erase(node_ptr header, node_ptr z) + { + node_ptr y(z); + node_ptr x(0); + node_ptr x_parent(0); + node_ptr y_left(NodeTraits::get_left(y)); + node_ptr y_right(NodeTraits::get_right(y)); + if(!y_left){ + x = y_right; // x might be null. + } + else if(!y_right){ // z has exactly one non-null child. y == z. + x = y_left; // x is not null. + } + else{ + y = minimum (y_right); + x = NodeTraits::get_right(y); // x might be null. + } + + if(y != z){ + // relink y in place of z. y is z's successor + NodeTraits::set_parent(NodeTraits::get_left(z), y); + NodeTraits::set_left(y, NodeTraits::get_left(z)); + if(y != NodeTraits::get_right(z)){ + x_parent = NodeTraits::get_parent(y); + if(x) + NodeTraits::set_parent(x, NodeTraits::get_parent(y)); + NodeTraits::set_left(NodeTraits::get_parent(y), x); // y must be a child of left_ + NodeTraits::set_right(y, NodeTraits::get_right(z)); + NodeTraits::set_parent(NodeTraits::get_right(z), y); + } + else + x_parent = y; + replace_own (z, y, header); + NodeTraits::set_parent(y, NodeTraits::get_parent(z)); + color tmp(NodeTraits::get_color(y)); + tmp = NodeTraits::get_color(y); + NodeTraits::set_color(y, NodeTraits::get_color(z)); + NodeTraits::set_color(z, tmp); +// std::swap(NodeTraits::get_color(y), NodeTraits::get_color(z)); + y = z; + // y now points to node to be actually deleted + } + else { // y == z + x_parent = NodeTraits::get_parent(y); + if(x) + NodeTraits::set_parent(x, NodeTraits::get_parent(y)); + replace_own (z, x, header); + if(NodeTraits::get_left(header) == z){ + NodeTraits::set_left(header, NodeTraits::get_right(z) == 0 ? // z->get_left() must be null also + NodeTraits::get_parent(z) : // makes leftmost == header if z == root + minimum (x)); + } + if(NodeTraits::get_right(header) == z){ + NodeTraits::set_right(header, NodeTraits::get_left(z) == 0 ? // z->get_right() must be null also + NodeTraits::get_parent(z) : // makes rightmost == header if z == root + maximum(x)); + } + } + if(NodeTraits::get_color(y) != NodeTraits::red()){ + while(x != NodeTraits::get_parent(header) && (x == 0 || NodeTraits::get_color(x) == NodeTraits::black())){ + if(x == NodeTraits::get_left(x_parent)){ + node_ptr w = NodeTraits::get_right(x_parent); + if(NodeTraits::get_color(w) == NodeTraits::red()){ + NodeTraits::set_color(w, NodeTraits::black()); + NodeTraits::set_color(x_parent, NodeTraits::red()); + rotate_left(x_parent, header); + w = NodeTraits::get_right(x_parent); + } + if((NodeTraits::get_left(w) == 0 || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black()) && + (NodeTraits::get_right(w) == 0 || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black())){ + NodeTraits::set_color(w, NodeTraits::red()); + x = x_parent; + x_parent = NodeTraits::get_parent(x_parent); + } + else { + if(NodeTraits::get_right(w) == 0 || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black()){ + NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black()); + NodeTraits::set_color(w, NodeTraits::red()); + rotate_right(w, header); + w = NodeTraits::get_right(x_parent); + } + NodeTraits::set_color(w, NodeTraits::get_color(x_parent)); + NodeTraits::set_color(x_parent, NodeTraits::black()); + if(NodeTraits::get_right(w)) + NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black()); + rotate_left(x_parent, header); + break; + } + } + else { + // same as above, with right_ <-> left_. + node_ptr w = NodeTraits::get_left(x_parent); + if(NodeTraits::get_color(w) == NodeTraits::red()){ + NodeTraits::set_color(w, NodeTraits::black()); + NodeTraits::set_color(x_parent, NodeTraits::red()); + rotate_right(x_parent, header); + w = NodeTraits::get_left(x_parent); + } + if((NodeTraits::get_right(w) == 0 || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black()) && + (NodeTraits::get_left(w) == 0 || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black())){ + NodeTraits::set_color(w, NodeTraits::red()); + x = x_parent; + x_parent = NodeTraits::get_parent(x_parent); + } + else { + if(NodeTraits::get_left(w) == 0 || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black()){ + NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black()); + NodeTraits::set_color(w, NodeTraits::red()); + rotate_left(w, header); + w = NodeTraits::get_left(x_parent); + } + NodeTraits::set_color(w, NodeTraits::get_color(x_parent)); + NodeTraits::set_color(x_parent, NodeTraits::black()); + if(NodeTraits::get_left(w)) + NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black()); + rotate_right(x_parent, header); + break; + } + } + } + if(x) + NodeTraits::set_color(x, NodeTraits::black()); + } + return y; + } + + //! Requires: "cloner" must be a function + //! object taking a node_ptr and returning a new cloned node of it. "destroyer" must + //! take a node_ptr and shouldn't throw. + //! + //! Effects: First empties target tree calling + //! void destroyer::operator()(node_ptr) for every node of the tree + //! except the header. + //! + //! Then, duplicates the entire tree pointed by "source_header" cloning each + //! source node with node_ptr Cloner::operator()(node_ptr) to obtain + //! the nodes of the target tree. If "cloner" throws, the cloned target nodes + //! are destroyed using void destroyer(node_ptr). + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are destroyed. + template + static void clone_tree + (const_node_ptr source_header, node_ptr target_header, Cloner cloner, Destroyer destroyer) + { + if(!unique(target_header)){ + node_ptr p; + while((p = unlink_leftmost_without_rebalance(target_header))){ + destroyer(p); + } + } + + node_ptr source_root = NodeTraits::get_parent(source_header); + if(!source_root) + return; + + NodeTraits::set_parent + ( target_header + , deep_clone_node(source_root, target_header, cloner, destroyer)); + NodeTraits::set_left(target_header, minimum(NodeTraits::get_parent(target_header))); + NodeTraits::set_right(target_header, maximum(NodeTraits::get_parent(target_header))); + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is + //! not less than "key" according to "comp" or "header" if that element does + //! not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr lower_bound + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { + node_ptr y = uncast(header); + node_ptr x = NodeTraits::get_parent(header); + while(x){ + if(comp(x, key)){ + x = NodeTraits::get_right(x); + } + else { + y = x; + x = NodeTraits::get_left(x); + } + } + return y; + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is greater + //! than "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr upper_bound + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { + node_ptr y = uncast(header); + node_ptr x = NodeTraits::get_parent(header); + while(x){ + if(comp(key, x)){ + y = x; + x = NodeTraits::get_left(x); + } + else { + x = NodeTraits::get_right(x); + } + } + return y; + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the element that is equivalent to + //! "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr find + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { + node_ptr end = uncast(header); + node_ptr y = lower_bound(header, key, comp); + return (y == end || comp(key, y)) ? end : y; + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an a pair of node_ptr delimiting a range containing + //! all elements that are equivalent to "key" according to "comp" or an + //! empty range that indicates the position where those elements would be + //! if they there are no equivalent elements. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static std::pair equal_range + (const_node_ptr header, const KeyType &key, KeyNodePtrCompare comp) + { + node_ptr y = uncast(header); + node_ptr x = NodeTraits::get_parent(header); + + while(x){ + if(comp(x, key)){ + x = NodeTraits::get_right(x); + } + else if(comp(key, x)){ + y = x; + x = NodeTraits::get_left(x); + } + else{ + node_ptr xu(x), yu(y); + y = x, x = NodeTraits::get_left(x); + xu = NodeTraits::get_right(xu); + + while(x){ + if(comp(x, key)){ + x = NodeTraits::get_right(x); + } + else { + y = x; + x = NodeTraits::get_left(x); + } + } + + while(xu){ + if(comp(key, xu)){ + yu = xu; + xu = NodeTraits::get_left(xu); + } + else { + xu = NodeTraits::get_right(xu); + } + } + return std::pair(y, yu); + } + } + return std::pair(y, y); + } + + //! Requires: "h" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. + //! + //! Effects: Inserts new_node into the tree before the upper bound + //! according to "comp". + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal_upper_bound + (node_ptr h, node_ptr new_node, NodePtrCompare comp) + { + node_ptr y(h); + node_ptr x(NodeTraits::get_parent(y)); + + while(x){ + y = x; + x = comp(new_node, x) ? + NodeTraits::get_left(x) : NodeTraits::get_right(x); + } + + bool link_left = (y == h) || + comp(new_node, y); + link_and_balance(new_node, y, link_left, h); + return new_node; + } + + //! Requires: "h" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. + //! + //! Effects: Inserts new_node into the tree before the lower bound + //! according to "comp". + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal_lower_bound + (node_ptr h, node_ptr new_node, NodePtrCompare comp) + { + node_ptr y(h); + node_ptr x(NodeTraits::get_parent(y)); + + while(x){ + y = x; + x = !comp(x, new_node) ? + NodeTraits::get_left(x) : NodeTraits::get_right(x); + } + + bool link_left = (y == h) || + !comp(y, new_node); + link_and_balance(new_node, y, link_left, h); + return new_node; + } + + //! Requires: "header" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from + //! the "header"'s tree. + //! + //! Effects: Inserts new_node into the tree, using "hint" as a hint to + //! where it will be inserted. If "hint" is the upper_bound + //! the insertion takes constant time (two comparisons in the worst case). + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if new_node is inserted immediately before "hint". + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal + (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp) + { + if(hint == header || !comp(hint, new_node)){ + node_ptr prev(hint); + if(hint == NodeTraits::get_left(header) || + !comp(new_node, (prev = prev_node(hint)))){ + bool link_left = unique(header) || !NodeTraits::get_left(hint); + link_and_balance(new_node, link_left ? hint : prev, link_left, header); + return new_node; + } + else{ + return insert_equal_upper_bound(header, new_node, comp); + } + } + else{ + return insert_equal_lower_bound(header, new_node, comp); + } + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares KeyType with a node_ptr. + //! + //! Effects: Checks if there is an equivalent node to "key" in the + //! tree according to "comp" and obtains the needed information to realize + //! a constant-time node insertion if there is no equivalent node. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing a node_ptr to the already present node + //! and false. If there is not equivalent key can be inserted returns true + //! in the returned pair's boolean and fills "commit_data" that is meant to + //! be used with the "insert_commit" function to achieve a constant-time + //! insertion function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Notes: This function is used to improve performance when constructing + //! a node is expensive and the user does not want to have two equivalent nodes + //! in the tree: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the node and this function offers the possibility to use that part + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the node and use + //! "insert_commit" to insert the node in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_unique_commit" only + //! if no more objects are inserted or erased from the set. + template + static std::pair insert_unique_check + (const_node_ptr header, const KeyType &key + ,KeyNodePtrCompare comp, insert_commit_data &commit_data) + { + node_ptr h(uncast(header)); + node_ptr y(h); + node_ptr x(NodeTraits::get_parent(y)); + node_ptr prev(0); + + //Find the upper bound, cache the previous value and if we should + //store it in the left or right node + bool left_child = true; + while(x){ + y = x; + x = (left_child = comp(key, x)) ? + NodeTraits::get_left(x) : (prev = y, NodeTraits::get_right(x)); + } + + //Since we've found the upper bound there is no other value with the same key if: + // - There is no previous node + // - The previous node is less than the key + if(!prev || comp(prev, key)){ + commit_data.link_left = left_child; + commit_data.node = y; + return std::pair(node_ptr(), true); + } + //If the previous value was not less than key, it means that it's equal + //(because we've checked the upper bound) + else{ + return std::pair(prev, false); + } + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares KeyType with a node_ptr. + //! "hint" is node from the "header"'s tree. + //! + //! Effects: Checks if there is an equivalent node to "key" in the + //! tree according to "comp" using "hint" as a hint to where it should be + //! inserted and obtains the needed information to realize + //! a constant-time node insertion if there is no equivalent node. + //! If "hint" is the upper_bound the function has constant time + //! complexity (two comparisons in the worst case). + //! + //! Returns: If there is an equivalent value + //! returns a pair containing a node_ptr to the already present node + //! and false. If there is not equivalent key can be inserted returns true + //! in the returned pair's boolean and fills "commit_data" that is meant to + //! be used with the "insert_commit" function to achieve a constant-time + //! insertion function. + //! + //! Complexity: Average complexity is at most logarithmic, but it is + //! amortized constant time if new_node should be inserted immediately before "hint". + //! + //! Throws: If "comp" throws. + //! + //! Notes: This function is used to improve performance when constructing + //! a node is expensive and the user does not want to have two equivalent nodes + //! in the tree: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the node and this function offers the possibility to use that part + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the node and use + //! "insert_commit" to insert the node in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_unique_commit" only + //! if no more objects are inserted or erased from the set. + template + static std::pair insert_unique_check + (const_node_ptr header, node_ptr hint, const KeyType &key + ,KeyNodePtrCompare comp, insert_commit_data &commit_data) + { + //hint must be bigger than the key + if(hint == header || comp(key, hint)){ + node_ptr prev = hint; + //The previous value should be less than the key + if(prev == NodeTraits::get_left(header) || comp((prev = prev_node(hint)), key)){ + commit_data.link_left = unique(header) || !NodeTraits::get_left(hint); + commit_data.node = commit_data.link_left ? hint : prev; + return std::pair(node_ptr(), true); + } + else{ + return insert_unique_check(header, key, comp, commit_data); + //return std::pair(prev, false); + } + } + //The hint was wrong, use hintless insert + else{ + return insert_unique_check(header, key, comp, commit_data); + } + } + + //! Requires: "header" must be the header node of a tree. + //! "commit_data" must have been obtained from a previous call to + //! "insert_unique_check". No objects should have been inserted or erased + //! from the set between the "insert_unique_check" that filled "commit_data" + //! and the call to "insert_commit". + //! + //! + //! Effects: Inserts new_node in the set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_unique_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + static void insert_unique_commit + (node_ptr header, node_ptr new_value, const insert_commit_data &commit_data) + { + //Check if commit_data has not been initialized by a insert_unique_check call. + BOOST_ASSERT(commit_data.node != 0); + link_and_balance(new_value, commit_data.node, commit_data.link_left, header); + } + + /// @cond + private: + static node_ptr uncast(const_node_ptr ptr) + { + using boost::get_pointer; + return node_ptr(const_cast(get_pointer(ptr))); + } + + //! Requires: z is the node to be inserted, par is its parent, + //! left, indicates if z should be a left node of par and header is the header + //! of the tree. + //! + //! Effects: If left is true links z as a left child of par or as a right + //! child otherwise. After that rebalances the tree. + //! + //! Complexity: Average constant time.??? + //! + //! Throws: Nothing. + static void link_and_balance (node_ptr z, node_ptr par, bool left, node_ptr header) + { + if(par == header){ + NodeTraits::set_parent(header, z); + NodeTraits::set_right(header, z); + NodeTraits::set_left(header, z); + } + else if(left){ + NodeTraits::set_left(par, z); + if(par == NodeTraits::get_left(header)) + NodeTraits::set_left(header, z); + } + else{ + NodeTraits::set_right(par, z); + if(par == NodeTraits::get_right(header)) + NodeTraits::set_right(header, z); + } + NodeTraits::set_parent(z, par); + NodeTraits::set_right(z, 0); + NodeTraits::set_left(z, 0); + rebalance(z, header); + } + + //! Requires: p is a node of a tree but not the header. + //! + //! Effects: Returns the minimum node of the subtree starting at p. + //! + //! Complexity: Logarithmic to the size of the subtree. + //! + //! Throws: Nothing. + static node_ptr minimum (node_ptr p) + { + for(node_ptr p_left = NodeTraits::get_left(p) + ;p_left + ;p_left = NodeTraits::get_left(p)){ + p = p_left; + } + return p; + } + + //! Requires: p is a node of a tree but not the header. + //! + //! Effects: Returns the maximum node of the subtree starting at p. + //! + //! Complexity: Logarithmic to the size of the subtree. + //! + //! Throws: Nothing. + static node_ptr maximum(node_ptr p) + { + for(node_ptr p_right = NodeTraits::get_right(p) + ;p_right + ;p_right = NodeTraits::get_right(p)){ + p = p_right; + } + return p; + } + + //! Requires: p is a node of a tree. + //! + //! Effects: Returns true if p is the header of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool is_header(const_node_ptr p) + { + return NodeTraits::get_color(p) == NodeTraits::red() && + NodeTraits::get_parent(NodeTraits::get_parent(p)) == p; + } + + //! Requires: p is a node of a tree. + //! + //! Effects: Returns true if p is a left child. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool is_left_child(node_ptr p) + { return NodeTraits::get_left(NodeTraits::get_parent(p)) == p; } + + //! Requires: p is a node of a tree. + //! + //! Effects: Returns true if p is a right child. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool is_right_child (node_ptr p) + { return NodeTraits::get_right(NodeTraits::get_parent(p)) == p; } + + static void replace_own (node_ptr own, node_ptr x, node_ptr header) + { + if(NodeTraits::get_parent(header) == own) + NodeTraits::set_parent(header, x); + else if(is_left_child(own)) + NodeTraits::set_left(NodeTraits::get_parent(own), x); + else + NodeTraits::set_right(NodeTraits::get_parent(own), x); + } + + static void rotate_left(node_ptr p, node_ptr header) + { + node_ptr x = NodeTraits::get_right(p); + NodeTraits::set_right(p, NodeTraits::get_left(x)); + if(NodeTraits::get_left(x) != 0) + NodeTraits::set_parent(NodeTraits::get_left(x), p); + NodeTraits::set_parent(x, NodeTraits::get_parent(p)); + replace_own (p, x, header); + NodeTraits::set_left(x, p); + NodeTraits::set_parent(p, x); + } + + static void rotate_right(node_ptr p, node_ptr header) + { + node_ptr x(NodeTraits::get_left(p)); + node_ptr x_right(NodeTraits::get_right(x)); + NodeTraits::set_left(p, x_right); + if(x_right) + NodeTraits::set_parent(x_right, p); + NodeTraits::set_parent(x, NodeTraits::get_parent(p)); + replace_own (p, x, header); + NodeTraits::set_right(x, p); + NodeTraits::set_parent(p, x); + } + + static void rebalance(node_ptr p, node_ptr header) + { + NodeTraits::set_color(p, NodeTraits::red()); + while(p != NodeTraits::get_parent(header) && NodeTraits::get_color(NodeTraits::get_parent(p)) == NodeTraits::red()){ + node_ptr p_parent(NodeTraits::get_parent(p)); + node_ptr p_parent_parent(NodeTraits::get_parent(p_parent)); + if(is_left_child(p_parent)){ + node_ptr x = NodeTraits::get_right(p_parent_parent); + if(x && NodeTraits::get_color(x) == NodeTraits::red()){ + NodeTraits::set_color(p_parent, NodeTraits::black()); + NodeTraits::set_color(p_parent_parent, NodeTraits::red()); + NodeTraits::set_color(x, NodeTraits::black()); + p = p_parent_parent; + } + else { + if(!is_left_child(p)){ + p = p_parent; + rotate_left(p, header); + } + node_ptr new_p_parent(NodeTraits::get_parent(p)); + node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent)); + NodeTraits::set_color(new_p_parent, NodeTraits::black()); + NodeTraits::set_color(new_p_parent_parent, NodeTraits::red()); + rotate_right(new_p_parent_parent, header); + } + } + else{ + node_ptr x = NodeTraits::get_left(p_parent_parent); + if(x && NodeTraits::get_color(x) == NodeTraits::red()){ + NodeTraits::set_color(p_parent, NodeTraits::black()); + NodeTraits::set_color(p_parent_parent, NodeTraits::red()); + NodeTraits::set_color(x, NodeTraits::black()); + p = p_parent_parent; + } + else{ + if(is_left_child(p)){ + p = p_parent; + rotate_right(p, header); + } + node_ptr new_p_parent(NodeTraits::get_parent(p)); + node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent)); + NodeTraits::set_color(new_p_parent, NodeTraits::black()); + NodeTraits::set_color(new_p_parent_parent, NodeTraits::red()); + rotate_left(new_p_parent_parent, header); + } + } + } + NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black()); + } + + template + static node_ptr deep_clone_node + (node_ptr source_root, node_ptr new_parent, Cloner cloner, Destroyer destroyer) + { + // structural copy. source_root and new_parent must be non-null. + node_ptr top = cloner(source_root); + NodeTraits::set_parent(top, new_parent); + + BOOST_TRY { + if(NodeTraits::get_right(source_root)){ + NodeTraits::set_right + (top, deep_clone_node(NodeTraits::get_right(source_root), top + ,cloner, destroyer)); + } + new_parent = top; + source_root = NodeTraits::get_left(source_root); + + while(source_root){ + node_ptr y = cloner(source_root); + NodeTraits::set_left(new_parent, y); + NodeTraits::set_parent(y, new_parent); + + if(NodeTraits::get_right(source_root)){ + NodeTraits::set_right(y, deep_clone_node(NodeTraits::get_right(source_root), y + ,cloner, destroyer)); + } + new_parent = y; + source_root = NodeTraits::get_left(source_root); + } + } + BOOST_CATCH(...){ + deep_destroy_node(top, destroyer); + BOOST_RETHROW; + } + BOOST_CATCH_END + return top; + } + + template + static void deep_destroy_node(node_ptr x, Destroyer destroyer) + { + // erase without rebalancing + while(x){ + deep_destroy_node(NodeTraits::get_right(x), destroyer); + node_ptr y = NodeTraits::get_left(x); + destroyer(x); + x = y; + } + } + /// @endcond +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP diff --git a/include/boost/intrusive/set.hpp b/include/boost/intrusive/set.hpp new file mode 100644 index 0000000..ab81763 --- /dev/null +++ b/include/boost/intrusive/set.hpp @@ -0,0 +1,1714 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_SET_HPP +#define BOOST_INTRUSIVE_SET_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template set is an intrusive container, that mimics most of +//! the interface of std::set as described in the C++ standard. +//! +//! The template parameter ValueTraits is called "value traits". It stores +//! information and operations about the type to be stored in the container. +//! +//! The template parameter Compare, provides a function object that can compare two +//! element values as sort keys to determine their relative order in the set. +//! +//! If the user specifies ConstantTimeSize as "true", a member of type SizeType +//! will be embedded in the class, that will keep track of the number of stored objects. +//! This will allow constant-time O(1) size() member, instead of default O(N) size. +template < class ValueTraits + , class Compare //= std::less + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class set +{ + /// @cond + typedef rbtree tree_type; + + //! This class is + //! non-copyable + set (const set&); + + //! This class is + //! non-assignable + set &operator =(const set&); + + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef value_type key_type; + typedef Compare value_compare; + typedef value_compare key_compare; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::reverse_iterator reverse_iterator; + typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + + /// @cond + private: + tree_type tree_; + + template + friend bool operator==(const set& x, const set& y); + + template + friend bool operator<(const set& x, const set& y); + /// @endcond + + public: + //! Effects: Constructs an empty set. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor of the Compare object throws. + set(const Compare &cmp = Compare()) + : tree_(cmp) + {} + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty set and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is std::distance(last, first). + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the Compare object throws. + template + set(Iterator b, Iterator e, const Compare &cmp = Compare()) + : tree_(true, b, e, cmp) + { insert(b, e); } + + //! Effects: Detaches all elements from this. The objects in the set + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: O(log(size()) + size()) if it's a safe-mode or auto-unlink + //! value. Otherwise constant. + //! + //! Throws: Nothing. + ~set() + {} + + //! Effects: Returns an iterator pointing to the beginning of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return tree_.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of set. + //! + //! Effects: Returns a const reference to the set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static set &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &set::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of set. + //! + //! Effects: Returns a const reference to the set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const set &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &set::tree_); + } + + //! Effects: Returns the key_compare object used by the set. + //! + //! Complexity: Constant. + //! + //! Throws: If key_compare copy-constructor throws. + key_compare key_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns the value_compare object used by the set. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true is the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the set. + //! + //! Complexity: Linear to elements contained in *this if, + //! ConstantTimeSize is false. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return tree_.size(); } + + //! Effects: Swaps the contents of two sets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(set& other) + { tree_.swap(other.tree_); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Destroyer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. + //! + //! If cloner throws, all cloned elements are unlinked and destroyed + //! calling Destroyer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. + template + void clone_from(const set &src, Cloner cloner, Destroyer destroyer) + { tree_.clone_from(src.tree_, cloner, destroyer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to inserts value into the set. + //! + //! Returns: If the value + //! is not already present inserts it and returns a pair containing the + //! iterator to the new value and true. If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + std::pair insert(reference value) + { return tree_.insert_unique(value); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to to insert x into the set, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: An iterator that points to the position where the + //! new element was inserted into the set. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(const_iterator hint, reference value) + { return tree_.insert_unique(hint, value); } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the set, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the set. + template + std::pair insert_check + (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { return tree_.insert_unique_check(key, key_value_comp, commit_data); } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the set, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the set. + template + std::pair insert_check + (const_iterator hint, const KeyType &key + ,KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { return tree_.insert_unique_check(hint, key, key_value_comp, commit_data); } + + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the set between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + iterator insert_commit(reference value, const insert_commit_data &commit_data) + { return tree_.insert_unique_commit(value, commit_data); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a range into the set. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { tree_.insert_unique(b, e); } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator i) + { return tree_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator b, iterator e) + { return tree_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size()) + this->count(value)). + //! + //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return tree_.erase(value); } + + //! Effects: Erases all the elements that compare equal with + //! the given key and the given comparison functor. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If the comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp) + { return tree_.erase(key, comp); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(iterator i, Destroyer destroyer) + { return tree_.erase_and_destroy(i, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer) + { return tree_.erase_and_destroy(b, e, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: If the internal Compare ordering function throws. + //! + //! Complexity: O(log(size() + this->count(value)). Basic guarantee. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_destroy(const_reference value, Destroyer destroyer) + { return tree_.erase_and_destroy(value, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_destroy(const KeyType& key, KeyValueCompare comp, Destroyer destroyer) + { return tree_.erase_and_destroy(key, comp, destroyer); } + + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return tree_.clear(); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_destroy(Destroyer destroyer) + { return tree_.clear_and_destroy(destroyer); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If the internal Compare ordering function throws. + size_type count(const_reference value) const + { return tree_.find(value) != end(); } + + //! Effects: Returns the number of contained elements with the same key + //! compared with the given comparison functor. + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If comp ordering function throws. + template + size_type count(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp) != end(); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + iterator lower_bound(const_reference value) + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator lower_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + const_iterator lower_bound(const_reference value) const + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + iterator upper_bound(const_reference value) + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator upper_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.upper_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + const_iterator upper_bound(const_reference value) const + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.upper_bound(key, comp); } + + //! Effects: Finds an iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + iterator find(const_reference value) + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyValueCompare comp) + { return tree_.find(key, comp); } + + //! Effects: Finds a const_iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + const_iterator find(const_reference value) const + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + std::pair equal_range(const_reference value) + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyValueCompare comp) + { return tree_.equal_range(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + std::pair + equal_range(const_reference value) const + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyValueCompare comp) const + { return tree_.equal_range(key, comp); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static iterator iterator_to(reference value) + { return tree_type::iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static const_iterator iterator_to(const_reference value) + { return tree_type::iterator_to(value); } + + /// @cond + friend bool operator==(const set &x, const set &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const set &x, const set &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +template +inline bool operator!=(const set& x, const set& y) +{ return !(x==y); } + +template +inline bool operator>(const set& x, const set& y) +{ return y < x; } + +template +inline bool operator<=(const set& x, const set& y) +{ return !(y > x); } + +template +inline bool operator>=(const set& x, const set& y) +{ return !(x < y); } + +template +inline void swap(set& x, set& y) +{ x.swap(y); } + +//! The class template multiset is an intrusive container, that mimics most of +//! the interface of std::multiset as described in the C++ standard. +//! +//! The template parameter ValueTraits is called "value traits". It stores +//! information and operations about the type to be stored +//! in list and what type of hook has been chosen to include it in the list. +//! The value_traits class is supplied by the appropriate hook as a template subtype +//! called "value_traits". +//! +//! The template parameter Compare, provides a function object that can compare two +//! element values as sort keys to determine their relative order in the set. +//! +//! If the user specifies ConstantTimeSize as "true", a member of type SizeType +//! will be embedded in the class, that will keep track of the number of stored objects. +//! This will allow constant-time O(1) size() member, instead of default O(N) size. +template < class ValueTraits + , class Compare //= std::less + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class multiset +{ + /// @cond + typedef rbtree tree_type; + + //! This class is + //! non-copyable + multiset (const multiset&); + + //! This class is + //! non-asignable + multiset &operator =(const multiset&); + + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef value_type key_type; + typedef Compare value_compare; + typedef value_compare key_compare; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::reverse_iterator reverse_iterator; + typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + + /// @cond + private: + tree_type tree_; + /// @endcond + + public: + //! Effects: Constructs an empty multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the Compare object throws. + multiset(const Compare &cmp = Compare()) + : tree_(cmp) + {} + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty multiset and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is last ­ first. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the Compare object throws. + template + multiset(Iterator b, Iterator e, const Compare &cmp = Compare()) + : tree_(false, b, e, cmp) + {} + + //! Effects: Detaches all elements from this. The objects in the set + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: O(log(size()) + size()) if it's a safe-mode or + //! auto-unlink value. Otherwise constant. + //! + //! Throws: Nothing. + ~multiset() + {} + + //! Effects: Returns an iterator pointing to the beginning of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return tree_.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static multiset &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &multiset::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const multiset &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &multiset::tree_); + } + + //! Effects: Returns the key_compare object used by the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If key_compare copy-constructor throws. + key_compare key_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns the value_compare object used by the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true is the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the multiset. + //! + //! Complexity: Linear to elements contained in *this if, + //! ConstantTimeSize is false. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return tree_.size(); } + + //! Effects: Swaps the contents of two multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(multiset& other) + { tree_.swap(other.tree_); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Destroyer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. + //! + //! If cloner throws, all cloned elements are unlinked and destroyed + //! calling Destroyer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. Basic guarantee. + template + void clone_from(const multiset &src, Cloner cloner, Destroyer destroyer) + { tree_.clone_from(src.tree_, cloner, destroyer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the multiset. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(reference value) + { return tree_.insert_equal_upper_bound(value); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts x into the multiset, using pos as a hint to + //! where it will be inserted. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal Compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(const_iterator hint, reference value) + { return tree_.insert_equal(hint, value); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a range into the multiset. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { tree_.insert_equal(b, e); } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator i) + { return tree_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(iterator b, iterator e) + { return tree_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(value)). + //! + //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return tree_.erase(value); } + + //! Effects: Erases all the elements that compare equal with + //! the given key and the given comparison functor. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp) + { return tree_.erase(key, comp); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Effects: Erases the element pointed to by pos. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(iterator i, Destroyer destroyer) + { return tree_.erase_and_destroy(i, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Effects: Erases the range pointed to by b end e. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(iterator b, iterator e, Destroyer destroyer) + { return tree_.erase_and_destroy(b, e, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(value)). + //! + //! Throws: If the internal Compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_destroy(const_reference value, Destroyer destroyer) + { return tree_.erase_and_destroy(value, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_destroy(const KeyType& key, KeyValueCompare comp, Destroyer destroyer) + { return tree_.erase_and_destroy(key, comp, destroyer); } + + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return tree_.clear(); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_destroy(Destroyer destroyer) + { return tree_.clear_and_destroy(destroyer); } + + //! Effects: Returns the number of contained elements with the same key + //! compared with the given comparison functor. + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If comp ordering function throws. + template + size_type count(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp) != end(); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + iterator lower_bound(const_reference value) + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator lower_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + const_iterator lower_bound(const_reference value) const + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + iterator upper_bound(const_reference value) + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator upper_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.upper_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + const_iterator upper_bound(const_reference value) const + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.upper_bound(key, comp); } + + //! Effects: Finds an iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + iterator find(const_reference value) + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyValueCompare comp) + { return tree_.find(key, comp); } + + //! Effects: Finds a const_iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + const_iterator find(const_reference value) const + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + std::pair equal_range(const_reference value) + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyValueCompare comp) + { return tree_.equal_range(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal Compare ordering function throws. + std::pair + equal_range(const_reference value) const + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyValueCompare comp) const + { return tree_.equal_range(key, comp); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static iterator iterator_to(reference value) + { return tree_type::iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static const_iterator iterator_to(const_reference value) + { return tree_type::iterator_to(value); } + + /// @cond + friend bool operator==(const multiset &x, const multiset &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const multiset &x, const multiset &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +template +inline bool operator!=(const multiset& x, const multiset& y) +{ return !(x==y); } + +template +inline bool operator>(const multiset& x, const multiset& y) +{ return y < x; } + +template +inline bool operator<=(const multiset& x, const multiset& y) +{ return !(y > x); } + +template +inline bool operator>=(const multiset& x, const multiset& y) +{ return !(x < y); } + +template +inline void swap(multiset& x, multiset& y) +{ x.swap(y); } + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SET_HPP diff --git a/include/boost/intrusive/set_hook.hpp b/include/boost/intrusive/set_hook.hpp new file mode 100644 index 0000000..0986365 --- /dev/null +++ b/include/boost/intrusive/set_hook.hpp @@ -0,0 +1,367 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_SET_HOOK_HPP +#define BOOST_INTRUSIVE_SET_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! Derive a class from set_base_hook in order to store objects in +//! in an set/multiset. set_base_hook holds the data necessary to maintain +//! the set/multiset and provides an appropriate value_traits class for set/multiset. +//! +//! The first integer template argument defines a tag to identify the node. +//! The same tag value can be used in different classes, but if a class is +//! derived from more than one set_base_hook, then each set_base_hook needs its +//! unique tag. +//! +//! The second boolean template parameter will specify the linking mode of the hook. +//! +//! The third argument is the pointer type that will be used internally in the hook +//! and the set/multiset configured from this hook. +template< class Tag //= tag + , linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class set_base_hook + : private detail::rbtree_node_traits::node +{ + public: + typedef detail::rbtree_node_traits node_traits; + enum { linking_policy = Policy }; + + /// @cond + private: + typedef rbtree_algorithms node_algorithms; + /// @endcond + + public: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef set_base_hook + this_type; + + typedef typename boost::pointer_to_other + ::type this_type_ptr; + + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + /// @cond + private: + + node_ptr this_as_node() + { return node_ptr(static_cast(this)); } + + const_node_ptr this_as_node() const + { return const_node_ptr(static_cast(this)); } + /// @endcond + + public: + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + set_base_hook() + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using set_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + set_base_hook(const set_base_hook& ) + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using set_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + set_base_hook& operator=(const set_base_hook& ) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~set_base_hook() + { detail::destructor_impl(*this, detail::dispatcher()); } + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether set::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const + { + //is_linked() can be only used in safe-mode or auto-unlink + BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink)); + return !node_algorithms::unique(this_as_node()); + } + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if Policy is auto_unlink. + //! + //! Throws: Nothing. + void unlink() + { + BOOST_STATIC_ASSERT((Policy == auto_unlink)); + node_algorithms::unlink_and_rebalance(this_as_node()); + node_algorithms::init(this_as_node()); + } + + //! The value_traits class is used as the first template argument for multiset. + //! The template argument T defines the class type stored in multiset. Objects + //! of type T and of types derived from T can be stored. T don't need to be + //! copy-constructible or assignable. + template + struct value_traits + : detail::derivation_value_traits + {}; + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return this_as_node(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return this_as_node(); } +}; + +//! Put a public data member set_member_hook in order to store objects of this class in +//! an set/multiset. set_member_hook holds the data necessary for maintaining the +//! set/multiset and provides an appropriate value_traits class for set/multiset. +//! +//! The first boolean template parameter will specify the linking mode of the hook. +//! +//! The second argument is the pointer type that will be used internally in the hook +//! and the set/multiset configured from this hook. +template< linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class set_member_hook + : private detail::rbtree_node_traits::node +{ + public: + typedef detail::rbtree_node_traits node_traits; + enum { linking_policy = Policy }; + + /// @cond + private: + typedef rbtree_algorithms node_algorithms; + /// @endcond + + public: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef set_member_hook + this_type; + + typedef typename boost::pointer_to_other + ::type this_type_ptr; + + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + /// @cond + private: + node_ptr this_as_node() + { return node_ptr(static_cast(this)); } + + const_node_ptr this_as_node() const + { return const_node_ptr(static_cast(this)); } + /// @endcond + + public: + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + set_member_hook() + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using set_member_hook STL-compliant without forcing the + //! user to do some additional work. + set_member_hook(const set_member_hook& ) + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using set_member_hook STL-compliant without forcing the + //! user to do some additional work. + set_member_hook& operator=(const set_member_hook& ) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~set_member_hook() + { detail::destructor_impl(*this, detail::dispatcher()); } + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Complexity: Constant + bool is_linked() const + { + //is_linked() can be only used in safe-mode or auto-unlink + BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink)); + return !node_algorithms::unique(this_as_node()); + } + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if Policy is auto_unlink. + //! + //! Throws: Nothing. + void unlink() + { + BOOST_STATIC_ASSERT((Policy == auto_unlink)); + node_algorithms::unlink_and_rebalance(this_as_node()); + node_algorithms::init(this_as_node()); + } + + //! The value_traits class is used as the first template argument for multiset. + //! The template argument is a pointer to member pointing to the node in + //! the class. Objects of type T and of types derived from T can be stored. + //! T don't need to be copy-constructible or assignable. + template + struct value_traits + : detail::member_value_traits + {}; + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return this_as_node(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return this_as_node(); } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SET_HOOK_HPP diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp new file mode 100644 index 0000000..627a4b5 --- /dev/null +++ b/include/boost/intrusive/slist.hpp @@ -0,0 +1,1428 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_SLIST_HPP +#define BOOST_INTRUSIVE_SLIST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template slist is an intrusive container, that encapsulates +//! a singly-linked list. You can use such a list to squeeze the last bit +//! of performance from your application. Unfortunately, the little gains +//! come with some huge drawbacks. A lot of member functions can't be +//! implemented as efficiently as for standard containers. To overcome +//! this limitation some other member functions with rather unusual semantics +//! have to be introduced. +//! +//! The template parameter ValueTraits is called "value traits". It stores +//! information and operations about the type to be stored in the container. +//! +//! If the user specifies ConstantTimeSize as "true", a member of type SizeType +//! will be embedded in the class, that will keep track of the number of stored objects. +//! This will allow constant-time O(1) size() member, instead of default O(N) size. +//! +//! 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. +template < class ValueTraits + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class slist + : private detail::size_holder + , private ValueTraits::node_traits::node +{ + /// @cond + private: + typedef slist this_type; + typedef typename ValueTraits::node_traits node_traits; + typedef detail::size_holder size_traits; + + //! This class is + //! non-copyable + slist (const slist&); + + //! This class is + //! non-asignable + slist &operator =(const slist&); + /// @endcond + + //Public typedefs + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef detail::slist_iterator iterator; + typedef detail::slist_iterator const_iterator; + + /// @cond + private: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef circular_slist_algorithms node_algorithms; + enum { safemode_or_autounlink = + (int)ValueTraits::linking_policy == (int)auto_unlink || + (int)ValueTraits::linking_policy == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink))); + + node_ptr get_root_node() + { return node_ptr(&static_cast(*this)); } + + const_node_ptr get_root_node() const + { return const_node_ptr(&static_cast(*this)); } + + static node_ptr uncast(const_node_ptr ptr) + { + using boost::get_pointer; + return node_ptr(const_cast(get_pointer(ptr))); + } + + static iterator previous_node(iterator beg, iterator i) + { + return iterator + (node_algorithms::get_previous_node(beg.pointed_node(), i.pointed_node())); + } + + static const_iterator previous_node(const_iterator beg, const_iterator i) + { + return const_iterator + (node_algorithms::get_previous_node(beg.pointed_node(), i.pointed_node())); + } + /// @endcond + + public: + //! Effects: constructs an empty list. + //! + //! Complexity: Constant + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). + slist() + { + size_traits::set_size(size_type(0)); + node_algorithms::init(get_root_node()); + } + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! + //! Effects: Constructs a list equal to [first,last). + //! + //! Complexity: Linear in std::distance(b, e). No copy constructors are called. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). + template + slist(Iterator b, Iterator e) + { + size_traits::set_size(size_type(0)); + node_algorithms::init(get_root_node()); + insert_after(before_begin(), b, e); + } + + //! Effects: If it's a safe-mode + //! or auto-unlink value, the destructor does nothing + //! (ie. no code is generated). Otherwise it detaches all elements from this. + //! In this case the objects in the list are not deleted (i.e. no destructors + //! are called), but the hooks according to the ValueTraits template parameter + //! are set to their default value. + //! + //! Complexity: Linear to the number of elements in the list, if + //! it's a safe-mode or auto-unlink value. Otherwise constant. + ~slist() + { this->clear(); } + + //! Effects: Erases all the elements of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of the list. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the erased elements. + void clear() + { + if(safemode_or_autounlink){ + this->erase_after(this->before_begin(), this->end()); + } + else{ + node_algorithms::init(get_root_node()); + size_traits::set_size(size_type(0)); + } + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of the list. + //! + //! Note: Invalidates the iterators to the erased elements. + template + void clear_and_destroy(Destroyer destroyer) + { this->erase_after_and_destroy(this->before_begin(), this->end(), destroyer); } + + //! Requires: value must be an lvalue. + //! + //! Effects: Inserts the value in the front of the list. + //! No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + void push_front(reference value) + { + node_ptr to_insert(ValueTraits::to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(to_insert)); + node_algorithms::link_after(get_root_node(), to_insert); + size_traits::increment(); + } + + //! Effects: Erases the first element of the list. + //! No destructors are called. + //! + //! Throws: Nothing. + //! + //! 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(get_root_node()); + node_algorithms::unlink_after(get_root_node()); + size_traits::decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the first element of the list. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators to the erased element. + template + void pop_front_and_destroy(Destroyer destroyer) + { + node_ptr to_erase = node_traits::get_next(get_root_node()); + this->pop_front(); + destroyer(ValueTraits::to_value_ptr(to_erase)); + } + + //! Effects: Returns a reference to the first element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *ValueTraits::to_value_ptr(node_traits::get_next(get_root_node())); } + + //! Effects: Returns a const_reference to the first element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *ValueTraits::to_value_ptr(uncast(node_traits::get_next(get_root_node()))); } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator (node_traits::get_next(get_root_node())); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return const_iterator (node_traits::get_next(get_root_node())); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator (node_traits::get_next(get_root_node())); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator (get_root_node()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return const_iterator (uncast(get_root_node())); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator (uncast(get_root_node())); } + + //! Effects: Returns an iterator that points to a position + //! before the first element. Equivalent to "end()" + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator before_begin() + { return end(); } + + //! Effects: Returns an iterator that points to a position + //! before the first element. Equivalent to "end()" + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator before_begin() const + { return end(); } + + //! Effects: Returns an iterator that points to a position + //! before the first element. Equivalent to "end()" + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbefore_begin() const + { return end(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of slist. + //! + //! Effects: Returns a const reference to the slist associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static slist &container_from_end_iterator(iterator end_iterator) + { return static_cast(*end_iterator.pointed_node()); } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of slist. + //! + //! Effects: Returns a const reference to the slist associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const slist &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(*end_iterator.pointed_node()); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements contained in the list. + //! if ConstantTimeSize is false. Constant time otherwise. + //! + //! Note: Does not affect the validity of iterators and references. + size_type size() const + { + if(ConstantTimeSize) + return size_traits::get_size(); + else + return node_algorithms::count(get_root_node()) - 1; + } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + bool empty() const + { return node_algorithms::unique(get_root_node()); } + + //! Effects: Swaps the elements of x and *this. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of both lists. + //! + //! Note: Does not affect the validity of iterators and references. + void swap(slist& other) + { + node_algorithms::swap_nodes(get_root_node(), other.get_root_node()); + if(ConstantTimeSize){ + size_type backup = size_traits::get_size(); + size_traits::set_size(other.get_size()); + other.set_size(backup); + } + } + + //! Effects: Moves backwards all the elements, so that the first + //! element becomes the second, the second becomes the third... + //! the last element becomes the first one. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number shifts. + //! + //! 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 = 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); + } + + //! Effects: Moves forward all the elements, so that the second + //! element becomes the first, the third becomes the second... + //! the first element becomes the last one. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number shifts. + //! + //! 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 = 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; + + //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); + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Destroyer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. + //! + //! If cloner throws, all cloned elements are unlinked and destroyed + //! calling Destroyer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. + template + void clone_from(const slist &src, Cloner cloner, Destroyer destroyer) + { + this->clear_and_destroy(destroyer); + try{ + iterator prev = this->before_begin(); + const_iterator b(src.begin()), e(src.end()); + for(; b != e; ++b, ++prev){ + this->insert_after(prev, *cloner(*b)); + } + } + catch(...){ + clear_and_destroy(destroyer); + throw; + } + } + + //! Requires: value must be an lvalue and prev_p must point to an element + //! contained by the list or to end(). + //! + //! Effects: Inserts the value after the position pointed by prev_p. + //! No copy constructor is called. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + iterator insert_after(iterator prev_p, reference value) + { + node_ptr n = ValueTraits::to_node_ptr(value); + if(safemode_or_autounlink) + BOOST_ASSERT(node_algorithms::unique(n)); + node_algorithms::link_after(prev_p.pointed_node(), n); + size_traits::increment(); + return iterator (n); + } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type and prev_p must point to an element + //! contained by the list or to the end node. + //! + //! Effects: Inserts the [first, last) + //! after the position prev_p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted. + //! + //! Note: Does not affect the validity of iterators and references. + template + void insert_after(iterator prev_p, Iterator first, Iterator last) + { + for (; first != last; ++first) + prev_p = insert_after(prev_p, *first); + } + + //! Requires: value must be an lvalue and p must point to an element + //! contained by the list or to end(). + //! + //! Effects: Inserts the value before the position pointed by p. + //! No copy constructor is called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before p. + //! + //! Note: Does not affect the validity of iterators and references. + iterator insert(iterator p, reference value) + { return insert_after(this->previous(p), value); } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type and p must point to an element + //! contained by the list or to the end node. + //! + //! Effects: Inserts the pointed by b and e + //! before the position p. No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus linear + //! to the elements before b. + //! + //! 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); } + + //! Effects: Erases the element after the element pointed by prev of + //! the list. No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! 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()); + size_traits::decrement(); + iterator ret(++prev); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + return ret; + } + + //! Effects: Erases the range (before_first, last) from + //! the list. No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Lineal to the elements (last - before_first). + //! + //! 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; + } + + //! Effects: Erases the element pointed by i of the list. + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed element, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements before i. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase(iterator i) + { return this->erase_after(this->previous(i)); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the range pointed by b and e. + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements erased plus linear + //! to the elements before first. + //! + //! 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); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element after the element pointed by prev of + //! the list. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators to the erased element. + template + iterator erase_after_and_destroy(iterator prev, Destroyer destroyer) + { + iterator it(prev); ++it; + node_ptr to_erase(it.pointed_node()); + iterator ret(this->erase_after(prev)); + destroyer(ValueTraits::to_value_ptr(to_erase)); + return ret; + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range (before_first, last) from + //! the list. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Lineal to the elements (last - before_first). + //! + //! Note: Invalidates the iterators to the erased element. + template + iterator erase_after_and_destroy(iterator before_first, iterator last, Destroyer destroyer) + { + iterator first; + while(++(first = before_first) != last){ + this->erase_after_and_destroy(before_first, destroyer); + } + return last; + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed by i of the list. + //! No destructors are called. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Returns: the first element remaining beyond the removed element, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements before i. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + template + iterator erase_and_destroy(iterator i, Destroyer destroyer) + { return this->erase_after_and_destroy(this->previous(i), destroyer); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed by b and e. + //! No destructors are called. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements erased plus linear + //! to the elements before first. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased elements. + template + iterator erase_and_destroy(iterator first, iterator last, Destroyer destroyer) + { return erase_after_and_destroy(this->previous(first), last, destroyer); } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type. + //! + //! Effects: Clears the list and inserts the range pointed by b and e. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus + //! linear to the elements contained in the list if it's a safe-mode + //! or auto-unlink value. + //! Linear to the number of elements inserted in the list otherwise. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. + template + void assign(Iterator b, Iterator e) + { + this->clear(); + this->insert_after(before_begin(), b, e); + } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type. + //! + //! Effects: Clears the list and inserts the range pointed by b and e. + //! No destructors or copy constructors are called. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus + //! linear to the elements contained in the list. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. + template + void destroy_and_assign(Destroyer destroyer, Iterator b, Iterator e) + { + this->clear_and_destroy(destroyer); + this->insert_after_and_destroy(before_begin(), b, e, destroyer); + } + + //! Requires: prev is an iterator to an element or x.end()/x.before_begin() in x. + //! + //! Effects: Transfers all the elements of list x to this list, after the + //! the element pointed by prev. No destructors or copy constructors are called. + //! + //! Returns: The last element inserted of x or prev if x is empty. + //! This iterator can be used as new "prev" iterator for a new splice_after call. + //! that will splice new values after the previously spliced values. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements contained in x + //! + //! 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 &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()); + size_traits::set_size(size_traits::get_size() + x.get_size()); + x.set_size(size_type(0)); + return last_x; + } + else{ + return prev; + } + } + + //! Requires: prev must point to an element contained by this list or + //! to the before_begin() element. prev_ele must point to an element contained in list + //! x or must be x.before_begin(). + //! + //! Effects: Transfers the element after prev_ele, from list x to this list, + //! after the element pointed by prev. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! 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 &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()); + size_traits::increment(); + x.decrement(); + } + } + + //! Requires: prev_pos must be a dereferenceable iterator in *this or be + //! before_begin(), and before_first and before_last belong to x and + //! ++before_first != x.end() && before_last != x.end(). + //! + //! Effects: Transfers the range (before_first, before_last] from list x to this + //! list, after the element pointed by prev_pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements transferred + //! if ConstantTimeSize is true. Constant-time otherwise. + //! + //! 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_pos, slist &x, iterator before_first, iterator before_last) + { + if (before_first != before_last){ + if(ConstantTimeSize){ + 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()); + size_traits::set_size(size_traits::get_size() + increment); + x.set_size(x.get_size() - increment); + } + else{ + node_algorithms::transfer_after + (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); + } + } + } + + //! Requires: prev_pos must be a dereferenceable iterator in *this or be + //! before_begin(), and before_first and before_last belong to x and + //! ++before_first != x.end() && before_last != x.end() and + //! n == std::distance(before_first, before_last). + //! + //! Effects: Transfers the range (before_first, before_last] from list x to this + //! list, after the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! 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_pos, slist &x, iterator before_first, iterator before_last, difference_type n) + { + if(n){ + if(ConstantTimeSize){ + BOOST_ASSERT(std::distance(before_first, before_last) == n); + node_algorithms::transfer_after + (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); + size_traits::set_size(size_traits::get_size() + n); + x.set_size(x.get_size() - n); + } + else{ + node_algorithms::transfer_after + (prev_pos.pointed_node(), before_first.pointed_node(), before_last.pointed_node()); + } + } + } + + //! Requires: it is an iterator to an element in x. + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by it. No destructors or copy constructors are called. + //! + //! Returns: The last element inserted of x or the previous element + //! of it if x is empty. + //! This iterator can be used as new "prev" iterator for a new splice call. + //! that will splice new values after the previously spliced values. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements contained in x plus linear to + //! the elements before it. + //! + //! 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 &x) + { return 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 + //! x. + //! + //! Effects: Transfers the element elem, from list x to this list, + //! before the element pointed by pos. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements before pos and before elem. + //! + //! 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 &x, iterator elem) + { return splice_after(this->previous(pos), x, this->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. + //! + //! Effects: Transfers the range [first, last) from list x to this + //! list, before the element pointed by pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the sum of elements before pos, first, and last. + //! Plus linear to the number of elements transferred if ConstantTimeSize 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. + void splice(iterator pos, slist &x, iterator first, iterator last) + { return splice_after(this->previous(pos), x, this->previous(first), this->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. + //! n == std::distance(first, last). + //! + //! Effects: Transfers the range [first, last) from list x to this + //! list, before the element pointed by pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the sum of elements before pos, first, and last. + //! + //! 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 &x, iterator first, iterator last, difference_type n) + { return splice_after(this->previous(pos), x, this->previous(first), this->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. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the predicate throws. Basic guarantee. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + //! + //! Note: Iterators and references are not invalidated + template + void sort(Predicate p) + { + if (node_traits::get_next(node_traits::get_next(get_root_node())) + != this->get_root_node()) { + slist carry; + slist counter[64]; + int fill = 0; + iterator last_inserted; + while(!this->empty()){ + last_inserted = this->begin(); + carry.splice_after(carry.before_begin(), *this, this->before_begin()); + int i = 0; + while(i < fill && !counter[i].empty()) { + last_inserted = carry.merge(counter[i++], p); + } + BOOST_ASSERT(counter[i].empty()); + + iterator last_element(previous_node(last_inserted, carry.end())); + if(ConstantTimeSize){ + counter[i].splice_after( counter[i].end(), carry + , carry.before_begin(), last_element + , carry.size()); + } + else{ + counter[i].splice_after( counter[i].end(), carry + , carry.before_begin(), last_element); + } + //counter[i].splice_after(counter[i].end(), carry, carry.end(), previous_node(last_inserted, carry.end())); + //carry.swap(counter[i]); + if(i == fill) + ++fill; + } + + for (int i = 1; i < fill; ++i) + last_inserted = counter[i].merge(counter[i-1], p); + //this->swap(counter[fill-1]); + BOOST_ASSERT(this->empty()); + + iterator last_element(previous_node(last_inserted, counter[--fill].end())); + if(ConstantTimeSize){ + this->splice_after( end(), counter[fill], counter[fill].before_begin() + , last_element, counter[fill].size()); + } + else{ + this->splice_after( end(), counter[fill], counter[fill].before_begin() + , last_element); + } + } + } + + //! 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 + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or std::less throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated. + void sort() + { this->sort(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 + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Returns: An iterator to the last transferred value, end() is x is empty. + //! + //! Throws: If the predicate throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated. + template + iterator merge(slist& x, Predicate p) + { + iterator a(before_begin()), e(end()), ax(x.before_begin()); + 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)){ + ++ix; ++n; + } + if(ax != ix){ + this->splice_after(a, x, ax, ix, n); + last_inserted = ix; + } + a = a_next; + } + if (!x.empty()){ + last_inserted = this->splice_after(a, x); + } + return last_inserted; + } + + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: if std::less throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated + void merge(slist& x) + { this->merge(x, std::less()); } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear to the contained elements. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { node_algorithms::reverse(get_root_node()); } + + //! Effects: Removes all the elements that compare equal to value. + //! No destructors are called. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! 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)); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes all the elements that compare equal to value. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_and_destroy(const_reference value, Destroyer destroyer) + { remove_and_destroy_if(detail::equal_to_value(value), destroyer); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. No destructors are called. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { remove_and_destroy_if(pred, detail::null_destroyer()); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_and_destroy_if(Pred pred, Destroyer destroyer) + { + iterator bcur(this->before_begin()), cur, e(this->end()); + + while(++(cur = bcur) != e){ + if (pred(*cur)){ + pointer p = cur.operator->(); + this->erase_after(bcur); + destroyer(p); + } + else{ + ++bcur; + } + } + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. No destructors are called. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons calls to pred()). + //! + //! 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_destroy(std::equal_to(), detail::null_destroyer()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! No destructors are called. + //! + //! Throws: If the predicate throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(BinaryPredicate pred) + { unique_and_destroy(pred, detail::null_destroyer()); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique_and_destroy(Destroyer destroyer) + { unique(std::equal_to(), destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! Destroyer::operator()(pointer) is called for every removed element. + //! + //! Throws: If the predicate throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique_and_destroy(BinaryPredicate pred, Destroyer destroyer) + { + 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); + destroyer(p); + } + else{ + ++cur; + } + } + } + } + + //! Requires: value must be a reference to a value inserted in a list. + //! + //! Effects: This function returns a const_iterator pointing to the element + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + static iterator iterator_to(reference value) + { + BOOST_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(value))); + return iterator (ValueTraits::to_node_ptr(value)); + } + + //! Requires: value must be a const reference to a value inserted in a list. + //! + //! Effects: This function returns an iterator pointing to the element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + static const_iterator iterator_to(const_reference value) + { + BOOST_ASSERT (!node_algorithms::unique(ValueTraits::to_node_ptr(const_cast (value)))); + return const_iterator (ValueTraits::to_node_ptr(const_cast (value))); + } + + //! Returns: The iterator to the element before i in the list. + //! Returns the end-iterator, if either i is the begin-iterator or the + //! list is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + iterator previous(iterator i) + { + return iterator + (node_algorithms::get_previous_node + (before_begin().pointed_node(), i.pointed_node())); + } + + //! Returns: The const_iterator to the element before i in the list. + //! Returns the end-const_iterator, if either i is the begin-const_iterator or + //! the list is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + const_iterator previous(const_iterator i) const + { + return const_iterator + (node_algorithms::get_previous_node + (before_begin().pointed_node(), i.pointed_node())); + } +}; + +template +inline bool operator==(const slist& x, const slist& y) +{ + if(C && x.size() != y.size()){ + return false; + } + typedef typename slist::const_iterator const_iterator; + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + if(C){ + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; + } + else{ + const_iterator end2 = y.end(); + while (i1 != end1 && i2 != end2 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1 && i2 == end2; + } +} + +template +inline bool operator<(const slist& x, + const slist& y) +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +template +inline bool operator!=(const slist& x, const slist& y) +{ return !(x == y); } + +template +inline bool operator>(const slist& x, const slist& y) +{ return y < x; } + +template +inline bool operator<=(const slist& x, const slist& y) +{ return !(y < x); } + +template +inline bool operator>=(const slist& x, const slist& y) +{ return !(x < y); } + +template +inline void swap(slist& x, slist& y) +{ x.swap(y); } + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SLIST_HPP diff --git a/include/boost/intrusive/slist_hook.hpp b/include/boost/intrusive/slist_hook.hpp new file mode 100644 index 0000000..b6ce0f1 --- /dev/null +++ b/include/boost/intrusive/slist_hook.hpp @@ -0,0 +1,407 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_SLIST_HOOK_HPP +#define BOOST_INTRUSIVE_SLIST_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! Derive a class from slist_base_hook in order to store objects in +//! in an slist. slist_base_hook holds the data necessary to maintain the +//! list and provides an appropriate value_traits class for slist. +//! +//! The first integer template argument defines a tag to identify the node. +//! The same tag value can be used in different classes, but if a class is +//! derived from more than one slist_base_hook, then each slist_base_hook needs its +//! unique tag. +//! +//! The second boolean template parameter will specify the linking mode of the hook. +//! +//! The third argument is the pointer type that will be used internally in the hook +//! and the slist configured from this hook. +template< class Tag //= tag + , linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class slist_base_hook + : private detail::slist_node_traits::node +{ + public: + typedef detail::slist_node_traits node_traits; + enum { linking_policy = Policy }; + + /// @cond + private: + typedef circular_slist_algorithms node_algorithms; + /// @endcond + + public: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef slist_base_hook + this_type; + + typedef typename boost::pointer_to_other + ::type this_type_ptr; + + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + /// @cond + private: + node_ptr this_as_node() + { return node_ptr(static_cast(this)); } + + const_node_ptr this_as_node() const + { return const_node_ptr(static_cast(this)); } + /// @endcond + + public: + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + slist_base_hook() + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using slist_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + slist_base_hook(const slist_base_hook& ) + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using slist_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + slist_base_hook& operator=(const slist_base_hook& ) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~slist_base_hook() + { detail::destructor_impl(*this, detail::dispatcher()); } + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(slist_base_hook &other) + { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); } + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether list::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const + { + //is_linked() can be only used in safe-mode or auto-unlink + BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink)); + return !node_algorithms::unique(this_as_node()); + } + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if Policy is auto_unlink. + //! + //! Throws: Nothing. + void unlink() + { + BOOST_STATIC_ASSERT((Policy == auto_unlink)); + node_algorithms::unlink(this_as_node()); + node_algorithms::init(this_as_node()); + } + + //! The value_traits class is used as the first template argument for list. + //! The template argument T defines the class type stored in list. Objects + //! of type T and of types derived from T can be stored. T doesn't need to be + //! copy-constructible or assignable. + template + struct value_traits + : detail::derivation_value_traits + {}; + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return this_as_node(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return this_as_node(); } +}; + +//! Put a public data member slist_member_hook in order to store objects of this class in +//! an slist. slist_member_hook holds the data necessary for maintaining the list and +//! provides an appropriate value_traits class for slist. +//! +//! The template argument T defines the class type stored in slist. Objects of type +//! T and of types derived from T can be stored. T doesn't need to be +//! copy-constructible or assignable. +//! +//! The second boolean template parameter will specify the linking mode of the hook. +//! +//! The third argument is the pointer type that will be used internally in the hook +//! and the slist configured from this hook. +template< linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class slist_member_hook + : private detail::slist_node_traits::node +{ + public: + typedef detail::slist_node_traits node_traits; + enum { linking_policy = Policy }; + + /// @cond + private: + typedef circular_slist_algorithms node_algorithms; + /// @endcond + + public: + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef slist_member_hook + this_type; + + typedef typename boost::pointer_to_other + ::type this_type_ptr; + + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + /// @cond + private: + node_ptr this_as_node() + { return node_ptr(static_cast(this)); } + + const_node_ptr this_as_node() const + { return const_node_ptr(static_cast(this)); } + /// @endcond + + public: + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + slist_member_hook() + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using slist_member_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + slist_member_hook(const slist_member_hook& ) + : node() + { + if(Policy == safe_link || Policy == auto_unlink){ + node_algorithms::init(this_as_node()); + } + } + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using slist_member_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + slist_member_hook& operator=(const slist_member_hook& ) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~slist_member_hook() + { detail::destructor_impl(*this, detail::dispatcher()); } + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(slist_member_hook& other) + { node_algorithms::swap_nodes(this_as_node(), other.this_as_node()); } + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether list::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const + { + //is_linked() can be only used in safe-mode or auto-unlink + BOOST_STATIC_ASSERT((Policy == safe_link || Policy == auto_unlink)); + return !node_algorithms::unique(this_as_node()); + } + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if Policy is auto_unlink. + //! + //! Throws: Nothing. + void unlink() + { + BOOST_STATIC_ASSERT((Policy == auto_unlink)); + node_algorithms::unlink(this_as_node()); + node_algorithms::init(this_as_node()); + } + + //! The value_traits class is used as the first template argument for list. + //! The template argument is a pointer to member pointing to the node in + //! the class. Objects of type T and of types derived from T can be stored. + //! T doesn't need to be copy-constructible or assignable. + template + struct value_traits + : detail::member_value_traits + {}; + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr(static_cast (get_pointer(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return this_as_node(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return this_as_node(); } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SLIST_HOOK_HPP diff --git a/include/boost/intrusive/tag.hpp b/include/boost/intrusive/tag.hpp new file mode 100644 index 0000000..c885289 --- /dev/null +++ b/include/boost/intrusive/tag.hpp @@ -0,0 +1,26 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztaņaga 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_DEFAULT_TAG_HPP +#define BOOST_INTRUSIVE_DEFAULT_TAG_HPP + +namespace boost { +namespace intrusive { + +//!This is the declaration of the default +//!hook used by base hooks +class tag; + +} //namespace intrusive +} //namespace boost + +#endif //BOOST_INTRUSIVE_DEFAULT_TAG_HPP diff --git a/include/boost/intrusive/unordered_set.hpp b/include/boost/intrusive/unordered_set.hpp new file mode 100644 index 0000000..3f8368e --- /dev/null +++ b/include/boost/intrusive/unordered_set.hpp @@ -0,0 +1,1761 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_HASHSET_HPP +#define BOOST_INTRUSIVE_HASHSET_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template unordered_set is an intrusive container, that mimics most of +//! the interface of std::tr1::unordered_set as described in the C++ TR1. +//! +//! unordered_set is a pseudo-intrusive container: each object to be stored in the +//! container must contain a proper hook, but the container also needs +//! additional auxiliary memory to work: unordered_set needs a pointer to an array +//! of type `bucket_type` to be passed in the constructor. This bucket array must +//! have at least the same lifetime as the container. This makes the use of +//! unordered_set more complicated than purely intrusive containers. +//! `bucket_type` is default-constructible, copyable and assignable +//! +//! The template parameter ValueTraits is called "value traits". It stores +//! information and operations about the type to be stored in the container. +//! +//! The template parameter Hash is a unary function object that take an argument +//! of type ValueTraits::value_type and returns a value of type std::size_t. +//! +//! The template parameter Equal is a binary predicate that takes two arguments of +//! type ValueTraits::value_type. Equal is an equivalence relation. +//! +//! If the user specifies ConstantTimeSize as "true", a member of type SizeType +//! will be embedded in the class, that will keep track of the number of stored objects. +//! This will allow constant-time O(1) size() member, instead of default O(N) size. +//! +//! unordered_set only provides forward iterators but it provides 4 iterator types: +//! iterator and const_iterator to navigate through the whole container and +//! local_iterator and const_local_iterator to navigate through the values +//! stored in a single bucket. Local iterators are faster and smaller. +//! +//! It's not recommended to use non ConstantTimeSize unordered_sets because several +//! key functions, like "empty()", become non-constant time functions. Non +//! ConstantTimeSize unordered_sets are mainly provided to support auto-unlink hooks. +//! +//! unordered_set, unlike std::unordered_set, does not make automatic rehashings nor +//! offers functions related to a load factor. Rehashing can be explicitly requested +//! and the user must provide a new bucket array that will be used from that moment. +//! +//! Since no automatic rehashing is done, iterators are never invalidated when +//! inserting or erasing elements. Iterators are only invalidated when rehasing. +template< class ValueTraits + , class Hash //= boost::hash + , class Equal //= std::equal_to + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class unordered_set +{ + /// @cond + private: + typedef hashtable table_type; + + //! This class is + //! non-copyable + unordered_set (const unordered_set&); + + //! This class is + //! non-assignable + unordered_set &operator =(const unordered_set&); + + typedef table_type implementation_defined; + /// @endcond + + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef value_type key_type; + typedef Equal key_equal; + typedef Hash hasher; + typedef typename implementation_defined::bucket_type bucket_type; + typedef typename boost::pointer_to_other::type bucket_ptr; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + typedef typename implementation_defined::local_iterator local_iterator; + typedef typename implementation_defined::const_local_iterator const_local_iterator; + + /// @cond + private: + table_type table_; + /// @endcond + + public: + + //! Requires: buckets must not be being used by any other resource. + //! + //! Effects: Constructs an empty unordered_set, storing a reference + //! to the bucket array and copies of the hasher and equal functors. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor or invocation of Hash or Equal throws. + //! + //! Notes: buckets array must be destroyed only after + //! *this is destroyed. + unordered_set( bucket_ptr buckets + , size_type buckets_len + , const Hash & hasher = Hash() + , const Equal &equal = Equal()) + : table_(buckets, buckets_len, hasher, equal) + {} + + //! Requires: buckets must not be being used by any other resource + //! and Dereferencing iterator must yield an lvalue of type value_type. + //! + //! Effects: Constructs an empty unordered_set and inserts elements from + //! [b, e). + //! + //! Complexity: If N is std::distance(b, e): Average case is O(N) + //! (with a good hash function and with buckets_len >= N),worst case O(N2). + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor or invocation of Hash or Equal throws. + //! + //! Notes: buckets array must be destroyed only after + //! *this is destroyed. + template + unordered_set( bucket_ptr buckets + , size_type buckets_len + , Iterator b + , Iterator e + , const Hash & hasher = Hash() + , const Equal &equal = Equal()) + : table_(buckets, buckets_len, hasher, equal) + { table_.insert_unique(b, e); } + + //! Effects: Detaches all elements from this. The objects in the unordered_set + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: Linear to the number of elements in the unordered_set, if + //! it's a safe-mode or auto-unlink value. Otherwise constant. + //! + //! Throws: Nothing. + ~unordered_set() + {} + + //! Effects: Returns an iterator pointing to the beginning of the unordered_set. + //! + //! Complexity: Amortized constant time. + //! Worst case (empty unordered_set): O(this->bucket_count()) + //! + //! Throws: Nothing. + iterator begin() + { return table_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning + //! of the unordered_set. + //! + //! Complexity: Amortized constant time. + //! Worst case (empty unordered_set): O(this->bucket_count()) + //! + //! Throws: Nothing. + const_iterator begin() const + { return table_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning + //! of the unordered_set. + //! + //! Complexity: Amortized constant time. + //! Worst case (empty unordered_set): O(this->bucket_count()) + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return table_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the unordered_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return table_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the unordered_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return table_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the unordered_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return table_.cend(); } + + //! Effects: Returns the hasher object used by the unordered_set. + //! + //! Complexity: Constant. + //! + //! Throws: If hasher copy-constructor throws. + hasher hash_function() const + { return table_.hash_function(); } + + //! Effects: Returns the key_equal object used by the unordered_set. + //! + //! Complexity: Constant. + //! + //! Throws: If key_equal copy-constructor throws. + key_equal key_eq() const + { return table_.key_eq(); } + + //! Effects: Returns true is the container is empty. + //! + //! Complexity: if ConstantTimeSize is false, average constant time + //! (worst case, with empty() == true): O(this->bucket_count()). + //! Otherwise constant. + //! + //! Throws: Nothing. + bool empty() const + { return table_.empty(); } + + //! Effects: Returns the number of elements stored in the unordered_set. + //! + //! Complexity: Linear to elements contained in *this if + //! ConstantTimeSize is false. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return table_.size(); } + + //! Requires: the hasher and the equality function unqualified swap + //! call should not throw. + //! + //! Effects: Swaps the contents of two unordered_sets. + //! Swaps also the contained bucket array and equality and hasher functors. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison or hash functors + //! found using ADL throw. Basic guarantee. + void swap(unordered_set& other) + { table_.swap(other.table_); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Destroyer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. + //! + //! If cloner throws, all cloned elements are unlinked and destroyed + //! calling Destroyer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. Basic guarantee. + template + void clone_from(const unordered_set &src, Cloner cloner, Destroyer destroyer) + { table_.clone_from(src.table_, cloner, destroyer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to inserts value into the unordered_set. + //! + //! Returns: If the value + //! is not already present inserts it and returns a pair containing the + //! iterator to the new value and true. If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + std::pair insert(reference value) + { return table_.insert_unique(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the unordered_set, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If hasher or key_value_equal throw. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the hash or the equality is much cheaper to + //! construct than the value_type and this function offers the possibility to + //! use that the part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the unordered_set. + //! + //! After a successful rehashing insert_commit_data remains valid. + template + std::pair insert_check + (const KeyType &key, KeyHasher hasher, KeyValueEqual key_value_equal, insert_commit_data &commit_data) + { return table_.insert_unique_check(key, hasher, key_value_equal, commit_data); } + + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the unordered_set between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the unordered_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + //! + //! After a successful rehashing insert_commit_data remains valid. + iterator insert_commit(reference value, const insert_commit_data &commit_data) + { return table_.insert_unique_commit(value, commit_data); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Equivalent to this->insert(t) for each element in [b, e). + //! + //! Complexity: Average case O(N), where N is std::distance(b, e). + //! Worst case O(N*this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { table_.insert_unique(b, e); } + + //! Effects: Erases the element pointed to by i. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased element. No destructors are called. + void erase(const_iterator i) + { table_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average case O(std::distance(b, e)), + //! worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void erase(const_iterator b, const_iterator e) + { table_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return table_.erase(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Erases all the elements that have the same hash and + //! compare equal with the given key. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If hasher or equal throw. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) + { return table_.erase(key, hasher, equal); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by i. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(const_iterator i, Destroyer destroyer) + { return table_.erase_and_destroy(i, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average case O(std::distance(b, e)), + //! worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_destroy(const_iterator b, const_iterator e, Destroyer destroyer) + { return table_.erase_and_destroy(b, e, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_destroy(const_reference value, Destroyer destroyer) + { return table_.erase_and_destroy(value, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "equal". + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If hasher or key_value_equal throw. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_destroy(const KeyType& key, KeyHasher hasher, KeyValueEqual equal, Destroyer destroyer) + { return table_.erase_and_destroy(key, hasher, equal, destroyer); } + + //! Effects: Erases all of the elements. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return table_.clear(); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all of the elements. + //! + //! Complexity: Linear to the number of elements on the container. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_destroy(Destroyer destroyer) + { return table_.clear_and_destroy(destroyer); } + + //! Effects: Returns the number of contained elements with the given value + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + size_type count(const_reference value) const + { return table_.find(value) != end(); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If hasher or equal throw. + template + size_type count(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const + { return table_.find(key, hasher, equal) != end(); } + + //! Effects: Finds an iterator to the first element is equal to + //! "value" or end() if that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + iterator find(const_reference value) + { return table_.find(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the given hasher and equality functor or end() if + //! that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If hasher or equal throw. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) + { return table_.find(key, hasher, equal); } + + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" or end() if that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + const_iterator find(const_reference value) const + { return table_.find(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the given hasher and equality functor or end() if + //! that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If hasher or equal throw. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const + { return table_.find(key, equal); } + + //! Effects: Returns a range containing all elements with values equivalent + //! to value. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(value)). Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + std::pair equal_range(const_reference value) + { return table_.equal_range(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Returns a range containing all elements with equivalent + //! keys. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! + //! Throws: If hasher or the equal throw. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) + { return table_.equal_range(key, hasher, equal); } + + //! Effects: Returns a range containing all elements with values equivalent + //! to value. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(value)). Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + std::pair + equal_range(const_reference value) const + { return table_.equal_range(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Returns a range containing all elements with equivalent + //! keys. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! + //! Throws: If the hasher or equal throw. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const + { return table_.equal_range(key, equal); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the unordered_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: If the internal hash function throws. + iterator iterator_to(reference value) + { return table_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! unordered_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: If the internal hash function throws. + const_iterator iterator_to(const_reference value) const + { return table_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid local_iterator i belonging to the unordered_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static local_iterator local_iterator_to(reference value) + { return table_type::local_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_local_iterator i belonging to + //! the unordered_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static const_local_iterator local_iterator_to(const_reference value) + { return table_type::local_iterator_to(value); } + + //! Effects: Returns the number of buckets passed in the constructor + //! or the last rehash function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + size_type bucket_count() const + { return table_.bucket_count(); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns the number of elements in the nth bucket. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + size_type bucket_size(size_type n) const + { return table_.bucket_size(n); } + + //! Effects: Returns the index of the bucket in which elements + //! with keys equivalent to k would be found, if any such element existed. + //! + //! Complexity: Constant. + //! + //! Throws: If the hash functor throws. + //! + //! Note: the return value is in the range [0, this->bucket_count()). + size_type bucket(const key_type& k) const + { return table_.bucket(k); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! Effects: Returns the index of the bucket in which elements + //! with keys equivalent to k would be found, if any such element existed. + //! + //! Complexity: Constant. + //! + //! Throws: If hasher throws. + //! + //! Note: the return value is in the range [0, this->bucket_count()). + template + size_type bucket(const KeyType& k, KeyHasher hasher) const + { return table_.bucket(k, hasher); } + + //! Effects: Returns the bucket array pointer passed in the constructor + //! or the last rehash function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bucket_ptr bucket_pointer() const + { return table_.bucket_pointer(); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a local_iterator pointing to the beginning + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + local_iterator begin(size_type n) + { return table_.begin(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the beginning + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator begin(size_type n) const + { return table_.begin(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the beginning + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator cbegin(size_type n) const + { return table_.cbegin(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a local_iterator pointing to the end + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + local_iterator end(size_type n) + { return table_.end(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the end + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator end(size_type n) const + { return table_.end(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the end + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator cend(size_type n) const + { return table_.cend(n); } + + //! Requires: new_buckets must be a pointer to a new bucket array + //! or the same as the old bucket array. new_size is the length of the + //! the array pointed by new_buckets. If new_buckets == this->bucket_pointer() + //! n can be bigger or smaller than this->bucket_count(). + //! + //! Effects: Updates the internal reference with the new bucket erases + //! the values from the old bucket and inserts then in the new one. + //! + //! Complexity: Average case linear in this->size(), worst case quadratic. + //! + //! Throws: If the hasher functor throws. Basic guarantee. + void rehash(bucket_ptr new_buckets, size_type new_size) + { table_.rehash(new_buckets, new_size); } + + //! Effects: Returns the nearest new bucket count optimized for + //! the container that is bigger than n. This suggestion can be used + //! to create bucket arrays with a size that will usually improve + //! container's performance. If such value does not exist, the + //! higher possible value is returned. + //! + //! Complexity: Amortized constant time. + //! + //! Throws: Nothing. + static size_type suggested_upper_bucket_count(size_type n) + { return table_type::suggested_upper_bucket_count(n); } + + //! Effects: Returns the nearest new bucket count optimized for + //! the container that is smaller than n. This suggestion can be used + //! to create bucket arrays with a size that will usually improve + //! container's performance. If such value does not exist, the + //! lower possible value is returned. + //! + //! Complexity: Amortized constant time. + //! + //! Throws: Nothing. + static size_type suggested_lower_bucket_count(size_type n) + { return table_type::suggested_lower_bucket_count(n); } +}; + +//! The class template unordered_multiset is an intrusive container, that mimics most of +//! the interface of std::tr1::unordered_multiset as described in the C++ TR1. +//! +//! unordered_multiset is a pseudo-intrusive container: each object to be stored in the +//! container must contain a proper hook, but the container also needs +//! additional auxiliary memory to work: unordered_multiset needs a pointer to an array +//! of type `bucket_type` to be passed in the constructor. This bucket array must +//! have at least the same lifetime as the container. This makes the use of +//! unordered_multiset more complicated than purely intrusive containers. +//! `bucket_type` is default-constructible, copyable and assignable +//! +//! The template parameter ValueTraits is called "value traits". It stores +//! information and operations about the type to be stored in the container. +//! +//! The template parameter Hash is a unary function object that take an argument +//! of type ValueTraits::value_type and returns a value of type std::size_t. +//! +//! The template parameter Equal is a binary predicate that takes two arguments of +//! type ValueTraits::value_type. Equal is an equivalence relation. +//! +//! If the user specifies ConstantTimeSize as "true", a member of type SizeType +//! will be embedded in the class, that will keep track of the number of stored objects. +//! This will allow constant-time O(1) size() member, instead of default O(N) size. +//! +//! unordered_multiset only provides forward iterators but it provides 4 iterator types: +//! iterator and const_iterator to navigate through the whole container and +//! local_iterator and const_local_iterator to navigate through the values +//! stored in a single bucket. Local iterators are faster and smaller. +//! +//! It's not recommended to use non ConstantTimeSize unordered_multisets because several +//! key functions, like "empty()", become non-constant time functions. Non +//! ConstantTimeSize unordered_multisets are mainly provided to support auto-unlink hooks. +//! +//! unordered_multiset, unlike std::unordered_set, does not make automatic rehashings nor +//! offers functions related to a load factor. Rehashing can be explicitly requested +//! and the user must provide a new bucket array that will be used from that moment. +//! +//! Since no automatic rehashing is done, iterators are never invalidated when +//! inserting or erasing elements. Iterators are only invalidated when rehasing. +template< class ValueTraits + , class Hash //= boost::hash + , class Equal //= std::equal_to + , bool ConstantTimeSize //= true + , class SizeType //= std::size_t + > +class unordered_multiset +{ + /// @cond + private: + typedef hashtable table_type; + /// @endcond + + //! This class is + //! non-copyable + unordered_multiset (const unordered_multiset&); + + //! This class is + //! non-assignable + unordered_multiset &operator =(const unordered_multiset&); + + typedef table_type implementation_defined; + + public: + typedef ValueTraits value_traits; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::const_pointer const_pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::reference const_reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef SizeType size_type; + typedef value_type key_type; + typedef Equal key_equal; + typedef Hash hasher; + typedef typename implementation_defined::bucket_type bucket_type; + typedef typename boost::pointer_to_other::type bucket_ptr; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + typedef typename implementation_defined::local_iterator local_iterator; + typedef typename implementation_defined::const_local_iterator const_local_iterator; + + /// @cond + private: + table_type table_; + /// @endcond + + public: + + //! Requires: buckets must not be being used by any other resource. + //! + //! Effects: Constructs an empty unordered_multiset, storing a reference + //! to the bucket array and copies of the hasher and equal functors. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor or invocation of Hash or Equal throws. + //! + //! Notes: buckets array must be destroyed only after + //! *this is destroyed. + unordered_multiset ( bucket_ptr buckets + , size_type buckets_len + , const Hash & hasher = Hash() + , const Equal &equal = Equal()) + : table_(buckets, buckets_len, hasher, equal) + {} + + //! Requires: buckets must not be being used by any other resource + //! and Dereferencing iterator must yield an lvalue of type value_type. + //! + //! Effects: Constructs an empty unordered_multiset and inserts elements from + //! [b, e). + //! + //! Complexity: If N is std::distance(b, e): Average case is O(N) + //! (with a good hash function and with buckets_len >= N),worst case O(N2). + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor or invocation of Hash or Equal throws. + //! + //! Notes: buckets array must be destroyed only after + //! *this is destroyed. + template + unordered_multiset ( bucket_ptr buckets + , size_type buckets_len + , Iterator b + , Iterator e + , const Hash & hasher = Hash() + , const Equal &equal = Equal()) + : table_(buckets, buckets_len, hasher, equal) + { table_.insert_equal(b, e); } + + //! Effects: Detaches all elements from this. The objects in the unordered_multiset + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: Linear to the number of elements in the unordered_multiset, if + //! it's a safe-mode or auto-unlink value. Otherwise constant. + //! + //! Throws: Nothing. + ~unordered_multiset() + {} + + //! Effects: Returns an iterator pointing to the beginning of the unordered_multiset. + //! + //! Complexity: Amortized constant time. + //! Worst case (empty unordered_multiset): O(this->bucket_count()) + //! + //! Throws: Nothing. + iterator begin() + { return table_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning + //! of the unordered_multiset. + //! + //! Complexity: Amortized constant time. + //! Worst case (empty unordered_multiset): O(this->bucket_count()) + //! + //! Throws: Nothing. + const_iterator begin() const + { return table_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning + //! of the unordered_multiset. + //! + //! Complexity: Amortized constant time. + //! Worst case (empty unordered_multiset): O(this->bucket_count()) + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return table_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the unordered_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return table_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the unordered_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return table_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the unordered_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return table_.cend(); } + + //! Effects: Returns the hasher object used by the unordered_set. + //! + //! Complexity: Constant. + //! + //! Throws: If hasher copy-constructor throws. + hasher hash_function() const + { return table_.hash_function(); } + + //! Effects: Returns the key_equal object used by the unordered_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If key_equal copy-constructor throws. + key_equal key_eq() const + { return table_.key_eq(); } + + //! Effects: Returns true is the container is empty. + //! + //! Complexity: if ConstantTimeSize is false, average constant time + //! (worst case, with empty() == true): O(this->bucket_count()). + //! Otherwise constant. + //! + //! Throws: Nothing. + bool empty() const + { return table_.empty(); } + + //! Effects: Returns the number of elements stored in the unordered_multiset. + //! + //! Complexity: Linear to elements contained in *this if + //! ConstantTimeSize is false. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return table_.size(); } + + //! Requires: the hasher and the equality function unqualified swap + //! call should not throw. + //! + //! Effects: Swaps the contents of two unordered_multisets. + //! Swaps also the contained bucket array and equality and hasher functors. + //! + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison or hash functors + //! found using ADL throw. Basic guarantee. + void swap(unordered_multiset& other) + { table_.swap(other.table_); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Destroyer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. + //! + //! If cloner throws, all cloned elements are unlinked and destroyed + //! calling Destroyer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. + template + void clone_from(const unordered_multiset &src, Cloner cloner, Destroyer destroyer) + { table_.clone_from(src.table_, cloner, destroyer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the unordered_multiset. + //! + //! Returns: An iterator to the new inserted value. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(reference value) + { return table_.insert_equal(value); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Equivalent to this->insert(t) for each element in [b, e). + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { table_.insert_equal(b, e); } + + //! Effects: Erases the element pointed to by i. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased element. No destructors are called. + void erase(const_iterator i) + { table_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average case O(std::distance(b, e)), + //! worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void erase(const_iterator b, const_iterator e) + { table_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return table_.erase(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Erases all the elements that have the same hash and + //! compare equal with the given key. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If the hasher or the equal functors throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) + { return table_.erase(key, hasher, equal); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by i. + //! Destroyer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + void erase_and_destroy(const_iterator i, Destroyer destroyer) + { table_.erase_and_destroy(i, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average case O(std::distance(b, e)), + //! worst case O(this->size()). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + void erase_and_destroy(const_iterator b, const_iterator e, Destroyer destroyer) + { table_.erase_and_destroy(b, e, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_destroy(const_reference value, Destroyer destroyer) + { return table_.erase_and_destroy(value, destroyer); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "equal". + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: Average case O(this->count(value)). + //! Worst case O(this->size()). + //! + //! Throws: If hasher or equal throw. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_destroy(const KeyType& key, KeyHasher hasher, KeyValueEqual equal, Destroyer destroyer) + { return table_.erase_and_destroy(key, hasher, equal, destroyer); } + + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return table_.clear(); } + + //! Requires: Destroyer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Destroyer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_destroy(Destroyer destroyer) + { return table_.clear_and_destroy(destroyer); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + size_type count(const_reference value) const + { return table_.count(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + template + size_type count(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const + { return table_.count(key, hasher, equal); } + + //! Effects: Finds an iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + iterator find(const_reference value) + { return table_.find(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the given hasher and equality functor or end() if + //! that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) + { return table_.find(key, hasher, equal); } + + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" or end() if that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + const_iterator find(const_reference value) const + { return table_.find(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the given hasher and equality functor or end() if + //! that element does not exist. + //! + //! Complexity: Average case O(1), worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const + { return table_.find(key, equal); } + + //! Effects: Returns a range containing all elements with values equivalent + //! to value. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(value)). Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + std::pair equal_range(const_reference value) + { return table_.equal_range(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Returns a range containing all elements with equivalent + //! keys. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) + { return table_.equal_range(key, hasher, equal); } + + //! Effects: Returns a range containing all elements with values equivalent + //! to value. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(value)). Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + std::pair + equal_range(const_reference value) const + { return table_.equal_range(value); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! "key_value_equal" must be a equality function that induces + //! the same equality as key_equal. The difference is that + //! "key_value_equal" compares an arbitrary key with the contained values. + //! + //! Effects: Returns a range containing all elements with equivalent + //! keys. Returns std::make_pair(this->end(), this->end()) if no such + //! elements exist. + //! + //! Complexity: Average case O(this->count(key, hasher, equal)). Worst case O(this->size()). + //! + //! Throws: If the internal hasher or the equality functor throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyHasher hasher, KeyValueEqual equal) const + { return table_.equal_range(key, equal); } + + //! Requires: value must be an lvalue and shall be in a unordered_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the unordered_multiset + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: If the hash function throws. + iterator iterator_to(reference value) + { return table_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! unordered_multiset that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: If the hash function throws. + const_iterator iterator_to(const_reference value) const + { return table_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid local_iterator i belonging to the unordered_multiset + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static local_iterator local_iterator_to(reference value) + { return table_type::local_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a unordered_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_local_iterator i belonging to + //! the unordered_multiset that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static const_local_iterator local_iterator_to(const_reference value) + { return table_type::local_iterator_to(value); } + + //! Effects: Returns the number of buckets passed in the constructor + //! or the last rehash function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + size_type bucket_count() const + { return table_.bucket_count(); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns the number of elements in the nth bucket. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + size_type bucket_size(size_type n) const + { return table_.bucket_size(n); } + + //! Effects: Returns the index of the bucket in which elements + //! with keys equivalent to k would be found, if any such element existed. + //! + //! Complexity: Constant. + //! + //! Throws: If the hash functor throws. + //! + //! Note: the return value is in the range [0, this->bucket_count()). + size_type bucket(const key_type& k) const + { return table_.bucket(k); } + + //! Requires: "hasher" must be a hash function that induces + //! the same hash values as the stored hasher. The difference is that + //! "hasher" hashes the given key instead of the value_type. + //! + //! Effects: Returns the index of the bucket in which elements + //! with keys equivalent to k would be found, if any such element existed. + //! + //! Complexity: Constant. + //! + //! Throws: If the hash functor throws. + //! + //! Note: the return value is in the range [0, this->bucket_count()). + template + size_type bucket(const KeyType& k, const KeyHasher &hasher) const + { return table_.bucket(k, hasher); } + + //! Effects: Returns the bucket array pointer passed in the constructor + //! or the last rehash function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bucket_ptr bucket_pointer() const + { return table_.bucket_pointer(); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a local_iterator pointing to the beginning + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + local_iterator begin(size_type n) + { return table_.begin(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the beginning + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator begin(size_type n) const + { return table_.begin(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the beginning + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator cbegin(size_type n) const + { return table_.cbegin(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a local_iterator pointing to the end + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + local_iterator end(size_type n) + { return table_.end(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the end + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator end(size_type n) const + { return table_.end(n); } + + //! Requires: n is in the range [0, this->bucket_count()). + //! + //! Effects: Returns a const_local_iterator pointing to the end + //! of the sequence stored in the bucket n. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: [this->begin(n), this->end(n)) is a valid range + //! containing all of the elements in the nth bucket. + const_local_iterator cend(size_type n) const + { return table_.cend(n); } + + //! Requires: new_buckets must be a pointer to a new bucket array + //! or the same as the old bucket array. new_size is the length of the + //! the array pointed by new_buckets. If new_buckets == this->bucket_pointer() + //! n can be bigger or smaller than this->bucket_count(). + //! + //! Effects: Updates the internal reference with the new bucket erases + //! the values from the old bucket and inserts then in the new one. + //! + //! Complexity: Average case linear in this->size(), worst case quadratic. + //! + //! Throws: If the hasher functor throws. + void rehash(bucket_ptr new_buckets, size_type new_size) + { table_.rehash(new_buckets, new_size); } + + //! Effects: Returns the nearest new bucket count optimized for + //! the container that is bigger than n. This suggestion can be used + //! to create bucket arrays with a size that will usually improve + //! container's performance. If such value does not exist, the + //! higher possible value is returned. + //! + //! Complexity: Amortized constant time. + //! + //! Throws: Nothing. + static size_type suggested_upper_bucket_count(size_type n) + { return table_type::suggested_upper_bucket_count(n); } + + //! Effects: Returns the nearest new bucket count optimized for + //! the container that is smaller than n. This suggestion can be used + //! to create bucket arrays with a size that will usually improve + //! container's performance. If such value does not exist, the + //! lower possible value is returned. + //! + //! Complexity: Amortized constant time. + //! + //! Throws: Nothing. + static size_type suggested_lower_bucket_count(size_type n) + { return table_type::suggested_lower_bucket_count(n); } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_HASHSET_HPP diff --git a/include/boost/intrusive/unordered_set_hook.hpp b/include/boost/intrusive/unordered_set_hook.hpp new file mode 100644 index 0000000..757b1bb --- /dev/null +++ b/include/boost/intrusive/unordered_set_hook.hpp @@ -0,0 +1,297 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztaņaga 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_HASHSET_HOOK_HPP +#define BOOST_INTRUSIVE_HASHSET_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! Derive a class from unordered_set_base_hook in order to store objects in +//! in an unordered_set/unordered_multi_set. unordered_set_base_hook holds the data necessary to maintain +//! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set. +//! +//! The first integer template argument defines a tag to identify the node. +//! The same tag value can be used in different classes, but if a class is +//! derived from more than one unordered_set_base_hook, then each unordered_set_base_hook needs its +//! unique tag. +//! +//! The second boolean template parameter will specify the linking mode of the hook. +//! +//! The third argument is the pointer type that will be used internally in the hook +//! and the unordered_set/unordered_multi_set configured from this hook. +template< class Tag //= tag + , linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class unordered_set_base_hook +{ + /// @cond + typedef slist_base_hook IsListHook; + IsListHook m_slisthook; + typedef IsListHook implementation_defined; + /// @endcond + + public: + enum { linking_policy = Policy }; + typedef typename implementation_defined::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef unordered_set_base_hook + this_type; + typedef typename boost::pointer_to_other + ::type this_type_ptr; + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + unordered_set_base_hook() + : m_slisthook() + {} + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using unordered_set_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + unordered_set_base_hook(const unordered_set_base_hook &other) + : m_slisthook(other.m_slisthook) + {} + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using unordered_set_base_hook STL-compliant without forcing the + //! user to do some additional work. "swap" can be used to emulate + //! move-semantics. + unordered_set_base_hook& operator=(const unordered_set_base_hook &other) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~unordered_set_base_hook() + {} //m_slisthook's destructor does the job + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether unordered_set/unordered_multiset::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const + { return m_slisthook.is_linked(); } + + //! The value_traits class is used as the first template argument for unordered_set/unordered_multiset. + //! The template argument T defines the class type stored in unordered_set/unordered_multiset. Objects + //! of type T and of types derived from T can be stored. T doesn't need to be + //! copy-constructible or assignable. + template + struct value_traits + : detail::derivation_value_traits + {}; + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return m_slisthook.to_node_ptr(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return m_slisthook.to_node_ptr(); } +}; + +//! Put a public data member unordered_set_member_hook in order to store objects of this class in +//! an unordered_set/unordered_multi_set. unordered_set_member_hook holds the data necessary for maintaining the +//! unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set. +//! +//! The first boolean template parameter will specify the linking mode of the hook. +//! +//! The second argument is the pointer type that will be used internally in the hook +//! and the unordered_set/unordered_multi_set configured from this hook. +template< linking_policy Policy //= safe_link + , class VoidPointer //= void * + > +class unordered_set_member_hook +{ + /// @cond + typedef slist_member_hook IsListHook; + IsListHook m_slisthook; + typedef IsListHook implementation_defined; + /// @endcond + + public: + enum { linking_policy = Policy }; + typedef typename implementation_defined::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef unordered_set_member_hook + this_type; + typedef typename boost::pointer_to_other + ::type this_type_ptr; + typedef typename boost::pointer_to_other + ::type const_this_type_ptr; + + public: + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + unordered_set_member_hook() + : m_slisthook() + {} + + //! Effects: If Policy is auto_unlink or safe_mode_linnk + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using unordered_set_member_hook STL-compliant without forcing the + //! user to do some additional work. + unordered_set_member_hook(const unordered_set_member_hook &other) + : m_slisthook(other.m_slisthook) + {} + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using unordered_set_member_hook STL-compliant without forcing the + //! user to do some additional work. + unordered_set_member_hook& operator=(const unordered_set_member_hook &other) + { return *this; } + + //! Effects: If Policy is normal_link, the destructor does + //! nothing (ie. no code is generated). If Policy is safe_link and the + //! object is stored in an list an assertion is raised. If Policy is + //! auto_unlink and "is_linked()" is true, the node is unlinked. + //! + //! Throws: Nothing. + ~unordered_set_member_hook() + {} //m_slisthook's destructor does the job + + //! Precondition: Policy must be safe_link or auto_unlink. + //! + //! Complexity: Constant + bool is_linked() const + { return m_slisthook.is_linked(); } + + //! The value_traits class is used as the first template argument for unordered_set/unordered_multiset. + //! The template argument is a pointer to member pointing to the node in + //! the class. Objects of type T and of types derived from T can be stored. + //! T doesn't need to be copy-constructible or assignable. + template + struct value_traits + : detail::member_value_traits + {}; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if Policy is auto_unlink. + //! + //! Throws: Nothing. + void unlink() + { m_slisthook.unlink(); } + + //! Effects: Converts a pointer to a node into + //! a pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static this_type_ptr to_hook_ptr(node_ptr p) + { + using boost::get_pointer; + return this_type_ptr((this_type*)get_pointer(IsListHook::to_hook_ptr(p))); + } + + //! Effects: Converts a const pointer to a node stored in a container into + //! a const pointer to the hook that holds that node. + //! + //! Throws: Nothing. + static const_this_type_ptr to_hook_ptr(const_node_ptr p) + { + using boost::get_pointer; + return const_this_type_ptr((const this_type*)get_pointer(IsListHook::to_hook_ptr(p))); + } + + //! Effects: Returns a pointer to the node that this hook holds. + //! + //! Throws: Nothing. + node_ptr to_node_ptr() + { return m_slisthook.to_node_ptr(); } + + //! Effects: Returns a const pointer to the node that this hook holds. + //! + //! Throws: Nothing. + const_node_ptr to_node_ptr() const + { return m_slisthook.to_node_ptr(); } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_HASHSET_HOOK_HPP