Advanced lookup and insertions in ordered associative containers now support comparison functions that are not required to offer the same strict weak ordering as key_compare, the container must be partitioned in regards to the passed comparison object. This fixed Boost Trac #11701 ("Regression in boost::intrusive::set::equal_range")

This commit is contained in:
Ion Gaztañaga
2015-10-07 23:28:03 +02:00
parent dda91f0e00
commit b11720f527
8 changed files with 95 additions and 124 deletions

View File

@@ -1942,15 +1942,18 @@ the same options explained in the section
[section:advanced_lookups Advanced lookups]
[*Boost.Intrusive] associative containers offer the same interface as STL associative
containers. However, STL and TR1 ordered and unordered simple associative containers
(`std::set`, `std::multiset`, `std::tr1::unordered_set` and `std::tr1::unordered_multiset`)
have some inefficiencies caused by the interface: the user can only operate with `value_type`
objects. When using these containers we must use `iterator find(const value_type &value)`
to find a value. The same happens in other functions
like `equal_range`, `lower_bound`, `upper_bound`, etc.
[*Boost.Intrusive] associative containers offer an interface similar to STL associative
containers. However, STL's ordered and unordered simple associative containers
(`std::set`, `std::multiset`, `std::unordered_set` and `std::unordered_multiset`)
have some inefficiencies caused by the interface in several search functions
(`equal_range`, `lower_bound`, `upper_bound`, ...): the user can only operate with
`value_type` objects or (starting from C++11),
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3657.htm heterogeneous comparison lookups]
which are not flexible enough as `key_compare` shall support the comparison between the provided
key and `value_type`, avoiding the use of user-defined comparison objects that can partition the
search in advanced ways.
However, sometimes the object to be searched is quite expensive to construct:
Imagine that the object to be searched is quite expensive to construct:
[import ../example/doc_assoc_optimized_code.cpp]
[doc_assoc_optimized_code_normal_find]
@@ -1968,15 +1971,16 @@ equivalent one.
Sometimes this interface limitation is severe, because
we [*might not have enough information to construct the object] but we might
[*have enough information to find the object]. In this case, a name is enough
to search `Expensive` in the container but constructing an `Expensive`
might require more information that the user might not have.
to search `Expensive` in the container but constructing an `Expensive` object
might requires more information that the user might not have.
To solve this, [classref boost::intrusive::set set]/[classref boost::intrusive::multiset multiset]
To solve this, [*Boost.Intrusive] associative containers
offer alternative functions, which take any type comparable with the value and a
functor that should be compatible with the
ordering function of the associative container.
functor that should be `compatible`
(the associative container must be also partitioned in regards to the supplied comparison type)
with container's predicate function (`key_compare`).
[classref boost::intrusive::unordered_set unordered_set]/[classref boost::intrusive::unordered_multiset unordered_multiset]
offers functions that take any key type and compatible hash and equality functions. Now, let's see the
offer similar functions that take any key type, a compatible hash (the hash of the key) and a equality function. Now, let's see
optimized search function:
[doc_assoc_optimized_code_optimized_find]
@@ -3819,6 +3823,16 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std
[section:release_notes Release Notes]
[section:release_notes_boost_1_60_00 Boost 1.60 Release]
* [link intrusive.advanced_lookups_insertions Advanced lookup and insertions] in ordered associative containers
now support comparison functions that are not required to offer the same strict weak ordering as `key_compare`,
the container must be partitioned in regards to the passed comparison object.
* Fixed bugs:
* [@https://svn.boost.org/trac/boost/ticket/11701 Boost Trac #11701: ['Regression in boost::intrusive::set::equal_range]]
[endsect]
[section:release_notes_boost_1_59_00 Boost 1.59 Release]
* Implemented [link intrusive.map_multimap map and multimap-like interfaces].

View File

@@ -328,7 +328,7 @@ class avl_set_impl
//! @copydoc ::boost::intrusive::rbtree::equal_range(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyTypeKeyCompare comp)
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
//! @copydoc ::boost::intrusive::rbtree::equal_range(const key_type &)const
std::pair<const_iterator, const_iterator>
@@ -339,7 +339,7 @@ class avl_set_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyTypeKeyCompare comp) const
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED

View File

@@ -325,7 +325,7 @@ class bs_set_impl
//! @copydoc ::boost::intrusive::bstree::equal_range(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyTypeKeyCompare comp)
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
//! @copydoc ::boost::intrusive::bstree::equal_range(const key_type &)const
std::pair<const_iterator, const_iterator>
@@ -336,7 +336,7 @@ class bs_set_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyTypeKeyCompare comp) const
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED

View File

@@ -1385,6 +1385,10 @@ class bstree_impl
size_type erase(const key_type &key)
{ return this->erase(key, this->key_comp()); }
//! <b>Requires</b>: key is a value such that `*this` is partitioned with respect to
//! comp(nk, key) and !c(key, nk), with c(nk, key) implying !c(key, nk),
//! with nk the key_type of a value_type inserted into `*this`.
//!
//! <b>Effects</b>: Erases all the elements with the given key.
//! according to the comparison functor "comp".
//!
@@ -1465,6 +1469,10 @@ class bstree_impl
iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer)
{ size_type n; return this->private_erase(b, e, n, disposer); }
//! <b>Requires</b>: key is a value such that `*this` is partitioned with respect to
//! comp(nk, key) and !c(key, nk), with c(nk, key) implying !c(key, nk)
//! and nk the key_type of a value_type inserted into `*this`.
//!
//! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
//!
//! <b>Effects</b>: Erases all the elements with the given key.
@@ -1537,6 +1545,10 @@ class bstree_impl
size_type count(const key_type &key) const
{ return size_type(this->count(key, this->key_comp())); }
//! <b>Requires</b>: key is a value such that `*this` is partitioned with respect to
//! comp(nk, key) and !c(key, nk), with c(nk, key) implying !c(key, nk),
//! and nk the key_type of a value_type inserted into `*this`.
//!
//! <b>Effects</b>: Returns the number of contained elements with the given key
//!
//! <b>Complexity</b>: Logarithmic to the number of elements contained plus lineal
@@ -1586,21 +1598,11 @@ class bstree_impl
//! <b>Throws</b>: If `key_compare` throws.
const_iterator lower_bound(const key_type &key) const;
//! <b>Effects</b>: Returns an iterator to the first element whose
//! key is not less than k or end() if that element does not exist.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `comp` throws.
//! @copydoc ::boost::intrusive::bstree::lower_bound(const key_type &)
template<class KeyType, class KeyTypeKeyCompare>
iterator lower_bound(const KeyType &key, KeyTypeKeyCompare comp);
//! <b>Effects</b>: Returns a const iterator to the first element whose
//! key is not less than k or end() if that element does not exist.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `comp` throws.
//! @copydoc ::boost::intrusive::bstree::lower_bound(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
const_iterator lower_bound(const KeyType &key, KeyTypeKeyCompare comp) const;
@@ -1612,6 +1614,9 @@ class bstree_impl
//! <b>Throws</b>: If `key_compare` throws.
iterator upper_bound(const key_type &key);
//! <b>Requires</b>: key is a value such that `*this` is partitioned with respect to
//! !comp(key, nk), with nk the key_type of a value_type inserted into `*this`.
//!
//! <b>Effects</b>: Returns an iterator to the first element whose
//! key is greater than k according to comp or end() if that element
//! does not exist.
@@ -1622,21 +1627,10 @@ class bstree_impl
template<class KeyType, class KeyTypeKeyCompare>
iterator upper_bound(const KeyType &key, KeyTypeKeyCompare comp);
//! <b>Effects</b>: Returns an iterator to the first element whose
//! key is greater than k or end() if that element does not exist.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `key_compare` throws.
//! @copydoc ::boost::intrusive::bstree::upper_bound(const key_type &)
const_iterator upper_bound(const key_type &key) const;
//! <b>Effects</b>: Returns an iterator to the first element whose
//! key is greater than k according to comp or end() if that element
//! does not exist.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `comp` throws.
//! @copydoc ::boost::intrusive::bstree::upper_bound(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
const_iterator upper_bound(const KeyType &key, KeyTypeKeyCompare comp) const;
@@ -1648,6 +1642,10 @@ class bstree_impl
//! <b>Throws</b>: If `key_compare` throws.
iterator find(const key_type &key);
//! <b>Requires</b>: key is a value such that `*this` is partitioned with respect to
//! comp(nk, key) and !c(key, nk), with c(nk, key) implying !c(key, nk),
//! and nk the key_type of a value_type inserted into `*this`.
//!
//! <b>Effects</b>: Finds an iterator to the first element whose key is
//! k or end() if that element does not exist.
//!
@@ -1657,20 +1655,10 @@ class bstree_impl
template<class KeyType, class KeyTypeKeyCompare>
iterator find(const KeyType &key, KeyTypeKeyCompare comp);
//! <b>Effects</b>: Finds a const_iterator to the first element whose key is
//! k or end() if that element does not exist.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `key_compare` throws.
//! @copydoc ::boost::intrusive::bstree::find(const key_type &)
const_iterator find(const key_type &key) const;
//! <b>Effects</b>: Finds a const_iterator to the first element whose key is
//! k or end() if that element does not exist.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `comp` throws.
//! @copydoc ::boost::intrusive::bstree::find(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
const_iterator find(const KeyType &key, KeyTypeKeyCompare comp) const;
@@ -1683,6 +1671,10 @@ class bstree_impl
//! <b>Throws</b>: If `key_compare` throws.
std::pair<iterator,iterator> equal_range(const key_type &key);
//! <b>Requires</b>: key is a value such that `*this` is partitioned with respect to
//! comp(nk, key) and !c(key, nk), with c(nk, key) implying !c(key, nk),
//! with nk the key_type of a value_type inserted into `*this`.
//!
//! <b>Effects</b>: 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.
@@ -1693,29 +1685,21 @@ class bstree_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> equal_range(const KeyType &key, KeyTypeKeyCompare comp);
//! <b>Effects</b>: 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.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `key_compare` throws.
std::pair<const_iterator, const_iterator>
equal_range(const key_type &key) const;
//! @copydoc ::boost::intrusive::bstree::equal_range(const key_type &)
std::pair<const_iterator, const_iterator> equal_range(const key_type &key) const;
//! <b>Effects</b>: 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.
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `comp` throws.
//! @copydoc ::boost::intrusive::bstree::equal_range(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType &key, KeyTypeKeyCompare comp) const;
//! <b>Requires</b>: 'lower_key' must not be greater than 'upper_key'. If
//! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false.
//! <b>Requires</b>:
//! `upper_key` shall not precede `lower_key` according to key_compare.
//! [key_comp()(upper_key, lower_key) shall be false]
//!
//! If `lower_key` is equivalent to `upper_key`
//! [!key_comp()(upper_key, lower_key) && !key_comp()(lower_key, upper_key)] then
//! ('left_closed' || 'right_closed') must be false.
//!
//! <b>Effects</b>: Returns an a pair with the following criteria:
//!
@@ -1734,11 +1718,19 @@ class bstree_impl
std::pair<iterator,iterator> bounded_range
(const key_type &lower_key, const key_type &upper_value, bool left_closed, bool right_closed);
//! <b>Requires</b>: KeyTypeKeyCompare is a function object that induces a strict weak
//! ordering compatible with the strict weak ordering used to create the
//! the container.
//! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If
//! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false.
//! <b>Requires</b>:
//! `lower_key` is a value such that `*this` is partitioned with respect to
//! comp(nk, lower_key) if left_closed is true, with respect to !comp(lower_key, nk) otherwise.
//!
//! `upper_key` is a value such that `*this` is partitioned with respect to
//! !comp(upper_key, nk) if right_closed is true, with respect to comp(nk, upper_key) otherwise.
//!
//! `upper_key` shall not precede `lower_key` according to comp
//! [comp(upper_key, lower_key) shall be false]
//!
//! If `lower_key` is equivalent to `upper_key`
//! [!comp(upper_key, lower_key) && !comp(lower_key, upper_key)] then
//! ('left_closed' || 'right_closed') must be false.
//!
//! <b>Effects</b>: Returns an a pair with the following criteria:
//!
@@ -1757,47 +1749,12 @@ class bstree_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> bounded_range
(const KeyType &lower_key, const KeyType &upper_key, KeyTypeKeyCompare comp, bool left_closed, bool right_closed);
//! <b>Requires</b>: 'lower_key' must not be greater than 'upper_key'. If
//! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false.
//!
//! <b>Effects</b>: Returns an a pair with the following criteria:
//!
//! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise
//!
//! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `key_compare` throws.
//!
//! <b>Note</b>: This function can be more efficient than calling upper_bound
//! and lower_bound for lower_value and upper_value.
//!
//! <b>Note</b>: Experimental function, the interface might change in future releases.
//! @copydoc ::boost::intrusive::bstree::bounded_range(const key_type &,const key_type &,bool,bool)
std::pair<const_iterator,const_iterator> bounded_range
(const key_type &lower_key, const key_type &upper_key, bool left_closed, bool right_closed) const;
//! <b>Requires</b>: KeyTypeKeyCompare is a function object that induces a strict weak
//! ordering compatible with the strict weak ordering used to create the
//! the container.
//! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If
//! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false.
//!
//! <b>Effects</b>: Returns an a pair with the following criteria:
//!
//! first = lower_bound(lower_key, comp) if left_closed, upper_bound(lower_key, comp) otherwise
//!
//! second = upper_bound(upper_key, comp) if right_closed, lower_bound(upper_key, comp) otherwise
//!
//! <b>Complexity</b>: Logarithmic.
//!
//! <b>Throws</b>: If `comp` throws.
//!
//! <b>Note</b>: This function can be more efficient than calling upper_bound
//! and lower_bound for lower_key and upper_key.
//!
//! <b>Note</b>: Experimental function, the interface might change in future releases.
//! @copydoc ::boost::intrusive::bstree::bounded_range(const KeyType&,const KeyType&,KeyTypeKeyCompare,bool,bool)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator,const_iterator> bounded_range
(const KeyType &lower_key, const KeyType &upper_key, KeyTypeKeyCompare comp, bool left_closed, bool right_closed) const;

View File

@@ -328,7 +328,7 @@ class set_impl
//! @copydoc ::boost::intrusive::rbtree::equal_range(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyTypeKeyCompare comp)
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
//! @copydoc ::boost::intrusive::rbtree::equal_range(const key_type &)const
std::pair<const_iterator, const_iterator>
@@ -339,7 +339,7 @@ class set_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyTypeKeyCompare comp) const
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED

View File

@@ -326,7 +326,7 @@ class sg_set_impl
//! @copydoc ::boost::intrusive::rbtree::equal_range(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyTypeKeyCompare comp)
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
//! @copydoc ::boost::intrusive::rbtree::equal_range(const key_type &)const
std::pair<const_iterator, const_iterator>
@@ -337,7 +337,7 @@ class sg_set_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyTypeKeyCompare comp) const
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED

View File

@@ -333,7 +333,7 @@ class splay_set_impl
//! @copydoc ::boost::intrusive::rbtree::equal_range(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyTypeKeyCompare comp)
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
//! @copydoc ::boost::intrusive::rbtree::equal_range(const key_type &)const
std::pair<const_iterator, const_iterator>
@@ -344,7 +344,7 @@ class splay_set_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyTypeKeyCompare comp) const
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED

View File

@@ -375,7 +375,7 @@ class treap_set_impl
//! @copydoc ::boost::intrusive::rbtree::equal_range(const KeyType&,KeyTypeKeyCompare)
template<class KeyType, class KeyTypeKeyCompare>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyTypeKeyCompare comp)
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
//! @copydoc ::boost::intrusive::rbtree::equal_range(const key_type &)const
std::pair<const_iterator, const_iterator>
@@ -386,7 +386,7 @@ class treap_set_impl
template<class KeyType, class KeyTypeKeyCompare>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyTypeKeyCompare comp) const
{ return this->tree_type::lower_bound_range(key, comp); }
{ return this->tree_type::equal_range(key, comp); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED