Implemented C++14's heterogeneous lookups.

This commit is contained in:
Ion Gaztañaga
2018-05-01 14:55:24 +02:00
parent 04b0791593
commit 48c21e3187
14 changed files with 1298 additions and 153 deletions

View File

@@ -1,5 +1,5 @@
[/
/ Copyright (c) 2009-2013 Ion Gazta\u00F1aga
/ Copyright (c) 2009-2018 Ion Gazta\u00F1aga
/
/ 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)
@@ -8,7 +8,7 @@
[library Boost.Container
[quickbook 1.5]
[authors [Gaztanaga, Ion]]
[copyright 2009-2017 Ion Gaztanaga]
[copyright 2009-2018 Ion Gaztanaga]
[id container]
[dirname container]
[purpose Containers library]
@@ -62,7 +62,7 @@ There is no need to compile [*Boost.Container], since it's a header-only library
just include your Boost header directory in your compiler include path *except if you use*:
* [link container.extended_allocators Extended Allocators]
* Some [link container.polymorphic_memory_resources Polymorphic Memory Resources] classes.
* Some [link container.cpp_conformance.polymorphic_memory_resources Polymorphic Memory Resources] classes.
Those exceptions are are implemented as a separately compiled library, so in those cases you must install binaries
in a location that can be found by your linker.
@@ -166,6 +166,10 @@ the effects are undefined in the following cases: (...) In particular - if an in
is used as a template argument when instantiating a template component,
unless specifically allowed for that component]].
Finally C++17 added support for incomplete types in `std::vector`, `std::list` and `std::forward_list`
(see [@https://wg21.link/n4569 ['N4569: Minimal incomplete type support for standard containers, revision 4]]
for details), but no other containers like `std::set/map/unordered_set/unordered_map`,
Fortunately all [*Boost.Container] containers except
[classref boost::container::static_vector static_vector] and
[classref boost::container::small_vector small_vector] and
@@ -745,130 +749,12 @@ Use them simply specifying the new allocator in the corresponding template argum
[endsect]
[section:polymorphic_memory_resources Extended Functionality: Polymorphic Memory Resources ]
The document
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html C++ Extensions for Library Fundamentals (Final draft: N4480)]
includes classes that provide allocator type erasure and runtime polymorphism. As Pablo Halpern, the author of the proposal,
explains in the paper ([@https://isocpp.org/files/papers/N3916.pdf N3916 Polymorphic Memory Resources (r2)]):
["['A significant impediment to effective memory management in C++ has been the
inability to use allocators in non-generic contexts. In large software systems,
most of the application program consists of non-generic procedural or
object-oriented code that is compiled once and linked many times.]]
["['Allocators in C++, however, have historically relied solely on
compile-time polymorphism, and therefore have not been suitable for use in vocabulary
types, which are passed through interfaces between separately-compiled modules,
because the allocator type necessarily affects the type of the object that uses it.
This proposal builds upon the improvements made to allocators in
C++11 and describes a set of facilities for runtime polymorphic memory
resources that interoperate with the existing compile-time polymorphic
allocators.]]
[*Boost.Container] implements nearly all classes of the proposal under
the namespace `boost::container::pmr`. There are two groups,
* Header only utilities (these don't require the separately compiled library):
* [classref boost::container::pmr::memory_resource memory_resource].
* [classref boost::container::pmr::resource_adaptor resource_adaptor].
* Utilities that require the the separately compiled library:
* [classref boost::container::pmr::polymorphic_allocator polymorphic_allocator].
* [classref boost::container::pmr::monotonic_buffer_resource monotonic_buffer_resource].
* [classref boost::container::pmr::unsynchronized_pool_resource unsynchronized_pool_resource].
* [classref boost::container::pmr::synchronized_pool_resource synchronized_pool_resource].
* Global resource functions: [funcref boost::container::pmr::get_default_resource get_default_resource]/
[funcref boost::container::pmr::set_default_resource set_default_resource]/
[funcref boost::container::pmr::new_delete_resource new_delete_resource]/
[funcref boost::container::pmr::null_memory_resource null_memory_resource]
* Aliases for boost containers using the polymorphic allocator
(like [classref boost::container::pmr::vector pmr::vector], etc.)
[*Boost.Container]'s polymorphic resource library is usable from C++03 containers,
and offers some alternative utilities if the required C++11 features of the
['Library Fundamentals] specification are not available.
[import ../example/doc_pmr.cpp]
Let's review the usage example given in
[@https://isocpp.org/files/papers/N3916.pdf N3916] and see how it can be implemented
using [*Boost.Container]: ['Suppose we are processing a series of shopping lists, where a shopping list is a
container of strings, and storing them in a collection (a list) of shopping lists.
Each shopping list being processed uses a bounded amount of memory that is needed for
a short period of time, while the collection of shopping lists uses an unbounded
amount of memory and will exist for a longer period of time. For efficiency, we can
use a more time-efficient memory allocator based on a finite buffer for the temporary
shopping lists.]
Let's see how `ShoppingList` can be defined to support an polymorphic memory resource
that can allocate memory from different underlying mechanisms. The most important
details are:
* It should declare that supports an allocator defining an `allocator_type` typedef.
This `allocator_type` will be of type [classref boost::container::pmr::memory_resource memory_resource *],
which is a base class for polymorphic resources.
* It must define constructors that take the
the allocator as argument. It can be implemented in two ways:
* `ShoppingList` has constructors taking
[classref boost::container::pmr::memory_resource memory_resource*] as the last argument.
* `ShoppingList` has constructors taking
[classref boost::container::allocator_arg_t allocator_arg_t] as the first argument
and [classref boost::container::pmr::memory_resource memory_resource*] as the second argument.
[*Note:] ['In C++03 compilers, it is required that the programmer specializes as `true`
[classref boost::container::constructible_with_allocator_suffix constructible_with_allocator_suffix] or
[classref boost::container::constructible_with_allocator_prefix constructible_with_allocator_prefix]
as in C++03 there is no way to automatically detect the chosen option at compile time. If
no specialization is done, [*Boost.Container] assumes the suffix option].
[doc_pmr_ShoppingList_hpp]
['However, this time-efficient allocator is not appropriate for the longer
lived collection of shopping lists. This example shows how those temporary shopping
lists, using a time-efficient allocator, can be used to populate the long lived collection
of shopping lists, using a general purpose allocator, something that would be
annoyingly difficult without the polymorphic allocators.]
In [*Boost.Container] for the time-efficient allocation we can use
[classref boost::container::pmr::monotonic_buffer_resource monotonic_buffer_resource],
providing an external buffer that will be used until it's exhausted. In the default
configuration, when the buffer is exhausted, the default memory resource will be used
instead.
[doc_pmr_main_cpp]
['Notice that the shopping lists within `folder` use the default allocator resource
whereas the shopping list `temporaryShoppingList` uses the short-lived but very fast
`buf_rsrc`. Despite using different allocators, you can insert
`temporaryShoppingList` into folder because they have the same `ShoppingList`
type. Also, while `ShoppingList` uses memory_resource directly,
[classref boost::container::pmr::list pmr::list],
[classref boost::container::pmr::vector pmr::vector]
and [classref boost::container::pmr::string pmr::string] all use
[classref boost::container::pmr::polymorphic_allocator polymorphic_allocator].]
['The resource passed to the `ShoppingList` constructor is propagated to the vector and
each string within that `ShoppingList`. Similarly, the resource used to construct
`folder` is propagated to the constructors of the ShoppingLists that are inserted into
the list (and to the strings within those `ShoppingLists`). The
[classref boost::container::pmr::polymorphic_allocator polymorphic_allocator]
template is designed to be almost interchangeable with a pointer to
[classref boost::container::pmr::memory_resource memory_resource],
thus producing a ['bridge] between the template-policy
style of allocator and the polymorphic-base-class style of allocator.]
This example actually shows how easy is to use [*Boost.Container] to write
type-erasured allocator-capable classes even in C++03 compilers.
[endsect]
[section:Cpp11_conformance C++11/C++14 Conformance]
[section:cpp_conformance C++11/C++14/C++17 Conformance]
[*Boost.Container] aims for full C++11 conformance except reasoned deviations,
backporting as much as possible for C++03. Obviously, this conformance is a work
in progress so this section explains what C++11 features are implemented and which of them
have been backported to C++03 compilers.
in progress so this section explains what C++11/C++14/C++17 features are implemented and which
of them have been backported to earlier standard conformig compilers.
[section:move_emplace Move and Emplace]
@@ -985,6 +871,128 @@ past the end of the same empty sequence (example taken from N3644):
[endsect]
[section:polymorphic_memory_resources Polymorphic Memory Resources ]
The document
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html C++ Extensions for Library Fundamentals (final draft)]
includes classes that provide allocator type erasure and runtime polymorphism. As Pablo Halpern, the author of the proposal,
explains in the paper ([@https://isocpp.org/files/papers/N3916.pdf N3916 Polymorphic Memory Resources (r2)]):
["['A significant impediment to effective memory management in C++ has been the
inability to use allocators in non-generic contexts. In large software systems,
most of the application program consists of non-generic procedural or
object-oriented code that is compiled once and linked many times.]]
["['Allocators in C++, however, have historically relied solely on
compile-time polymorphism, and therefore have not been suitable for use in vocabulary
types, which are passed through interfaces between separately-compiled modules,
because the allocator type necessarily affects the type of the object that uses it.
This proposal builds upon the improvements made to allocators in
C++11 and describes a set of facilities for runtime polymorphic memory
resources that interoperate with the existing compile-time polymorphic
allocators.]]
Most utilities from the Fundamentals TS were merged into C++17, but
[*Boost.Container] offers them for C++03, C++11 and C++14 compilers.
[*Boost.Container] implements nearly all classes of the proposal under
the namespace `boost::container::pmr`. There are two groups,
* Header only utilities (these don't require the separately compiled library):
* [classref boost::container::pmr::memory_resource memory_resource].
* [classref boost::container::pmr::resource_adaptor resource_adaptor].
* Utilities that require the the separately compiled library:
* [classref boost::container::pmr::polymorphic_allocator polymorphic_allocator].
* [classref boost::container::pmr::monotonic_buffer_resource monotonic_buffer_resource].
* [classref boost::container::pmr::unsynchronized_pool_resource unsynchronized_pool_resource].
* [classref boost::container::pmr::synchronized_pool_resource synchronized_pool_resource].
* Global resource functions: [funcref boost::container::pmr::get_default_resource get_default_resource]/
[funcref boost::container::pmr::set_default_resource set_default_resource]/
[funcref boost::container::pmr::new_delete_resource new_delete_resource]/
[funcref boost::container::pmr::null_memory_resource null_memory_resource]
* Aliases for boost containers using the polymorphic allocator
(like [classref boost::container::pmr::vector pmr::vector], etc.)
[*Boost.Container]'s polymorphic resource library is usable from C++03 containers,
and offers some alternative utilities if the required C++11 features of the
['Library Fundamentals] specification are not available.
[import ../example/doc_pmr.cpp]
Let's review the usage example given in
[@https://isocpp.org/files/papers/N3916.pdf N3916] and see how it can be implemented
using [*Boost.Container]: ['Suppose we are processing a series of shopping lists, where a shopping list is a
container of strings, and storing them in a collection (a list) of shopping lists.
Each shopping list being processed uses a bounded amount of memory that is needed for
a short period of time, while the collection of shopping lists uses an unbounded
amount of memory and will exist for a longer period of time. For efficiency, we can
use a more time-efficient memory allocator based on a finite buffer for the temporary
shopping lists.]
Let's see how `ShoppingList` can be defined to support an polymorphic memory resource
that can allocate memory from different underlying mechanisms. The most important
details are:
* It should declare that supports an allocator defining an `allocator_type` typedef.
This `allocator_type` will be of type [classref boost::container::pmr::memory_resource memory_resource *],
which is a base class for polymorphic resources.
* It must define constructors that take the
the allocator as argument. It can be implemented in two ways:
* `ShoppingList` has constructors taking
[classref boost::container::pmr::memory_resource memory_resource*] as the last argument.
* `ShoppingList` has constructors taking
[classref boost::container::allocator_arg_t allocator_arg_t] as the first argument
and [classref boost::container::pmr::memory_resource memory_resource*] as the second argument.
[*Note:] ['In C++03 compilers, it is required that the programmer specializes as `true`
[classref boost::container::constructible_with_allocator_suffix constructible_with_allocator_suffix] or
[classref boost::container::constructible_with_allocator_prefix constructible_with_allocator_prefix]
as in C++03 there is no way to automatically detect the chosen option at compile time. If
no specialization is done, [*Boost.Container] assumes the suffix option].
[doc_pmr_ShoppingList_hpp]
['However, this time-efficient allocator is not appropriate for the longer
lived collection of shopping lists. This example shows how those temporary shopping
lists, using a time-efficient allocator, can be used to populate the long lived collection
of shopping lists, using a general purpose allocator, something that would be
annoyingly difficult without the polymorphic allocators.]
In [*Boost.Container] for the time-efficient allocation we can use
[classref boost::container::pmr::monotonic_buffer_resource monotonic_buffer_resource],
providing an external buffer that will be used until it's exhausted. In the default
configuration, when the buffer is exhausted, the default memory resource will be used
instead.
[doc_pmr_main_cpp]
['Notice that the shopping lists within `folder` use the default allocator resource
whereas the shopping list `temporaryShoppingList` uses the short-lived but very fast
`buf_rsrc`. Despite using different allocators, you can insert
`temporaryShoppingList` into folder because they have the same `ShoppingList`
type. Also, while `ShoppingList` uses memory_resource directly,
[classref boost::container::pmr::list pmr::list],
[classref boost::container::pmr::vector pmr::vector]
and [classref boost::container::pmr::string pmr::string] all use
[classref boost::container::pmr::polymorphic_allocator polymorphic_allocator].]
['The resource passed to the `ShoppingList` constructor is propagated to the vector and
each string within that `ShoppingList`. Similarly, the resource used to construct
`folder` is propagated to the constructors of the ShoppingLists that are inserted into
the list (and to the strings within those `ShoppingLists`). The
[classref boost::container::pmr::polymorphic_allocator polymorphic_allocator]
template is designed to be almost interchangeable with a pointer to
[classref boost::container::pmr::memory_resource memory_resource],
thus producing a ['bridge] between the template-policy
style of allocator and the polymorphic-base-class style of allocator.]
This example actually shows how easy is to use [*Boost.Container] to write
type-erasured allocator-capable classes even in C++03 compilers.
[endsect]
[section:forward_list `forward_list<T>`]
[*Boost.Container] does not offer C++11 `forward_list` container yet, but it will be available in future
@@ -1172,10 +1180,10 @@ collect them containers and build [*Boost.Container], a library targeted to a wi
With so many high quality standard library implementations out there, why would you want to
use [*Boost.Container]? There are several reasons for that:
* If you have a C++03 compiler, you can have access to C++11 features and have an easy
code migration when you change your compiler.
* Even if you have a earlier standard conforming compiler, you still can have access to many
of the latest C++ standard features and have an easy code migration when you change your compiler.
* It's compatible with [*Boost.Interprocess] shared memory allocators.
* You have extremely useful new containers like `stable_vector` and `flat_[multi]set/map`.
* You have extremely useful new containers like `[stable/static/small]_vector` and `flat_[multi]set/map`.
* If you work on multiple platforms, you'll have a portable behaviour without depending
on the std-lib implementation conformance of each platform. Some examples:
* Default constructors don't allocate memory at all, which improves performance and
@@ -1237,6 +1245,8 @@ use [*Boost.Container]? There are several reasons for that:
* Improved correctness of [classref boost::container::adaptive_pool adaptive_pool] and many parameters are now compile-time
constants instead of runtime constants.
* Implemented C++14's heterogeneous lookup functions for `[multi]map/[multi]set/flat_[multi]map/flat_[multi]set`.
* Fixed bugs:
* [@https://svn.boost.org/trac/boost/ticket/13533 Trac #13533: ['"Boost vector resize causes assert(false)"]].
@@ -1348,7 +1358,7 @@ use [*Boost.Container]? There are several reasons for that:
[section:release_notes_boost_1_60_00 Boost 1.60 Release]
* Implemented [link container.polymorphic_memory_resources Polymorphic Memory Resources].
* Implemented [link container.cpp_conformance.polymorphic_memory_resources Polymorphic Memory Resources].
* Add more BOOST_ASSERT checks to test preconditions in some operations (like `pop_back`, `pop_front`, `back`, `front`, etc.)
* Added C++11 `back`/`front` operations to [classref boost::container::basic_string basic_string].
* Fixed bugs:

View File

@@ -1160,7 +1160,31 @@ class flat_tree
return i;
}
// set operations:
template<class K>
typename dtl::enable_if_transparent<key_compare, K, iterator>::type
find(const K& k)
{
iterator i = this->lower_bound(k);
iterator end_it = this->end();
if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
i = end_it;
}
return i;
}
template<class K>
typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
find(const K& k) const
{
const_iterator i = this->lower_bound(k);
const_iterator end_it = this->cend();
if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){
i = end_it;
}
return i;
}
size_type count(const key_type& k) const
{
std::pair<const_iterator, const_iterator> p = this->equal_range(k);
@@ -1168,6 +1192,15 @@ class flat_tree
return n;
}
template<class K>
typename dtl::enable_if_transparent<key_compare, K, size_type>::type
count(const K& k) const
{
std::pair<const_iterator, const_iterator> p = this->equal_range(k);
size_type n = p.second - p.first;
return n;
}
template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source)
{
@@ -1212,24 +1245,73 @@ class flat_tree
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const
{ return this->priv_lower_bound(this->cbegin(), this->cend(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, iterator>::type
lower_bound(const K& k)
{ return this->priv_lower_bound(this->begin(), this->end(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
lower_bound(const K& k) const
{ return this->priv_lower_bound(this->cbegin(), this->cend(), k); }
BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k)
{ return this->priv_upper_bound(this->begin(), this->end(), k); }
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const
{ return this->priv_upper_bound(this->cbegin(), this->cend(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K,iterator>::type
upper_bound(const K& k)
{ return this->priv_upper_bound(this->begin(), this->end(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K,const_iterator>::type
upper_bound(const K& k) const
{ return this->priv_upper_bound(this->cbegin(), this->cend(), k); }
BOOST_CONTAINER_FORCEINLINE std::pair<iterator,iterator> equal_range(const key_type& k)
{ return this->priv_equal_range(this->begin(), this->end(), k); }
BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
{ return this->priv_equal_range(this->cbegin(), this->cend(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K,std::pair<iterator,iterator> >::type
equal_range(const K& k)
{ return this->priv_equal_range(this->begin(), this->end(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type
equal_range(const K& k) const
{ return this->priv_equal_range(this->cbegin(), this->cend(), k); }
BOOST_CONTAINER_FORCEINLINE std::pair<iterator, iterator> lower_bound_range(const key_type& k)
{ return this->priv_lower_bound_range(this->begin(), this->end(), k); }
BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const
{ return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K,std::pair<iterator,iterator> >::type
lower_bound_range(const K& k)
{ return this->priv_lower_bound_range(this->begin(), this->end(), k); }
template<class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type
lower_bound_range(const K& k) const
{ return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); }
BOOST_CONTAINER_FORCEINLINE size_type capacity() const
{
const bool value = boost::container::dtl::
@@ -1419,9 +1501,9 @@ class flat_tree
, boost::forward<Convertible>(convertible));
}
template <class RanIt>
template <class RanIt, class K>
RanIt priv_lower_bound(RanIt first, const RanIt last,
const key_type & key) const
const K & key) const
{
const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract;
@@ -1444,9 +1526,9 @@ class flat_tree
return first;
}
template <class RanIt>
template <class RanIt, class K>
RanIt priv_upper_bound
(RanIt first, const RanIt last,const key_type & key) const
(RanIt first, const RanIt last,const K & key) const
{
const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract;
@@ -1469,9 +1551,9 @@ class flat_tree
return first;
}
template <class RanIt>
template <class RanIt, class K>
std::pair<RanIt, RanIt>
priv_equal_range(RanIt first, RanIt last, const key_type& key) const
priv_equal_range(RanIt first, RanIt last, const K& key) const
{
const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract;
@@ -1502,8 +1584,8 @@ class flat_tree
return std::pair<RanIt, RanIt>(first, first);
}
template<class RanIt>
std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const key_type& k) const
template<class RanIt, class K>
std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const K& k) const
{
const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract;

View File

@@ -76,6 +76,24 @@ struct select1st
{ return const_cast<type&>(x.first); }
};
template <class T, class=void>
struct is_transparent
{
static const bool value = false;
};
template <class T>
struct is_transparent<T, typename T::is_transparent>
{
static const bool value = true;
};
template <typename C, typename K, typename R>
struct enable_if_transparent
: boost::move_detail::enable_if_c<dtl::is_transparent<C>::value, R>
{};
} //namespace dtl {
} //namespace container {
} //namespace boost {

View File

@@ -394,6 +394,7 @@ class RecyclingCloner
intrusive_container &m_icont;
};
template<class KeyCompare, class KeyOfValue>
struct key_node_compare
: public boost::intrusive::detail::ebo_functor_holder<KeyCompare>
@@ -407,6 +408,21 @@ struct key_node_compare
typedef KeyOfValue key_of_value;
typedef typename KeyOfValue::type key_type;
template <class T, class VoidPointer, boost::container::tree_type_enum tree_type_value, bool OptimizeSize>
BOOST_CONTAINER_FORCEINLINE static const key_type &
key_from(const tree_node<T, VoidPointer, tree_type_value, OptimizeSize> &n)
{
return key_of_value()(n.get_data());
}
template <class T>
BOOST_CONTAINER_FORCEINLINE static const T &
key_from(const T &t)
{
return t;
}
BOOST_CONTAINER_FORCEINLINE const key_compare &key_comp() const
{ return static_cast<const key_compare &>(*this); }
@@ -418,15 +434,15 @@ struct key_node_compare
template<class U>
BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const U &nonkey2) const
{ return this->key_comp()(key1, key_of_value()(nonkey2.get_data())); }
{ return this->key_comp()(key1, this->key_from(nonkey2)); }
template<class U>
BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const key_type &key2) const
{ return this->key_comp()(key_of_value()(nonkey1.get_data()), key2); }
{ return this->key_comp()(this->key_from(nonkey1), key2); }
template<class U, class V>
BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const V &nonkey2) const
{ return this->key_comp()(key_of_value()(nonkey1.get_data()), key_of_value()(nonkey2.get_data())); }
{ return this->key_comp()(this->key_from(nonkey1), this->key_from(nonkey2)); }
};
template<class Options>
@@ -1260,21 +1276,63 @@ class tree
BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& k) const
{ return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(key_comp()))); }
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, iterator>::type
find(const K& k)
{ return iterator(this->icont().find(k, KeyNodeCompare(key_comp()))); }
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
find(const K& k) const
{ return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(key_comp()))); }
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& k) const
{ return size_type(this->icont().count(k, KeyNodeCompare(key_comp()))); }
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, size_type>::type
count(const K& k) const
{ return size_type(this->icont().count(k, KeyNodeCompare(key_comp()))); }
BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k)
{ return iterator(this->icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const
{ return const_iterator(this->non_const_icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, iterator>::type
lower_bound(const K& k)
{ return iterator(this->icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
lower_bound(const K& k) const
{ return const_iterator(this->non_const_icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k)
{ return iterator(this->icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const
{ return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, iterator>::type
upper_bound(const K& k)
{ return iterator(this->icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type
upper_bound(const K& k) const
{ return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
std::pair<iterator,iterator> equal_range(const key_type& k)
{
std::pair<iiterator, iiterator> ret =
@@ -1290,6 +1348,27 @@ class tree
(const_iterator(ret.first), const_iterator(ret.second));
}
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, std::pair<iterator,iterator> >::type
equal_range(const K& k)
{
std::pair<iiterator, iiterator> ret =
this->icont().equal_range(k, KeyNodeCompare(key_comp()));
return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
}
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, std::pair<const_iterator, const_iterator> >::type
equal_range(const K& k) const
{
std::pair<iiterator, iiterator> ret =
this->non_const_icont().equal_range(k, KeyNodeCompare(key_comp()));
return std::pair<const_iterator,const_iterator>
(const_iterator(ret.first), const_iterator(ret.second));
}
std::pair<iterator,iterator> lower_bound_range(const key_type& k)
{
std::pair<iiterator, iiterator> ret =
@@ -1305,6 +1384,27 @@ class tree
(const_iterator(ret.first), const_iterator(ret.second));
}
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, std::pair<iterator,iterator> >::type
lower_bound_range(const K& k)
{
std::pair<iiterator, iiterator> ret =
this->icont().lower_bound_range(k, KeyNodeCompare(key_comp()));
return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
}
template <class K>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if_transparent<key_compare, K, std::pair<const_iterator, const_iterator> >::type
lower_bound_range(const K& k) const
{
std::pair<iiterator, iiterator> ret =
this->non_const_icont().lower_bound_range(k, KeyNodeCompare(key_comp()));
return std::pair<const_iterator,const_iterator>
(const_iterator(ret.first), const_iterator(ret.second));
}
BOOST_CONTAINER_FORCEINLINE void rebalance()
{ intrusive_tree_proxy_t::rebalance(this->icont()); }

View File

@@ -1302,12 +1302,44 @@ class flat_map
BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE iterator find(const K& x)
{ return dtl::force_copy<iterator>(m_flat_tree.find(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const_iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE const_iterator find(const K& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); }
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const
{ return static_cast<size_type>(m_flat_tree.find(x) != m_flat_tree.end()); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
template<class K>
BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const
{ return static_cast<size_type>(m_flat_tree.find(x) != m_flat_tree.end()); }
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
@@ -1322,6 +1354,28 @@ class flat_map
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const K& x)
{ return dtl::force_copy<iterator>(m_flat_tree.lower_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); }
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
@@ -1336,6 +1390,28 @@ class flat_map
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const K& x)
{ return dtl::force_copy<iterator>(m_flat_tree.upper_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const K& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); }
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic.
@@ -1348,6 +1424,26 @@ class flat_map
BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const
{ return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.lower_bound_range(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE std::pair<iterator,iterator> equal_range(const K& x)
{ return dtl::force_copy<std::pair<iterator,iterator> >(m_flat_tree.lower_bound_range(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const K& x) const
{ return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.lower_bound_range(x)); }
//! <b>Effects</b>: Extracts the internal sequence container.
//!
//! <b>Complexity</b>: Same as the move constructor of sequence_type, usually constant.
@@ -2443,12 +2539,44 @@ class flat_multimap
BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE iterator find(const K& x)
{ return dtl::force_copy<iterator>(m_flat_tree.find(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An const_iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<class K>
BOOST_CONTAINER_FORCEINLINE const_iterator find(const K& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); }
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const
{ return m_flat_tree.count(x); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
template<class K>
BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const
{ return m_flat_tree.count(x); }
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
@@ -2456,12 +2584,34 @@ class flat_multimap
BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& x)
{ return dtl::force_copy<iterator>(m_flat_tree.lower_bound(x)); }
//! <b>Returns</b>: A const iterator pointing to the first element with key
//! not less than k, or a.end() if such an element is not found.
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); }
{ return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<class K>
BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const K& x)
{ return dtl::force_copy<iterator>(m_flat_tree.lower_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<class K>
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); }
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
@@ -2477,6 +2627,28 @@ class flat_multimap
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<class K>
BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const K& x)
{return dtl::force_copy<iterator>(m_flat_tree.upper_bound(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key
//! not less than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<class K>
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const K& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); }
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
@@ -2489,6 +2661,26 @@ class flat_multimap
BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const
{ return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<class K>
BOOST_CONTAINER_FORCEINLINE std::pair<iterator,iterator> equal_range(const K& x)
{ return dtl::force_copy<std::pair<iterator,iterator> >(m_flat_tree.equal_range(x)); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<class K>
BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const K& x) const
{ return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); }
//! <b>Effects</b>: Extracts the internal sequence container.
//!
//! <b>Complexity</b>: Same as the move constructor of sequence_type, usually constant.

View File

@@ -823,6 +823,26 @@ class flat_set
//! <b>Complexity</b>: Logarithmic.
const_iterator find(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
iterator find(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const_iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
const_iterator find(const K& x) const;
//! <b>Requires</b>: size() >= n.
//!
//! <b>Effects</b>: Returns an iterator to the nth element
@@ -881,6 +901,16 @@ class flat_set
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const
{ return static_cast<size_type>(this->tree_t::find(x) != this->tree_t::cend()); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
template<typename K>
BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const
{ return static_cast<size_type>(this->tree_t::find(x) != this->tree_t::cend()); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
@@ -894,6 +924,26 @@ class flat_set
//! <b>Complexity</b>: Logarithmic
const_iterator lower_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator lower_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator lower_bound(const K& x) const;
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
@@ -906,6 +956,26 @@ class flat_set
//! <b>Complexity</b>: Logarithmic
const_iterator upper_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator upper_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator upper_bound(const K& x) const;
#endif // #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
@@ -920,6 +990,26 @@ class flat_set
BOOST_CONTAINER_FORCEINLINE std::pair<iterator,iterator> equal_range(const key_type& x)
{ return this->tree_t::lower_bound_range(x); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<iterator,iterator> equal_range(const K& x)
{ return this->tree_t::lower_bound_range(x); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<const_iterator,const_iterator> equal_range(const K& x) const
{ return this->tree_t::lower_bound_range(x); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Returns true if x and y are equal

View File

@@ -1079,6 +1079,26 @@ class map
//! <b>Complexity</b>: Logarithmic.
const_iterator find(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
iterator find(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const_iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
const_iterator find(const K& x) const;
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Returns</b>: The number of elements with key equivalent to x.
@@ -1087,6 +1107,16 @@ class map
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const
{ return static_cast<size_type>(this->find(x) != this->cend()); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
template<typename K>
BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const
{ return static_cast<size_type>(this->find(x) != this->cend()); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Returns</b>: An iterator pointing to the first element with key not less
@@ -1101,6 +1131,26 @@ class map
//! <b>Complexity</b>: Logarithmic
const_iterator lower_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator lower_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator lower_bound(const K& x) const;
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
@@ -1113,6 +1163,26 @@ class map
//! <b>Complexity</b>: Logarithmic
const_iterator upper_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator upper_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator upper_bound(const K& x) const;
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
@@ -1123,6 +1193,24 @@ class map
//! <b>Complexity</b>: Logarithmic
std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<iterator,iterator> equal_range(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<const_iterator,const_iterator> equal_range(const K& x) const;
//! <b>Effects</b>: Rebalances the tree. It's a no-op for Red-Black and AVL trees.
//!
//! <b>Complexity</b>: Linear
@@ -1841,11 +1929,40 @@ class multimap
//! <b>Complexity</b>: Logarithmic.
const_iterator find(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
iterator find(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const_iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
const_iterator find(const K& x) const;
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
size_type count(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
template<typename K>
size_type count(const K& x) const;
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
@@ -1858,6 +1975,26 @@ class multimap
//! <b>Complexity</b>: Logarithmic
const_iterator lower_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator lower_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator lower_bound(const K& x) const;
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
@@ -1870,6 +2007,26 @@ class multimap
//! <b>Complexity</b>: Logarithmic
const_iterator upper_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator upper_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator upper_bound(const K& x) const;
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
@@ -1880,6 +2037,24 @@ class multimap
//! <b>Complexity</b>: Logarithmic
std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<iterator,iterator> equal_range(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<const_iterator,const_iterator> equal_range(const K& x) const;
//! <b>Effects</b>: Rebalances the tree. It's a no-op for Red-Black and AVL trees.
//!
//! <b>Complexity</b>: Linear

View File

@@ -734,6 +734,26 @@ class set
//! <b>Complexity</b>: Logarithmic.
const_iterator find(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
iterator find(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const_iterator pointing to an element with the key
//! equivalent to x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic.
template<typename K>
const_iterator find(const K& x) const;
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Returns</b>: The number of elements with key equivalent to x.
@@ -742,6 +762,16 @@ class set
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const
{ return static_cast<size_type>(this->base_t::find(x) != this->base_t::cend()); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
template<typename K>
BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const
{ return static_cast<size_type>(this->find(x) != this->cend()); }
//! <b>Returns</b>: The number of elements with key equivalent to x.
//!
//! <b>Complexity</b>: log(size())+count(k)
@@ -762,6 +792,26 @@ class set
//! <b>Complexity</b>: Logarithmic
const_iterator lower_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator lower_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than k, or a.end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator lower_bound(const K& x) const;
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
@@ -774,6 +824,26 @@ class set
//! <b>Complexity</b>: Logarithmic
const_iterator upper_bound(const key_type& x) const;
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: An iterator pointing to the first element with key not less
//! than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
iterator upper_bound(const K& x);
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Returns</b>: A const iterator pointing to the first element with key not
//! less than x, or end() if such an element is not found.
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
const_iterator upper_bound(const K& x) const;
#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
@@ -788,18 +858,28 @@ class set
BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const
{ return this->base_t::lower_bound_range(x); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<iterator,iterator> equal_range(const K& x)
{ return this->base_t::lower_bound_range(x); }
//! <b>Requires</b>: This overload is available only if
//! key_compare::is_transparent exists.
//!
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
template<typename K>
std::pair<const_iterator,const_iterator> equal_range(const K& x) const
{ return this->base_t::lower_bound_range(x); }
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
std::pair<iterator,iterator> equal_range(const key_type& x);
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//!
//! <b>Complexity</b>: Logarithmic
std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
//! <b>Effects</b>: Rebalances the tree. It's a no-op for Red-Black and AVL trees.
//!
//! <b>Complexity</b>: Linear
@@ -1330,27 +1410,63 @@ class multiset
//! @copydoc ::boost::container::set::find(const key_type& ) const
const_iterator find(const key_type& x) const;
//! @copydoc ::boost::container::set::find(const K& )
template<typename K>
iterator find(const K& x);
//! @copydoc ::boost::container::set::find(const K& )
template<typename K>
const_iterator find(const K& x) const;
//! @copydoc ::boost::container::set::count(const key_type& ) const
size_type count(const key_type& x) const;
//! @copydoc ::boost::container::set::count(const K& ) const
template<typename K>
size_type count(const K& x) const;
//! @copydoc ::boost::container::set::lower_bound(const key_type& )
iterator lower_bound(const key_type& x);
//! @copydoc ::boost::container::set::lower_bound(const key_type& ) const
const_iterator lower_bound(const key_type& x) const;
//! @copydoc ::boost::container::set::lower_bound(const K& )
template<typename K>
iterator lower_bound(const K& x);
//! @copydoc ::boost::container::set::lower_bound(const K& ) const
template<typename K>
const_iterator lower_bound(const K& x) const;
//! @copydoc ::boost::container::set::upper_bound(const key_type& )
iterator upper_bound(const key_type& x);
//! @copydoc ::boost::container::set::upper_bound(const key_type& ) const
const_iterator upper_bound(const key_type& x) const;
//! @copydoc ::boost::container::set::upper_bound(const K& )
template<typename K>
iterator upper_bound(const K& x);
//! @copydoc ::boost::container::set::upper_bound(const K& ) const
template<typename K>
const_iterator upper_bound(const K& x) const;
//! @copydoc ::boost::container::set::equal_range(const key_type& ) const
std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
//! @copydoc ::boost::container::set::equal_range(const key_type& )
std::pair<iterator,iterator> equal_range(const key_type& x);
//! @copydoc ::boost::container::set::equal_range(const K& ) const
template<typename K>
std::pair<const_iterator, const_iterator> equal_range(const K& x) const;
//! @copydoc ::boost::container::set::equal_range(const K& )
template<typename K>
std::pair<iterator,iterator> equal_range(const K& x);
//! @copydoc ::boost::container::set::rebalance()
void rebalance();

View File

@@ -108,6 +108,17 @@ bool CheckEqualPairContainers(const MyBoostCont &boostcont, const MyStdCont &std
return true;
}
struct less_transparent
{
typedef void is_transparent;
template<class T, class U>
bool operator()(const T &t, const U &u) const
{
return t < u;
}
};
} //namespace test{
} //namespace container {
} //namespace boost{

View File

@@ -422,6 +422,85 @@ struct get_real_stored_allocator<flat_multimap<Key, T, Compare, Allocator> >
typedef typename flat_multimap<Key, T, Compare, Allocator>::impl_stored_allocator_type type;
};
bool test_heterogeneous_lookups()
{
typedef flat_map<int, char, less_transparent> map_t;
typedef flat_multimap<int, char, less_transparent> mmap_t;
typedef map_t::value_type value_type;
map_t map1;
mmap_t mmap1;
const map_t &cmap1 = map1;
const mmap_t &cmmap1 = mmap1;
map1.insert_or_assign(1, 'a');
map1.insert_or_assign(1, 'b');
map1.insert_or_assign(2, 'c');
map1.insert_or_assign(2, 'd');
map1.insert_or_assign(3, 'e');
mmap1.insert(value_type(1, 'a'));
mmap1.insert(value_type(1, 'b'));
mmap1.insert(value_type(2, 'c'));
mmap1.insert(value_type(2, 'd'));
mmap1.insert(value_type(3, 'e'));
const test::non_copymovable_int find_me(2);
//find
if(map1.find(find_me)->second != 'd')
return false;
if(cmap1.find(find_me)->second != 'd')
return false;
if(mmap1.find(find_me)->second != 'c')
return false;
if(cmmap1.find(find_me)->second != 'c')
return false;
//count
if(map1.count(find_me) != 1)
return false;
if(cmap1.count(find_me) != 1)
return false;
if(mmap1.count(find_me) != 2)
return false;
if(cmmap1.count(find_me) != 2)
return false;
//lower_bound
if(map1.lower_bound(find_me)->second != 'd')
return false;
if(cmap1.lower_bound(find_me)->second != 'd')
return false;
if(mmap1.lower_bound(find_me)->second != 'c')
return false;
if(cmmap1.lower_bound(find_me)->second != 'c')
return false;
//upper_bound
if(map1.upper_bound(find_me)->second != 'e')
return false;
if(cmap1.upper_bound(find_me)->second != 'e')
return false;
if(mmap1.upper_bound(find_me)->second != 'e')
return false;
if(cmmap1.upper_bound(find_me)->second != 'e')
return false;
//equal_range
if(map1.equal_range(find_me).first->second != 'd')
return false;
if(cmap1.equal_range(find_me).second->second != 'e')
return false;
if(mmap1.equal_range(find_me).first->second != 'c')
return false;
if(cmmap1.equal_range(find_me).second->second != 'e')
return false;
return true;
}
}}} //namespace boost::container::test
template<class VoidAllocatorOrContainer>
@@ -527,6 +606,9 @@ int main()
if (!boost::container::test::instantiate_constructors<flat_map<int, int>, flat_multimap<int, int> >())
return 1;
if (!test_heterogeneous_lookups())
return 1;
////////////////////////////////////
// Testing allocator implementations
////////////////////////////////////

View File

@@ -450,6 +450,84 @@ bool flat_tree_extract_adopt_test()
return true;
}
bool test_heterogeneous_lookups()
{
typedef flat_set<int, test::less_transparent> set_t;
typedef flat_multiset<int, test::less_transparent> mset_t;
set_t set1;
mset_t mset1;
const set_t &cset1 = set1;
const mset_t &cmset1 = mset1;
set1.insert(1);
set1.insert(1);
set1.insert(2);
set1.insert(2);
set1.insert(3);
mset1.insert(1);
mset1.insert(1);
mset1.insert(2);
mset1.insert(2);
mset1.insert(3);
const test::non_copymovable_int find_me(2);
//find
if(*set1.find(find_me) != 2)
return false;
if(*cset1.find(find_me) != 2)
return false;
if(*mset1.find(find_me) != 2)
return false;
if(*cmset1.find(find_me) != 2)
return false;
//count
if(set1.count(find_me) != 1)
return false;
if(cset1.count(find_me) != 1)
return false;
if(mset1.count(find_me) != 2)
return false;
if(cmset1.count(find_me) != 2)
return false;
//lower_bound
if(*set1.lower_bound(find_me) != 2)
return false;
if(*cset1.lower_bound(find_me) != 2)
return false;
if(*mset1.lower_bound(find_me) != 2)
return false;
if(*cmset1.lower_bound(find_me) != 2)
return false;
//upper_bound
if(*set1.upper_bound(find_me) != 3)
return false;
if(*cset1.upper_bound(find_me) != 3)
return false;
if(*mset1.upper_bound(find_me) != 3)
return false;
if(*cmset1.upper_bound(find_me) != 3)
return false;
//equal_range
if(*set1.equal_range(find_me).first != 2)
return false;
if(*cset1.equal_range(find_me).second != 3)
return false;
if(*mset1.equal_range(find_me).first != 2)
return false;
if(*cmset1.equal_range(find_me).second != 3)
return false;
return true;
}
}}}
template<class VoidAllocatorOrContainer>
@@ -636,6 +714,10 @@ int main()
if (!boost::container::test::instantiate_constructors<flat_set<int>, flat_multiset<int> >())
return 1;
if(!test_heterogeneous_lookups()){
return 1;
}
////////////////////////////////////
// Testing allocator implementations
////////////////////////////////////

View File

@@ -320,6 +320,85 @@ void test_merge_from_different_comparison()
map1.merge(map2);
}
bool test_heterogeneous_lookups()
{
typedef map<int, char, less_transparent> map_t;
typedef multimap<int, char, less_transparent> mmap_t;
typedef map_t::value_type value_type;
map_t map1;
mmap_t mmap1;
const map_t &cmap1 = map1;
const mmap_t &cmmap1 = mmap1;
map1.insert_or_assign(1, 'a');
map1.insert_or_assign(1, 'b');
map1.insert_or_assign(2, 'c');
map1.insert_or_assign(2, 'd');
map1.insert_or_assign(3, 'e');
mmap1.insert(value_type(1, 'a'));
mmap1.insert(value_type(1, 'b'));
mmap1.insert(value_type(2, 'c'));
mmap1.insert(value_type(2, 'd'));
mmap1.insert(value_type(3, 'e'));
const test::non_copymovable_int find_me(2);
//find
if(map1.find(find_me)->second != 'd')
return false;
if(cmap1.find(find_me)->second != 'd')
return false;
if(mmap1.find(find_me)->second != 'c')
return false;
if(cmmap1.find(find_me)->second != 'c')
return false;
//count
if(map1.count(find_me) != 1)
return false;
if(cmap1.count(find_me) != 1)
return false;
if(mmap1.count(find_me) != 2)
return false;
if(cmmap1.count(find_me) != 2)
return false;
//lower_bound
if(map1.lower_bound(find_me)->second != 'd')
return false;
if(cmap1.lower_bound(find_me)->second != 'd')
return false;
if(mmap1.lower_bound(find_me)->second != 'c')
return false;
if(cmmap1.lower_bound(find_me)->second != 'c')
return false;
//upper_bound
if(map1.upper_bound(find_me)->second != 'e')
return false;
if(cmap1.upper_bound(find_me)->second != 'e')
return false;
if(mmap1.upper_bound(find_me)->second != 'e')
return false;
if(cmmap1.upper_bound(find_me)->second != 'e')
return false;
//equal_range
if(map1.equal_range(find_me).first->second != 'd')
return false;
if(cmap1.equal_range(find_me).second->second != 'e')
return false;
if(mmap1.equal_range(find_me).first->second != 'c')
return false;
if(cmmap1.equal_range(find_me).second->second != 'e')
return false;
return true;
}
}}} //namespace boost::container::test
int main ()
@@ -437,6 +516,9 @@ int main ()
test::test_merge_from_different_comparison();
if(!test::test_heterogeneous_lookups())
return 1;
////////////////////////////////////
// Test optimize_size option
////////////////////////////////////

View File

@@ -97,6 +97,12 @@ class movable_int
friend bool operator==(int l, const movable_int &r)
{ return l == r.get_int(); }
friend bool operator<(const movable_int &l, int r)
{ return l.get_int() < r; }
friend bool operator<(int l, const movable_int &r)
{ return l < r.get_int(); }
private:
int m_int;
};
@@ -193,6 +199,12 @@ class movable_and_copyable_int
friend bool operator==(int l, const movable_and_copyable_int &r)
{ return l == r.get_int(); }
friend bool operator<(const movable_and_copyable_int &l, int r)
{ return l.get_int() < r; }
friend bool operator<(int l, const movable_and_copyable_int &r)
{ return l < r.get_int(); }
private:
int m_int;
};
@@ -280,6 +292,12 @@ class copyable_int
friend bool operator==(int l, const copyable_int &r)
{ return l == r.get_int(); }
friend bool operator<(const copyable_int &l, int r)
{ return l.get_int() < r; }
friend bool operator<(int l, const copyable_int &r)
{ return l < r.get_int(); }
private:
int m_int;
};
@@ -351,6 +369,12 @@ class non_copymovable_int
friend bool operator==(int l, const non_copymovable_int &r)
{ return l == r.get_int(); }
friend bool operator<(const non_copymovable_int &l, int r)
{ return l.get_int() < r; }
friend bool operator<(int l, const non_copymovable_int &r)
{ return l < r.get_int(); }
private:
int m_int;
};

View File

@@ -318,6 +318,84 @@ void test_merge_from_different_comparison()
set1.merge(set2);
}
bool test_heterogeneous_lookups()
{
typedef set<int, test::less_transparent> set_t;
typedef multiset<int, test::less_transparent> mset_t;
set_t set1;
mset_t mset1;
const set_t &cset1 = set1;
const mset_t &cmset1 = mset1;
set1.insert(1);
set1.insert(1);
set1.insert(2);
set1.insert(2);
set1.insert(3);
mset1.insert(1);
mset1.insert(1);
mset1.insert(2);
mset1.insert(2);
mset1.insert(3);
const test::non_copymovable_int find_me(2);
//find
if(*set1.find(find_me) != 2)
return false;
if(*cset1.find(find_me) != 2)
return false;
if(*mset1.find(find_me) != 2)
return false;
if(*cmset1.find(find_me) != 2)
return false;
//count
if(set1.count(find_me) != 1)
return false;
if(cset1.count(find_me) != 1)
return false;
if(mset1.count(find_me) != 2)
return false;
if(cmset1.count(find_me) != 2)
return false;
//lower_bound
if(*set1.lower_bound(find_me) != 2)
return false;
if(*cset1.lower_bound(find_me) != 2)
return false;
if(*mset1.lower_bound(find_me) != 2)
return false;
if(*cmset1.lower_bound(find_me) != 2)
return false;
//upper_bound
if(*set1.upper_bound(find_me) != 3)
return false;
if(*cset1.upper_bound(find_me) != 3)
return false;
if(*mset1.upper_bound(find_me) != 3)
return false;
if(*cmset1.upper_bound(find_me) != 3)
return false;
//equal_range
if(*set1.equal_range(find_me).first != 2)
return false;
if(*cset1.equal_range(find_me).second != 3)
return false;
if(*mset1.equal_range(find_me).first != 2)
return false;
if(*cmset1.equal_range(find_me).second != 3)
return false;
return true;
}
int main ()
{
//Recursive container instantiation
@@ -349,6 +427,9 @@ int main ()
test_merge_from_different_comparison();
if(!test_heterogeneous_lookups())
return 1;
////////////////////////////////////
// Testing allocator implementations
////////////////////////////////////