diff --git a/include/boost/intrusive/avl_set.hpp b/include/boost/intrusive/avl_set.hpp new file mode 100644 index 0000000..74e8967 --- /dev/null +++ b/include/boost/intrusive/avl_set.hpp @@ -0,0 +1,2069 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 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_AVL_SET_HPP +#define BOOST_INTRUSIVE_AVL_SET_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template avl_set is an intrusive container, that mimics most of +//! the interface of std::set as described in the C++ standard. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<> and +//! \c compare<>. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class avl_set_impl +{ + /// @cond + typedef avltree_impl tree_type; + //! This class is + //! non-copyable + avl_set_impl (const avl_set_impl&); + + //! This class is + //! non-assignable + avl_set_impl &operator =(const avl_set_impl&); + + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef typename implementation_defined::value_type value_type; + typedef typename implementation_defined::value_traits value_traits; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::value_compare value_compare; + typedef typename implementation_defined::key_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; + typedef typename implementation_defined::node_traits node_traits; + typedef typename implementation_defined::node node; + typedef typename implementation_defined::node_ptr node_ptr; + typedef typename implementation_defined::const_node_ptr const_node_ptr; + typedef typename implementation_defined::node_algorithms node_algorithms; + + /// @cond + private: + tree_type tree_; + /// @endcond + + public: + //! Effects: Constructs an empty avl_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 value_compare object throws. + avl_set_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, v_traits) + {} + + //! 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 avl_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 value_compare object throws. + template + avl_set_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(true, b, e, cmp, v_traits) + {} + + //! Effects: Detaches all elements from this. The objects in the avl_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. + ~avl_set_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed avl_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 avl_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 avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed avl_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 avl_set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of avl_set. + //! + //! Effects: Returns a const reference to the avl_set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static avl_set_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &avl_set_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of avl_set. + //! + //! Effects: Returns a const reference to the avl_set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const avl_set_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &avl_set_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the avl_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 avl_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 avl_set. + //! + //! Complexity: Linear to elements contained in *this if, + //! constant-time size option is enabled. 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(avl_set_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::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 disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. + template + void clone_from(const avl_set_impl &src, Cloner cloner, Disposer disposer) + { tree_.clone_from(src.tree_, cloner, disposer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to inserts value into the avl_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 value_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 avl_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 avl_set. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal value_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 aavlitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the avl_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 avl_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 aavlitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the avl_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 avl_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 avl_set between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the avl_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 avl_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 value_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 value_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: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::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_dispose(iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::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_dispose(iterator b, iterator e, Disposer disposer) + { return tree_.erase_and_dispose(b, e, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: If the internal value_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_dispose(const_reference value, Disposer disposer) + { return tree_.erase_and_dispose(value, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::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_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + { return tree_.erase_and_dispose(key, comp, disposer); } + + //! 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: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Disposer::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_dispose(Disposer disposer) + { return tree_.clear_and_dispose(disposer); } + + //! 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 value_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 value_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 value_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 value_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 value_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 value_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 value_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 value_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 value_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 avl_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the avl_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a avl_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! avl_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a avl_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the avl_set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a avl_set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! avl_set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a avl_set/avl_multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { tree_type::init_node(value); } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! 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. + pointer unlink_leftmost_without_rebalance() + { return tree_.unlink_leftmost_without_rebalance(); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { tree_.replace_node(replace_this, with_this); } + + /// @cond + friend bool operator==(const avl_set_impl &x, const avl_set_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const avl_set_impl &x, const avl_set_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_set_impl &x, const avl_set_impl &y) +#else +(const avl_set_impl &x, const avl_set_impl &y) +#endif +{ return !(x == y); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_set_impl &x, const avl_set_impl &y) +#else +(const avl_set_impl &x, const avl_set_impl &y) +#endif +{ return y < x; } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_set_impl &x, const avl_set_impl &y) +#else +(const avl_set_impl &x, const avl_set_impl &y) +#endif +{ return !(y < x); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_set_impl &x, const avl_set_impl &y) +#else +(const avl_set_impl &x, const avl_set_impl &y) +#endif +{ return !(x < y); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(avl_set_impl &x, avl_set_impl &y) +#else +(avl_set_impl &x, avl_set_impl &y) +#endif +{ x.swap(y); } + +//! Helper metafunction to define a \c avl_set that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +struct make_avl_set +{ + /// @cond + typedef avl_set_impl + < typename make_avltree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class avl_set + : public make_avl_set::type +{ + typedef typename make_avl_set + ::type Base; + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + avl_set( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + avl_set( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, v_traits) + {} + + static avl_set &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const avl_set &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + +//! The class template avl_multiset is an intrusive container, that mimics most of +//! the interface of std::avl_multiset as described in the C++ standard. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<> and +//! \c compare<>. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class avl_multiset_impl +{ + /// @cond + typedef avltree_impl tree_type; + + //Non-copyable and non-assignable + avl_multiset_impl (const avl_multiset_impl&); + avl_multiset_impl &operator =(const avl_multiset_impl&); + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef typename implementation_defined::value_type value_type; + typedef typename implementation_defined::value_traits value_traits; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::value_compare value_compare; + typedef typename implementation_defined::key_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; + typedef typename implementation_defined::node_traits node_traits; + typedef typename implementation_defined::node node; + typedef typename implementation_defined::node_ptr node_ptr; + typedef typename implementation_defined::const_node_ptr const_node_ptr; + typedef typename implementation_defined::node_algorithms node_algorithms; + + /// @cond + private: + tree_type tree_; + /// @endcond + + public: + //! Effects: Constructs an empty avl_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 value_compare object throws. + avl_multiset_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, v_traits) + {} + + //! 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 avl_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 the distance between first and last + //! + //! 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 value_compare object throws. + template + avl_multiset_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(false, b, e, cmp, v_traits) + {} + + //! Effects: Detaches all elements from this. The objects in the avl_multiset + //! 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. + ~avl_multiset_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed avl_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 avl_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 avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed avl_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 avl_multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of avl_multiset. + //! + //! Effects: Returns a const reference to the avl_multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static avl_multiset_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &avl_multiset_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of avl_multiset. + //! + //! Effects: Returns a const reference to the avl_multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const avl_multiset_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &avl_multiset_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the avl_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 avl_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 avl_multiset. + //! + //! Complexity: Linear to elements contained in *this if, + //! constant-time size option is enabled. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return tree_.size(); } + + //! Effects: Swaps the contents of two avl_multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(avl_multiset_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::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 disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. Basic guarantee. + template + void clone_from(const avl_multiset_impl &src, Cloner cloner, Disposer disposer) + { tree_.clone_from(src.tree_, cloner, disposer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the avl_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 value_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(value); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts x into the avl_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 value_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 avl_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 value_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 value_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: Disposer::operator()(pointer) shouldn't throw. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::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_dispose(iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + //! Requires: Disposer::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. + //! Disposer::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_dispose(iterator b, iterator e, Disposer disposer) + { return tree_.erase_and_dispose(b, e, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::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 value_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_dispose(const_reference value, Disposer disposer) + { return tree_.erase_and_dispose(value, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::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_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + { return tree_.erase_and_dispose(key, comp, disposer); } + + //! 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: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Disposer::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_dispose(Disposer disposer) + { return tree_.clear_and_dispose(disposer); } + + //! 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 value_compare ordering function throws. + size_type count(const_reference value) const + { return tree_.count(value); } + + //! 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_.count(key, 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: If the internal value_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 value_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 value_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 value_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 value_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 value_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 value_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 value_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 avl_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the avl_multiset + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a avl_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! avl_multiset that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a avl_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the avl_multiset + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a avl_multiset of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! avl_multiset that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a avl_multiset/avl_multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { tree_type::init_node(value); } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! 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. + pointer unlink_leftmost_without_rebalance() + { return tree_.unlink_leftmost_without_rebalance(); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { tree_.replace_node(replace_this, with_this); } + + /// @cond + friend bool operator==(const avl_multiset_impl &x, const avl_multiset_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const avl_multiset_impl &x, const avl_multiset_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#else +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#endif +{ return !(x == y); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#else +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#endif +{ return y < x; } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#else +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#endif +{ return !(y < x); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#else +(const avl_multiset_impl &x, const avl_multiset_impl &y) +#endif +{ return !(x < y); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(avl_multiset_impl &x, avl_multiset_impl &y) +#else +(avl_multiset_impl &x, avl_multiset_impl &y) +#endif +{ x.swap(y); } + +//! Helper metafunction to define a \c avl_multiset that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +struct make_avl_multiset +{ + /// @cond + typedef avl_multiset_impl + < typename make_avltree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class avl_multiset + : public make_avl_multiset::type +{ + typedef typename make_avl_multiset + ::type Base; + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + avl_multiset( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + avl_multiset( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, v_traits) + {} + + static avl_multiset &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const avl_multiset &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_AVL_SET_HPP diff --git a/include/boost/intrusive/avl_set_hook.hpp b/include/boost/intrusive/avl_set_hook.hpp new file mode 100644 index 0000000..390c577 --- /dev/null +++ b/include/boost/intrusive/avl_set_hook.hpp @@ -0,0 +1,259 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 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_AVL_SET_HOOK_HPP +#define BOOST_INTRUSIVE_AVL_SET_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond +template +struct get_avl_set_node_algo +{ + typedef avltree_algorithms > type; +}; +/// @endcond + +//! Helper metafunction to define a \c avl_set_base_hook that yields to the same +//! type when the same options (either explicitly or implicitly) are used. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +struct make_avl_set_base_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3, O4>::type packed_options; + + typedef detail::generic_hook + < get_avl_set_node_algo + , typename packed_options::tag + , packed_options::link_mode + , detail::AvlSetBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Derive a class from avl_set_base_hook in order to store objects in +//! in an set/multiset. avl_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 avl_set_base_hook, then each avl_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. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class avl_set_base_hook + : public make_avl_set_base_hook::type +{ + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + avl_set_base_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + avl_set_base_hook(const avl_set_base_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + avl_set_base_hook& operator=(const avl_set_base_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in an set an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~avl_set_base_hook(); + + //! 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(avl_set_base_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c set::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif +}; + +//! Helper metafunction to define a \c avl_set_member_hook that yields to the same +//! type when the same options (either explicitly or implicitly) are used. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +struct make_avl_set_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, O1, O2, O3, O4>::type packed_options; + + typedef detail::generic_hook + < get_avl_set_node_algo + , member_tag + , packed_options::link_mode + , detail::NoBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Put a public data member avl_set_member_hook in order to store objects of this class in +//! an set/multiset. avl_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. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class avl_set_member_hook + : public make_avl_set_member_hook::type +{ + #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + avl_set_member_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + avl_set_member_hook(const avl_set_member_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + avl_set_member_hook& operator=(const avl_set_member_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in an set an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~avl_set_member_hook(); + + //! 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(avl_set_member_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c set::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_AVL_SET_HOOK_HPP diff --git a/include/boost/intrusive/avltree.hpp b/include/boost/intrusive/avltree.hpp new file mode 100644 index 0000000..e5af13b --- /dev/null +++ b/include/boost/intrusive/avltree.hpp @@ -0,0 +1,1442 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 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_AVLTREE_HPP +#define BOOST_INTRUSIVE_AVLTREE_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond + +template +struct internal_default_avl_set_hook +{ + template static detail::one test(...); + template static detail::two test(typename U::default_avl_set_hook* = 0); + static const bool value = sizeof(test(0)) == sizeof(detail::two); +}; + +template +struct get_default_avl_set_hook +{ + typedef typename T::default_avl_set_hook type; +}; + +template +struct avl_setopt +{ + typedef ValueTraits value_traits; + typedef Compare compare; + typedef SizeType size_type; + static const bool constant_time_size = ConstantTimeSize; +}; + +template +struct avl_set_defaults + : pack_options + < none + , base_hook + < typename detail::eval_if_c + < internal_default_avl_set_hook::value + , get_default_avl_set_hook + , detail::identity + >::type + > + , constant_time_size + , size_type + , compare > + >::type +{}; + +/// @endcond + +//! The class template avltree is an intrusive AVL tree container, that +//! is used to construct intrusive avl_set and avl_multiset containers. +//! The no-throw guarantee holds only, if the value_compare object +//! doesn't throw. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<> and +//! \c compare<>. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +class avltree_impl +{ + public: + typedef typename Config::value_traits value_traits; + /// @cond + static const bool external_value_traits = + detail::external_value_traits_is_true::value; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::type real_value_traits; + /// @endcond + typedef typename real_value_traits::pointer pointer; + typedef typename real_value_traits::const_pointer const_pointer; + typedef typename std::iterator_traits::value_type value_type; + typedef value_type key_type; + 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 typename Config::size_type size_type; + typedef typename Config::compare value_compare; + typedef value_compare key_compare; + typedef tree_iterator iterator; + typedef tree_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef typename real_value_traits::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 avltree_algorithms node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::store_cont_ptr_on_it::value; + + /// @cond + private: + typedef detail::size_holder size_traits; + + //noncopyable + avltree_impl (const avltree_impl&); + avltree_impl operator =(const avltree_impl&); + + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink))); + + struct header_plus_size : public size_traits + { node header_; }; + + struct node_plus_pred_t : public detail::ebo_functor_holder + { + node_plus_pred_t(const value_compare &comp) + : detail::ebo_functor_holder(comp) + {} + header_plus_size header_plus_size_; + }; + + struct data_t : public avltree_impl::value_traits + { + typedef typename avltree_impl::value_traits value_traits; + data_t(const value_compare & comp, const value_traits &val_traits) + : value_traits(val_traits), node_plus_pred_(comp) + {} + node_plus_pred_t node_plus_pred_; + } data_; + + const value_compare &priv_comp() const + { return data_.node_plus_pred_.get(); } + + value_compare &priv_comp() + { return data_.node_plus_pred_.get(); } + + const node &priv_header() const + { return data_.node_plus_pred_.header_plus_size_.header_; } + + node &priv_header() + { return data_.node_plus_pred_.header_plus_size_.header_; } + + static node_ptr uncast(const_node_ptr ptr) + { + return node_ptr(const_cast(detail::get_pointer(ptr))); + } + + size_traits &priv_size_traits() + { return data_.node_plus_pred_.header_plus_size_; } + + const size_traits &priv_size_traits() const + { return data_.node_plus_pred_.header_plus_size_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_.get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_; } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_.get_value_traits(*this); } + + /// @endcond + + public: + + const real_value_traits &get_real_value_traits() const + { return this->get_real_value_traits(detail::bool_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + + 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 value_compare object throws. + avltree_impl( value_compare cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, v_traits) + { + node_algorithms::init_header(&priv_header()); + this->priv_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 the distance between first and last. + //! + //! Throws: Nothing unless the copy constructor of the value_compare object throws. + template + avltree_impl( bool unique, Iterator b, Iterator e + , value_compare cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, v_traits) + { + node_algorithms::init_header(&priv_header()); + this->priv_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 value_traits template parameter are reinitialized and thus can be reused. + //! + //! Complexity: Linear to elements contained in *this. + //! + //! Throws: Nothing. + ~avltree_impl() + { 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())), this); } + + //! 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())), this); } + + //! Effects: Returns an iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return iterator (node_ptr(&priv_header()), this); } + + //! 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())), this); } + + //! 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 avltree. + //! + //! Effects: Returns a const reference to the avltree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static avltree_impl &container_from_end_iterator(iterator end_iterator) + { return priv_container_from_end_iterator(end_iterator); } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of avltree. + //! + //! Effects: Returns a const reference to the avltree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const avltree_impl &container_from_end_iterator(const_iterator end_iterator) + { return priv_container_from_end_iterator(end_iterator); } + + //! 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(constant_time_size) + return this->priv_size_traits().get_size(); + else{ + const_iterator beg(this->cbegin()), end(this->cend()); + size_type i = 0; + for(;beg != end; ++beg) ++i; + return i; + } + } + + //! Effects: Swaps the contents of two multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the comparison functor's swap call throws. + void swap(avltree_impl& 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(constant_time_size){ + size_type backup = this->priv_size_traits().get_size(); + this->priv_size_traits().set_size(other.priv_size_traits().get_size()); + other.priv_size_traits().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(reference value) + { + detail::key_nodeptr_comp + key_node_comp(priv_comp(), this); + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + return iterator(node_algorithms::insert_equal_upper_bound + (node_ptr(&priv_header()), to_insert, key_node_comp), this); + } + + //! 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_nodeptr_comp + key_node_comp(priv_comp(), this); + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + return iterator(node_algorithms::insert_equal + (node_ptr(&priv_header()), hint.pointed_node(), to_insert, key_node_comp), this); + } + + //! 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) + { + iterator end(this->end()); + for (; b != e; ++b) + this->insert_equal(end, *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_nodeptr_comp + comp(key_value_comp, this); + std::pair ret = + (node_algorithms::insert_unique_check + (node_ptr(&priv_header()), key, comp, commit_data)); + return std::pair(iterator(ret.first, this), 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_nodeptr_comp + comp(key_value_comp, this); + 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, this), ret.second); + } + + iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) + { + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + node_algorithms::insert_unique_commit + (node_ptr(&priv_header()), to_insert, commit_data); + return iterator(to_insert, this); + } + + //! 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_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!node_algorithms::unique(to_erase)); + node_algorithms::erase(&priv_header(), to_erase); + this->priv_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: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::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_dispose(iterator i, Disposer disposer) + { + node_ptr to_erase(i.pointed_node()); + iterator ret(this->erase(i)); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + return ret; + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::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_dispose(iterator b, iterator e, Disposer disposer) + { size_type n; return private_erase(b, e, n, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::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_dispose(const_reference value, Disposer disposer) + { + std::pair p = this->equal_range(value); + size_type n; + private_erase(p.first, p.second, n, disposer); + return n; + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::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_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer) + { + std::pair p = this->equal_range(key, comp); + size_type n; + private_erase(p.first, p.second, n, disposer); + 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){ + this->clear_and_dispose(detail::null_disposer()); + } + else{ + node_algorithms::init_header(&priv_header()); + this->priv_size_traits().set_size(0); + } + } + + //! Effects: Erases all of the elements calling disposer(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 disposer functor. + template + void clear_and_dispose(Disposer disposer) + { + node_algorithms::clear_and_dispose(node_ptr(&priv_header()) + , detail::node_disposer(disposer, this)); + node_algorithms::init_header(&priv_header()); + this->priv_size_traits().set_size(0); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + return iterator(node_algorithms::lower_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + return const_iterator(node_algorithms::lower_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + return iterator(node_algorithms::upper_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + return const_iterator(node_algorithms::upper_bound + (const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + return iterator + (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + return const_iterator + (node_algorithms::find(const_node_ptr(&priv_header()), key, key_node_comp), this); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); + return std::pair(iterator(ret.first, this), iterator(ret.second, this)); + } + + //! 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_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::equal_range(const_node_ptr(&priv_header()), key, key_node_comp)); + return std::pair(const_iterator(ret.first, this), const_iterator(ret.second, this)); + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::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 disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. + template + void clone_from(const avltree_impl &src, Cloner cloner, Disposer disposer) + { + this->clear_and_dispose(disposer); + if(!src.empty()){ + node_algorithms::clone + (const_node_ptr(&src.priv_header()) + ,node_ptr(&this->priv_header()) + ,detail::node_cloner(cloner, this) + ,detail::node_disposer(disposer, this)); + this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + } + } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! 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. + pointer unlink_leftmost_without_rebalance() + { + node_ptr to_be_disposed(node_algorithms::unlink_leftmost_without_rebalance + (node_ptr(&priv_header()))); + if(!to_be_disposed) + return 0; + this->priv_size_traits().decrement(); + if(safemode_or_autounlink)//If this is commented does not work with normal_link + node_algorithms::init(to_be_disposed); + return get_real_value_traits().to_value_ptr(to_be_disposed); + } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { + node_algorithms::replace_node( get_real_value_traits().to_node_ptr(*replace_this) + , node_ptr(&priv_header()) + , get_real_value_traits().to_node_ptr(with_this)); + } + + //! 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. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + return iterator (value_traits::to_node_ptr(value), 0); + } + + //! 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. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + return const_iterator (value_traits::to_node_ptr(const_cast (value)), 0); + } + + //! 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. + iterator iterator_to(reference value) + { return iterator (value_traits::to_node_ptr(value), this); } + + //! 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. + const_iterator iterator_to(const_reference value) const + { return const_iterator (value_traits::to_node_ptr(const_cast (value)), this); } + + //! Requires: value shall not be in a tree. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { node_algorithms::init(value_traits::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 && constant_time_size))); + BOOST_STATIC_ASSERT((!constant_time_size)); + BOOST_STATIC_ASSERT((boost::is_convertible::value)); + node_ptr to_remove(value_traits::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, Disposer disposer) + { + for(n = 0; b != e; ++n) + this->erase_and_dispose(b++, disposer); + return b; + } + + iterator private_erase(iterator b, iterator e, size_type &n) + { + for(n = 0; b != e; ++n) + this->erase(b++); + return b; + } + /// @endcond + + private: + static avltree_impl &priv_container_from_end_iterator(const const_iterator &end_iterator) + { + header_plus_size *r = detail::parent_from_member + ( detail::get_pointer(end_iterator.pointed_node()), &header_plus_size::header_); + node_plus_pred_t *n = detail::parent_from_member + (r, &node_plus_pred_t::header_plus_size_); + data_t *d = detail::parent_from_member(n, &data_t::node_plus_pred_); + avltree_impl *avl = detail::parent_from_member(d, &avltree_impl::data_); + return *avl; + } +}; + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator< +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avltree_impl &x, const avltree_impl &y) +#else +(const avltree_impl &x, const avltree_impl &y) +#endif +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +bool operator== +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avltree_impl &x, const avltree_impl &y) +#else +(const avltree_impl &x, const avltree_impl &y) +#endif +{ + typedef avltree_impl tree_type; + typedef typename tree_type::const_iterator const_iterator; + + if(tree_type::constant_time_size && x.size() != y.size()){ + return false; + } + const_iterator end1 = x.end(); + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + if(tree_type::constant_time_size){ + 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; + } +} + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator!= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avltree_impl &x, const avltree_impl &y) +#else +(const avltree_impl &x, const avltree_impl &y) +#endif +{ return !(x == y); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator> +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avltree_impl &x, const avltree_impl &y) +#else +(const avltree_impl &x, const avltree_impl &y) +#endif +{ return y < x; } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator<= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avltree_impl &x, const avltree_impl &y) +#else +(const avltree_impl &x, const avltree_impl &y) +#endif +{ return !(y < x); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline bool operator>= +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(const avltree_impl &x, const avltree_impl &y) +#else +(const avltree_impl &x, const avltree_impl &y) +#endif +{ return !(x < y); } + +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +inline void swap +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +(avltree_impl &x, avltree_impl &y) +#else +(avltree_impl &x, avltree_impl &y) +#endif +{ x.swap(y); } + +/// @cond +template +struct make_avltree_opt +{ + typedef typename pack_options + < avl_set_defaults, O1, O2, O3, O4>::type packed_options; + typedef typename detail::get_value_traits + ::type value_traits; + + typedef avl_setopt + < value_traits + , typename packed_options::compare + , typename packed_options::size_type + , packed_options::constant_time_size + > type; +}; +/// @endcond + +//! Helper metafunction to define a \c avltree that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +#else +template +#endif +struct make_avltree +{ + /// @cond + typedef avltree_impl + < typename make_avltree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +template +class avltree + : public make_avltree::type +{ + typedef typename make_avltree + ::type Base; + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::real_value_traits real_value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + avltree( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + avltree( bool unique, Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(unique, b, e, cmp, v_traits) + {} + + static avltree &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const avltree &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_AVLTREE_HPP diff --git a/include/boost/intrusive/avltree_algorithms.hpp b/include/boost/intrusive/avltree_algorithms.hpp new file mode 100644 index 0000000..3783ef8 --- /dev/null +++ b/include/boost/intrusive/avltree_algorithms.hpp @@ -0,0 +1,975 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Daniel K. O. 2005. +// (C) Copyright Ion Gaztanaga 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_AVLTREE_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_AVLTREE_ALGORITHMS_HPP + +#include + +#include +#include + +#include +#include +#include +#include + + +namespace boost { +namespace intrusive { + +//! avltree_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 +//! +//! balance: The type of the balance factor +//! +//! 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 balance get_balance(const_node_ptr n); +//! +//! static void set_balance(node_ptr n, balance b); +//! +//! static balance negative(); +//! +//! static balance zero(); +//! +//! static balance positive(); +template +class avltree_algorithms +{ + public: + typedef NodeTraits node_traits; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef typename NodeTraits::balance balance; + + /// @cond + private: + + typedef typename NodeTraits::node node; + typedef detail::tree_algorithms tree_algorithms; + + template + struct avltree_node_cloner + : private detail::ebo_functor_holder + { + typedef detail::ebo_functor_holder base_t; + + avltree_node_cloner(F f) + : base_t(f) + {} + + node_ptr operator()(node_ptr p) + { + node_ptr n = base_t::get()(p); + NodeTraits::set_balance(n, NodeTraits::get_balance(p)); + return n; + } + }; + + struct avltree_erase_fixup + { + void operator()(node_ptr to_erase, node_ptr successor) + { NodeTraits::set_balance(successor, NodeTraits::get_balance(to_erase)); } + }; + + static node_ptr uncast(const_node_ptr ptr) + { + return node_ptr(const_cast(::boost::intrusive::detail::get_pointer(ptr))); + } + /// @endcond + + public: + static node_ptr begin_node(const_node_ptr header) + { return tree_algorithms::begin_node(header); } + + static node_ptr end_node(const_node_ptr header) + { return tree_algorithms::end_node(header); } + + //! This type is the information that will be + //! filled by insert_unique_check + typedef typename tree_algorithms::insert_commit_data insert_commit_data; + + //! 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) + { return tree_algorithms::swap_tree(header1, header2); } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(node_ptr node1, node_ptr node2) + { + if(node1 == node2) + return; + + node_ptr header1(tree_algorithms::get_header(node1)), header2(tree_algorithms::get_header(node2)); + swap_nodes(node1, header1, node2, header2); + } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees with header header1 and header2. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(node_ptr node1, node_ptr header1, node_ptr node2, node_ptr header2) + { + if(node1 == node2) return; + + tree_algorithms::swap_nodes(node1, header1, node2, header2); + //Swap balance + balance c = NodeTraits::get_balance(node1); + NodeTraits::set_balance(node1, NodeTraits::get_balance(node2)); + NodeTraits::set_balance(node2, c); + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing and comparison is needed. + //! + //!Experimental function + static void replace_node(node_ptr node_to_be_replaced, node_ptr new_node) + { + if(node_to_be_replaced == new_node) + return; + replace_node(node_to_be_replaced, tree_algorithms::get_header(node_to_be_replaced), new_node); + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! with header "header" and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + //! + //!Experimental function + static void replace_node(node_ptr node_to_be_replaced, node_ptr header, node_ptr new_node) + { + tree_algorithms::replace_node(node_to_be_replaced, header, new_node); + NodeTraits::set_balance(new_node, NodeTraits::get_balance(node_to_be_replaced)); + } + + //! 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(node_ptr node) + { + node_ptr x = NodeTraits::get_parent(node); + if(x){ + 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) + { return tree_algorithms::unlink_leftmost_without_rebalance(header); } + + //! 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 tree_algorithms::unique(node); } + + //! Requires: node is a node of the tree but it's not the header. + //! + //! Effects: Returns the number of nodes of the subtree. + //! + //! Complexity: Linear time. + //! + //! Throws: Nothing. + static std::size_t count(const_node_ptr node) + { return tree_algorithms::count(node); } + + //! 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) + { return tree_algorithms::next_node(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) + { return tree_algorithms::prev_node(p); } + + //! 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) + { tree_algorithms::init(node); } + + //! 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) + { + tree_algorithms::init_header(header); + NodeTraits::set_balance(header, NodeTraits::zero()); + } + + //! 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) + { + typename tree_algorithms::data_for_rebalance info; + tree_algorithms::erase(header, z, avltree_erase_fixup(), info); + node_ptr x = info.x; + node_ptr x_parent = info.x_parent; + + //Rebalance avltree + rebalance_after_erasure(header, x, x_parent); + return z; + } + + //! Requires: "cloner" must be a function + //! object taking a node_ptr and returning a new cloned node of it. "disposer" must + //! take a node_ptr and shouldn't throw. + //! + //! Effects: First empties target tree calling + //! void disposer::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 disposed using void disposer(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 disposed. + template + static void clone + (const_node_ptr source_header, node_ptr target_header, Cloner cloner, Disposer disposer) + { + avltree_node_cloner new_cloner(cloner); + tree_algorithms::clone(source_header, target_header, new_cloner, disposer); + } + + //! Requires: "disposer" must be an object function + //! taking a node_ptr parameter and shouldn't throw. + //! + //! Effects: Empties the target tree calling + //! void disposer::operator()(node_ptr) for every node of the tree + //! except the header. + //! + //! 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 disposed. + template + static void clear_and_dispose(node_ptr header, Disposer disposer) + { tree_algorithms::clear_and_dispose(header, disposer); } + + //! 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) + { return tree_algorithms::lower_bound(header, key, 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. 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) + { return tree_algorithms::upper_bound(header, key, 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. 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) + { return tree_algorithms::find(header, key, 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. 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) + { return tree_algorithms::equal_range(header, key, comp); } + + //! 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) + { + tree_algorithms::insert_equal_upper_bound(h, new_node, comp); + rebalance_after_insertion(h, new_node); + 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) + { + tree_algorithms::insert_equal_lower_bound(h, new_node, comp); + rebalance_after_insertion(h, new_node); + 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) + { + tree_algorithms::insert_equal(header, hint, new_node, comp); + rebalance_after_insertion(header, new_node); + return new_node; + } + + //! 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) + { return tree_algorithms::insert_unique_check(header, key, comp, commit_data); } + + //! 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) + { return tree_algorithms::insert_unique_check(header, hint, 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) + { + tree_algorithms::insert_unique_commit(header, new_value, commit_data); + rebalance_after_insertion(header, new_value); + } + + /// @cond + private: + + //! 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_balance(p) == NodeTraits::zero() && tree_algorithms::is_header(p); } + + static void rebalance_after_erasure(node_ptr header, node_ptr x, node_ptr x_parent) + { + node_ptr root = NodeTraits::get_parent(header); + while (x != root) { + const balance x_parent_balance = NodeTraits::get_balance(x_parent); + if(x_parent_balance == NodeTraits::zero()){ + NodeTraits::set_balance(x_parent, + (x == NodeTraits::get_right(x_parent) ? NodeTraits::negative() : NodeTraits::positive())); + break; // the height didn't change, let's stop here + } + else if(x_parent_balance == NodeTraits::negative()){ + if (x == NodeTraits::get_left(x_parent)) { + NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced + x = x_parent; + x_parent = NodeTraits::get_parent(x_parent); + } + else { + // x is right child + // a is left child + node_ptr a = NodeTraits::get_left(x_parent); + assert(a); + if (NodeTraits::get_balance(a) == NodeTraits::positive()) { + // a MUST have a right child + assert(NodeTraits::get_right(a)); + rotate_left_right(x_parent, root); + + x = NodeTraits::get_parent(x_parent); + x_parent = NodeTraits::get_parent(x); + } + else { + rotate_right(x_parent, root); + x = NodeTraits::get_parent(x_parent); + x_parent = NodeTraits::get_parent(x); + + } + + // if changed from negative to NodeTraits::positive(), no need to check above + if (NodeTraits::get_balance(x) == NodeTraits::positive()){ + break; + } + } + } + else if(x_parent_balance == NodeTraits::positive()){ + if (x == NodeTraits::get_right(x_parent)) { + NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced + x = x_parent; + x_parent = NodeTraits::get_parent(x_parent); + } + else { + // x is left child + // a is right child + node_ptr a = NodeTraits::get_right(x_parent); + assert(a); + if (NodeTraits::get_balance(a) == NodeTraits::negative()) { + // a MUST have then a left child + assert(NodeTraits::get_left(a)); + rotate_right_left(x_parent, root); + + x = NodeTraits::get_parent(x_parent); + x_parent = NodeTraits::get_parent(x); + } + else { + rotate_left(x_parent, root); + x = NodeTraits::get_parent(x_parent); + x_parent = NodeTraits::get_parent(x); + } + // if changed from NodeTraits::positive() to negative, no need to check above + if (NodeTraits::get_balance(x) == NodeTraits::negative()){ + break; + } + } + } + else{ + assert(false); // never reached + } + } + NodeTraits::set_parent(header, root); + } + + + static void rebalance_after_insertion(node_ptr header, node_ptr x) + { + node_ptr root = NodeTraits::get_parent(header); + NodeTraits::set_balance(x, NodeTraits::zero()); + + // Rebalance. + while (x != root){ + const balance x_parent_balance = NodeTraits::get_balance(NodeTraits::get_parent(x)); + + if(x_parent_balance == NodeTraits::zero()){ + // if x is left, parent will have parent->bal_factor = negative + // else, parent->bal_factor = NodeTraits::positive() + NodeTraits::set_balance( NodeTraits::get_parent(x) + , x == NodeTraits::get_left(NodeTraits::get_parent(x)) + ? NodeTraits::negative() : NodeTraits::positive() ); + x = NodeTraits::get_parent(x); + } + else if(x_parent_balance == NodeTraits::positive()){ + // if x is a left child, parent->bal_factor = zero + if (x == NodeTraits::get_left(NodeTraits::get_parent(x))) + NodeTraits::set_balance(NodeTraits::get_parent(x), NodeTraits::zero()); + else{ // x is a right child, needs rebalancing + if (NodeTraits::get_balance(x) == NodeTraits::negative()) + rotate_right_left(NodeTraits::get_parent(x), root); + else + rotate_left(NodeTraits::get_parent(x), root); + } + break; + } + else if(x_parent_balance == NodeTraits::negative()){ + // if x is a left child, needs rebalancing + if (x == NodeTraits::get_left(NodeTraits::get_parent(x))) { + if (NodeTraits::get_balance(x) == NodeTraits::positive()) + rotate_left_right(NodeTraits::get_parent(x), root); + else + rotate_right(NodeTraits::get_parent(x), root); + } + else + NodeTraits::set_balance(NodeTraits::get_parent(x), NodeTraits::zero()); + break; + } + else{ + assert(false); // never reached + } + } + NodeTraits::set_parent(header, root); + } + + static void rotate_left_right(node_ptr a, node_ptr &root) + { + // | | // + // a(-2) c // + // / \ / \ // + // / \ ==> / \ // + // (pos)b [g] b a // + // / \ / \ / \ // + // [d] c [d] e f [g] // + // / \ // + // e f // + node_ptr b = NodeTraits::get_left(a), c = NodeTraits::get_right(b); + + // switch + NodeTraits::set_left(a, NodeTraits::get_right(c)); + NodeTraits::set_right(b, NodeTraits::get_left(c)); + + NodeTraits::set_right(c, a); + NodeTraits::set_left(c, b); + + // set the parents + NodeTraits::set_parent(c, NodeTraits::get_parent(a)); + NodeTraits::set_parent(a, c); + NodeTraits::set_parent(b, c); + + if (NodeTraits::get_left(a)) // do we have f? + NodeTraits::set_parent(NodeTraits::get_left(a), a); + if (NodeTraits::get_right(b)) // do we have e? + NodeTraits::set_parent(NodeTraits::get_right(b), b); + + if (a==root) root = c; + else // a had a parent, his child is now c + if (a == NodeTraits::get_left(NodeTraits::get_parent(c))) + NodeTraits::set_left(NodeTraits::get_parent(c), c); + else + NodeTraits::set_right(NodeTraits::get_parent(c), c); + + // balancing... + const balance c_balance = NodeTraits::get_balance(c); + if(c_balance == NodeTraits::negative()){ + NodeTraits::set_balance(a, NodeTraits::positive()); + NodeTraits::set_balance(b, NodeTraits::zero()); + } + else if(c_balance == NodeTraits::zero()){ + NodeTraits::set_balance(a, NodeTraits::zero()); + NodeTraits::set_balance(b, NodeTraits::zero()); + } + else if(c_balance == NodeTraits::positive()){ + NodeTraits::set_balance(a, NodeTraits::zero()); + NodeTraits::set_balance(b, NodeTraits::negative()); + } + else{ + assert(false); // never reached + } + NodeTraits::set_balance(c, NodeTraits::zero()); + } + + static void rotate_right_left(node_ptr a, node_ptr &root) + { + // | | // + // a(pos) c // + // / \ / \ // + // / \ / \ // + // [d] b(neg) ==> a b // + // / \ / \ / \ // + // c [g] [d] e f [g] // + // / \ // + // e f // + node_ptr b = NodeTraits::get_right(a), c = NodeTraits::get_left(b); + + // switch + NodeTraits::set_right(a, NodeTraits::get_left(c)); + NodeTraits::set_left(b, NodeTraits::get_right(c)); + + NodeTraits::set_left(c, a); + NodeTraits::set_right(c, b); + + // set the parents + NodeTraits::set_parent(c, NodeTraits::get_parent(a)); + NodeTraits::set_parent(a, c); + NodeTraits::set_parent(b, c); + + if (NodeTraits::get_right(a)) // do we have e? + NodeTraits::set_parent(NodeTraits::get_right(a), a); + if (NodeTraits::get_left(b)) // do we have f? + NodeTraits::set_parent(NodeTraits::get_left(b), b); + + if (a==root) root = c; + else // a had a parent, his child is now c + if (a == NodeTraits::get_left(NodeTraits::get_parent(c))) + NodeTraits::set_left(NodeTraits::get_parent(c), c); + else + NodeTraits::set_right(NodeTraits::get_parent(c), c); + + // balancing... + const balance c_balance = NodeTraits::get_balance(c); + if(c_balance == NodeTraits::negative()){ + NodeTraits::set_balance(a, NodeTraits::zero()); + NodeTraits::set_balance(b, NodeTraits::positive()); + } + else if(c_balance == NodeTraits::zero()){ + NodeTraits::set_balance(a, NodeTraits::zero()); + NodeTraits::set_balance(b, NodeTraits::zero()); + } + else if(c_balance == NodeTraits::positive()){ + NodeTraits::set_balance(a, NodeTraits::negative()); + NodeTraits::set_balance(b, NodeTraits::zero()); + } + else{ + assert(false); + } + NodeTraits::set_balance(c, NodeTraits::zero()); + } + + static void rotate_left(node_ptr x, node_ptr & root) + { + // | | // + // x(2) y(0) // + // / \ ==> / \ // + // n[a] y(1)n+2 n+1(0)x [c]n+1 // + // / \ / \ // + // n[b] [c]n+1 n[a] [b]n // + node_ptr y = NodeTraits::get_right(x); + + // switch + NodeTraits::set_right(x, NodeTraits::get_left(y)); + NodeTraits::set_left(y, x); + + // rearrange parents + NodeTraits::set_parent(y, NodeTraits::get_parent(x)); + NodeTraits::set_parent(x, y); + + // do we have [b]? + if (NodeTraits::get_right(x)) + NodeTraits::set_parent(NodeTraits::get_right(x), x); + + if (x == root) + root = y; + else + // need to reparent y + if (NodeTraits::get_left(NodeTraits::get_parent(y)) == x) + NodeTraits::set_left(NodeTraits::get_parent(y), y); + else + NodeTraits::set_right(NodeTraits::get_parent(y), y); + + // reset the balancing factor + if (NodeTraits::get_balance(y) == NodeTraits::positive()) { + NodeTraits::set_balance(x, NodeTraits::zero()); + NodeTraits::set_balance(y, NodeTraits::zero()); + } + else { // this doesn't happen during insertions + NodeTraits::set_balance(x, NodeTraits::positive()); + NodeTraits::set_balance(y, NodeTraits::negative()); + } + } + + static void rotate_right(node_ptr x, node_ptr &root) + { + node_ptr y = NodeTraits::get_left(x); + + // switch + NodeTraits::set_left(x, NodeTraits::get_right(y)); + NodeTraits::set_right(y, x); + + // rearrange parents + NodeTraits::set_parent(y, NodeTraits::get_parent(x)); + NodeTraits::set_parent(x, y); + + // do we have [b]? + if (NodeTraits::get_left(x)) + NodeTraits::set_parent(NodeTraits::get_left(x), x); + + if (x == root) + root = y; + else + // need to reparent y + if (NodeTraits::get_left(NodeTraits::get_parent(y)) == x) + NodeTraits::set_left(NodeTraits::get_parent(y), y); + else + NodeTraits::set_right(NodeTraits::get_parent(y), y); + + // reset the balancing factor + if (NodeTraits::get_balance(y) == NodeTraits::negative()) { + NodeTraits::set_balance(x, NodeTraits::zero()); + NodeTraits::set_balance(y, NodeTraits::zero()); + } + else { // this doesn't happen during insertions + NodeTraits::set_balance(x, NodeTraits::negative()); + NodeTraits::set_balance(y, NodeTraits::positive()); + } + } + + /// @endcond +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_AVLTREE_ALGORITHMS_HPP diff --git a/include/boost/intrusive/detail/avltree_node.hpp b/include/boost/intrusive/detail/avltree_node.hpp new file mode 100644 index 0000000..f60f7db --- /dev/null +++ b/include/boost/intrusive/detail/avltree_node.hpp @@ -0,0 +1,179 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 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_AVLTREE_NODE_HPP +#define BOOST_INTRUSIVE_AVLTREE_NODE_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +///////////////////////////////////////////////////////////////////////////// +// // +// Generic node_traits for any pointer type // +// // +///////////////////////////////////////////////////////////////////////////// + +//This is the compact representation: 3 pointers +template +struct compact_avltree_node +{ + typedef typename pointer_to_other + >::type node_ptr; + enum balance { negative_t, zero_t, positive_t }; + node_ptr parent_, left_, right_; +}; + +//This is the normal representation: 3 pointers + enum +template +struct avltree_node +{ + typedef typename pointer_to_other + >::type node_ptr; + enum balance { negative_t, zero_t, positive_t }; + node_ptr parent_, left_, right_; + balance balance_; +}; + +//This is the default node traits implementation +//using a node with 3 generic pointers plus an enum +template +struct default_avltree_node_traits_impl +{ + typedef avltree_node node; + + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef typename node::balance balance; + + 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 balance get_balance(const_node_ptr n) + { return n->balance_; } + + static void set_balance(node_ptr n, balance b) + { n->balance_ = b; } + + static balance negative() + { return node::negative_t; } + + static balance zero() + { return node::zero_t; } + + static balance positive() + { return node::positive_t; } +}; + +//This is the compact node traits implementation +//using a node with 3 generic pointers +template +struct compact_avltree_node_traits_impl +{ + typedef compact_avltree_node node; + typedef typename boost::pointer_to_other + ::type node_ptr; + typedef typename boost::pointer_to_other + ::type const_node_ptr; + typedef typename node::balance balance; + + typedef pointer_plus_2_bits ptr_bit; + + 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 balance get_balance(const_node_ptr n) + { return (balance)ptr_bit::get_bits(n->parent_); } + + static void set_balance(node_ptr n, balance b) + { ptr_bit::set_bits(n->parent_, (std::size_t)b); } + + static balance negative() + { return node::negative_t; } + + static balance zero() + { return node::zero_t; } + + static balance positive() + { return node::positive_t; } +}; + +//Dispatches the implementation based on the boolean +template +struct avltree_node_traits_dispatch + : public default_avltree_node_traits_impl +{}; + +template +struct avltree_node_traits_dispatch + : public compact_avltree_node_traits_impl +{}; + +//Inherit from the detail::link_dispatch depending on the embedding capabilities +template +struct avltree_node_traits + : public avltree_node_traits_dispatch + < VoidPointer + , OptimizeSize && + has_pointer_plus_2_bits + < VoidPointer + , detail::alignment_of >::value + >::value + > +{}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_AVLTREE_NODE_HPP diff --git a/include/boost/intrusive/detail/generic_hook.hpp b/include/boost/intrusive/detail/generic_hook.hpp index 1cd1225..f6e156d 100644 --- a/include/boost/intrusive/detail/generic_hook.hpp +++ b/include/boost/intrusive/detail/generic_hook.hpp @@ -33,6 +33,7 @@ enum , SetBaseHook , UsetBaseHook , SplaySetBaseHook +, AvlSetBaseHook }; struct no_default_definer{}; @@ -52,13 +53,17 @@ template struct default_definer { typedef Hook default_set_hook; }; +template +struct default_definer +{ typedef Hook default_uset_hook; }; + template struct default_definer { typedef Hook default_splay_set_hook; }; template -struct default_definer -{ typedef Hook default_uset_hook; }; +struct default_definer +{ typedef Hook default_avl_set_hook; }; template struct make_default_definer diff --git a/include/boost/intrusive/detail/rbtree_node.hpp b/include/boost/intrusive/detail/rbtree_node.hpp index aba08a2..647c6e5 100644 --- a/include/boost/intrusive/detail/rbtree_node.hpp +++ b/include/boost/intrusive/detail/rbtree_node.hpp @@ -168,131 +168,7 @@ struct rbtree_node_traits >::value > {}; -/* -///////////////////////////////////////////////////////////////////////////// -// // -// Implementation of the rbtree iterator // -// // -///////////////////////////////////////////////////////////////////////////// -// rbtree_iterator provides some basic functions for a -// node oriented bidirectional iterator: -template -class rbtree_iterator - : public std::iterator - < std::bidirectional_iterator_tag - , typename detail::add_const_if_c - ::type - > -{ - protected: - typedef typename Container::real_value_traits real_value_traits; - typedef typename real_value_traits::node_traits node_traits; - typedef typename node_traits::node node; - typedef typename node_traits::node_ptr node_ptr; - typedef rbtree_algorithms node_algorithms; - typedef typename boost::pointer_to_other - ::type void_pointer; - static const bool store_container_ptr = - detail::store_cont_ptr_on_it::value; - - public: - public: - typedef typename detail::add_const_if_c - - ::type value_type; - typedef value_type & reference; - typedef value_type * pointer; - - rbtree_iterator() - : members_ (0, 0) - {} - - explicit rbtree_iterator(node_ptr node, const Container *cont_ptr) - : members_ (node, cont_ptr) - {} - - rbtree_iterator(rbtree_iterator const& other) - : members_(other.pointed_node(), other.get_container()) - {} - - const node_ptr &pointed_node() const - { return members_.nodeptr_; } - - rbtree_iterator &operator=(const node_ptr &node) - { members_.nodeptr_ = node; return static_cast(*this); } - - public: - rbtree_iterator& operator++() - { - members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_); - return static_cast (*this); - } - - rbtree_iterator operator++(int) - { - rbtree_iterator result (*this); - members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_); - return result; - } - - rbtree_iterator& operator--() - { - members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_); - return static_cast (*this); - } - - rbtree_iterator operator--(int) - { - rbtree_iterator result (*this); - members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_); - return result; - } - - bool operator== (const rbtree_iterator& i) const - { return members_.nodeptr_ == i.pointed_node(); } - - bool operator!= (const rbtree_iterator& i) const - { return !operator== (i); } - - value_type& operator*() const - { return *operator->(); } - - pointer operator->() const - { return detail::get_pointer(this->get_real_value_traits()->to_value_ptr(members_.nodeptr_)); } - - const Container *get_container() const - { - if(store_container_ptr) - return static_cast(members_.get_ptr()); - else - return 0; - } - - const real_value_traits *get_real_value_traits() const - { - if(store_container_ptr) - return &this->get_container()->get_real_value_traits(); - else - return 0; - } - - private: - struct members - : public detail::select_constptr - ::type - { - typedef typename detail::select_constptr - ::type Base; - - members(const node_ptr &n_ptr, const void *cont) - : Base(cont), nodeptr_(n_ptr) - {} - - node_ptr nodeptr_; - } members_; -}; -*/ } //namespace intrusive } //namespace boost diff --git a/include/boost/intrusive/detail/tree_algorithms.hpp b/include/boost/intrusive/detail/tree_algorithms.hpp index 423f9fc..471aa5a 100644 --- a/include/boost/intrusive/detail/tree_algorithms.hpp +++ b/include/boost/intrusive/detail/tree_algorithms.hpp @@ -693,8 +693,7 @@ class tree_algorithms { node_ptr end = uncast(header); node_ptr y = lower_bound(header, key, comp); - node_ptr r = (y == end || comp(key, y)) ? end : y; - return r; + return (y == end || comp(key, y)) ? end : y; } //! Requires: "header" must be the header node of a tree. @@ -1243,16 +1242,39 @@ class tree_algorithms // delete node | complexity : constant | exception : nothrow static void erase(node_ptr header, node_ptr z) - { erase(header, z, nop_erase_fixup()); } + { + data_for_rebalance ignored; + erase(header, z, nop_erase_fixup(), ignored); + } struct data_for_rebalance { node_ptr x; node_ptr x_parent; + node_ptr y; }; template - static void erase(node_ptr header, node_ptr z, F z_and_successor_fixup, data_for_rebalance * info = 0) + static void erase(node_ptr header, node_ptr z, F z_and_successor_fixup, data_for_rebalance &info) + { + erase_impl(header, z, info); + if(info.y != z){ + z_and_successor_fixup(z, info.y); + } + } + + static void unlink(node_ptr node) + { + node_ptr x = NodeTraits::get_parent(node); + if(x){ + while(!is_header(x)) + x = NodeTraits::get_parent(x); + erase(x, node); + } + } + + private: + static void erase_impl(node_ptr header, node_ptr z, data_for_rebalance &info) { node_ptr y(z); node_ptr x; @@ -1287,7 +1309,6 @@ class tree_algorithms x_parent = y; tree_algorithms::replace_own (z, y, header); NodeTraits::set_parent(y, NodeTraits::get_parent(z)); - z_and_successor_fixup(z, y); } else { // y == z --> z has only one child, or none x_parent = NodeTraits::get_parent(z); @@ -1305,22 +1326,12 @@ class tree_algorithms tree_algorithms::maximum(x)); } } - - if(info){ - info->x = x; - info->x_parent = x_parent; - } + + info.x = x; + info.x_parent = x_parent; + info.y = y; } - static void unlink(node_ptr node) - { - node_ptr x = NodeTraits::get_parent(node); - if(x){ - while(!is_header(x)) - x = NodeTraits::get_parent(x); - erase(x, node); - } - } }; } //namespace detail { diff --git a/include/boost/intrusive/intrusive_fwd.hpp b/include/boost/intrusive/intrusive_fwd.hpp index 04b1f8c..49c6526 100644 --- a/include/boost/intrusive/intrusive_fwd.hpp +++ b/include/boost/intrusive/intrusive_fwd.hpp @@ -195,6 +195,50 @@ template > class splay_set_member_hook; +//avltree/avl_set/avl_multiset +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class avltree; + +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class avl_set; + +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class avl_multiset; + +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class avl_set_base_hook; + +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +class avl_set_member_hook; + //hash/unordered //rbtree/set/multiset template diff --git a/include/boost/intrusive/pointer_plus_2_bits.hpp b/include/boost/intrusive/pointer_plus_2_bits.hpp new file mode 100644 index 0000000..c7d9592 --- /dev/null +++ b/include/boost/intrusive/pointer_plus_2_bits.hpp @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 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_2_BIT_HPP +#define BOOST_INTRUSIVE_POINTER_PLUS_2_BIT_HPP + +namespace boost { +namespace intrusive { + +//!This trait class is used to know if a pointer +//!can embed 2 extra bits of information if +//!it's going to be used to point to objects +//!with an alignment of "Alignment" bytes. +template +struct has_pointer_plus_2_bits +{ + static const bool value = false; +}; + +//!This is an specialization for raw pointers. +//!Raw pointers can embed two extra bits in the lower bits +//!if the alignment is multiple of 4. +template +struct has_pointer_plus_2_bits +{ + static const bool value = (N % 4u == 0); +}; + +//!This is class that is supposed to have static methods +//!to embed 2 extra bits of information in a pointer. +//! +//!This is a declaration and there is no default implementation, +//!because operations to embed bits change with every pointer type. +//! +//!An implementation that detects that a pointer type whose +//!has_pointer_plus_2_bits<>::value is non-zero can make use of these +//!operations to embed bits in the pointer. +template +struct pointer_plus_2_bits +{ + static const bool value = false; +}; + +//!This is the specialization to embed 2 extra bits of information +//!in a raw pointer. Extra bits are stored in the lower bits of the pointer. +template +struct pointer_plus_2_bits +{ + typedef T* pointer; + + static pointer get_pointer(pointer n) + { return pointer(std::size_t(n) & ~std::size_t(3u)); } + + static void set_pointer(pointer &n, pointer p) + { + assert(0 == (std::size_t(p) & std::size_t(3u))); + n = pointer(std::size_t(p) | (std::size_t(n) & std::size_t(3u))); + } + + static std::size_t get_bits(pointer n) + { return (std::size_t(n) & std::size_t(3u)); } + + static void set_bits(pointer &n, std::size_t c) + { + assert(c < 4); + n = pointer(std::size_t(get_pointer(n)) | c); + } +}; + +} //namespace intrusive +} //namespace boost + +#endif //BOOST_INTRUSIVE_POINTER_PLUS_2_BIT_HPP diff --git a/include/boost/intrusive/rbtree_algorithms.hpp b/include/boost/intrusive/rbtree_algorithms.hpp index 43ebaa7..76b4486 100644 --- a/include/boost/intrusive/rbtree_algorithms.hpp +++ b/include/boost/intrusive/rbtree_algorithms.hpp @@ -393,7 +393,7 @@ class rbtree_algorithms static node_ptr erase(node_ptr header, node_ptr z) { typename tree_algorithms::data_for_rebalance info; - tree_algorithms::erase(header, z, rbtree_erase_fixup(), &info); + tree_algorithms::erase(header, z, rbtree_erase_fixup(), info); node_ptr x = info.x; node_ptr x_parent = info.x_parent;