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 / 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) / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -8,7 +8,7 @@
[library Boost.Container [library Boost.Container
[quickbook 1.5] [quickbook 1.5]
[authors [Gaztanaga, Ion]] [authors [Gaztanaga, Ion]]
[copyright 2009-2017 Ion Gaztanaga] [copyright 2009-2018 Ion Gaztanaga]
[id container] [id container]
[dirname container] [dirname container]
[purpose Containers library] [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*: just include your Boost header directory in your compiler include path *except if you use*:
* [link container.extended_allocators Extended Allocators] * [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 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. 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, is used as a template argument when instantiating a template component,
unless specifically allowed for that 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 Fortunately all [*Boost.Container] containers except
[classref boost::container::static_vector static_vector] and [classref boost::container::static_vector static_vector] and
[classref boost::container::small_vector small_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] [endsect]
[section:polymorphic_memory_resources Extended Functionality: Polymorphic Memory Resources ] [section:cpp_conformance C++11/C++14/C++17 Conformance]
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]
[*Boost.Container] aims for full C++11 conformance except reasoned deviations, [*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 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 in progress so this section explains what C++11/C++14/C++17 features are implemented and which
have been backported to C++03 compilers. of them have been backported to earlier standard conformig compilers.
[section:move_emplace Move and Emplace] [section:move_emplace Move and Emplace]
@@ -985,6 +871,128 @@ past the end of the same empty sequence (example taken from N3644):
[endsect] [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>`] [section:forward_list `forward_list<T>`]
[*Boost.Container] does not offer C++11 `forward_list` container yet, but it will be available in future [*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 With so many high quality standard library implementations out there, why would you want to
use [*Boost.Container]? There are several reasons for that: 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 * Even if you have a earlier standard conforming compiler, you still can have access to many
code migration when you change your compiler. 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. * 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 * 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: on the std-lib implementation conformance of each platform. Some examples:
* Default constructors don't allocate memory at all, which improves performance and * 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 * Improved correctness of [classref boost::container::adaptive_pool adaptive_pool] and many parameters are now compile-time
constants instead of runtime constants. 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: * Fixed bugs:
* [@https://svn.boost.org/trac/boost/ticket/13533 Trac #13533: ['"Boost vector resize causes assert(false)"]]. * [@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] [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.) * 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]. * Added C++11 `back`/`front` operations to [classref boost::container::basic_string basic_string].
* Fixed bugs: * Fixed bugs:

View File

@@ -1160,7 +1160,31 @@ class flat_tree
return i; 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 size_type count(const key_type& k) const
{ {
std::pair<const_iterator, const_iterator> p = this->equal_range(k); std::pair<const_iterator, const_iterator> p = this->equal_range(k);
@@ -1168,6 +1192,15 @@ class flat_tree
return n; 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> template<class C2>
BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source) 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 BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const
{ return this->priv_lower_bound(this->cbegin(), this->cend(), k); } { 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) BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k)
{ return this->priv_upper_bound(this->begin(), this->end(), k); } { return this->priv_upper_bound(this->begin(), this->end(), k); }
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const
{ return this->priv_upper_bound(this->cbegin(), this->cend(), k); } { 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) BOOST_CONTAINER_FORCEINLINE std::pair<iterator,iterator> equal_range(const key_type& k)
{ return this->priv_equal_range(this->begin(), this->end(), 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 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); } { 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) 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); } { 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 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); } { 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 BOOST_CONTAINER_FORCEINLINE size_type capacity() const
{ {
const bool value = boost::container::dtl:: const bool value = boost::container::dtl::
@@ -1419,9 +1501,9 @@ class flat_tree
, boost::forward<Convertible>(convertible)); , boost::forward<Convertible>(convertible));
} }
template <class RanIt> template <class RanIt, class K>
RanIt priv_lower_bound(RanIt first, const RanIt last, 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(); const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract; KeyOfValue key_extract;
@@ -1444,9 +1526,9 @@ class flat_tree
return first; return first;
} }
template <class RanIt> template <class RanIt, class K>
RanIt priv_upper_bound 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(); const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract; KeyOfValue key_extract;
@@ -1469,9 +1551,9 @@ class flat_tree
return first; return first;
} }
template <class RanIt> template <class RanIt, class K>
std::pair<RanIt, RanIt> 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(); const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract; KeyOfValue key_extract;
@@ -1502,8 +1584,8 @@ class flat_tree
return std::pair<RanIt, RanIt>(first, first); return std::pair<RanIt, RanIt>(first, first);
} }
template<class RanIt> template<class RanIt, class K>
std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const key_type& k) const 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(); const Compare &key_cmp = this->m_data.get_comp();
KeyOfValue key_extract; KeyOfValue key_extract;

View File

@@ -76,6 +76,24 @@ struct select1st
{ return const_cast<type&>(x.first); } { 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 dtl {
} //namespace container { } //namespace container {
} //namespace boost { } //namespace boost {

View File

@@ -394,6 +394,7 @@ class RecyclingCloner
intrusive_container &m_icont; intrusive_container &m_icont;
}; };
template<class KeyCompare, class KeyOfValue> template<class KeyCompare, class KeyOfValue>
struct key_node_compare struct key_node_compare
: public boost::intrusive::detail::ebo_functor_holder<KeyCompare> : public boost::intrusive::detail::ebo_functor_holder<KeyCompare>
@@ -407,6 +408,21 @@ struct key_node_compare
typedef KeyOfValue key_of_value; typedef KeyOfValue key_of_value;
typedef typename KeyOfValue::type key_type; 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 BOOST_CONTAINER_FORCEINLINE const key_compare &key_comp() const
{ return static_cast<const key_compare &>(*this); } { return static_cast<const key_compare &>(*this); }
@@ -418,15 +434,15 @@ struct key_node_compare
template<class U> template<class U>
BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const U &nonkey2) const 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> template<class U>
BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const key_type &key2) const 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> template<class U, class V>
BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const V &nonkey2) const 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> template<class Options>
@@ -1260,21 +1276,63 @@ class tree
BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& k) const BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& k) const
{ return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(key_comp()))); } { 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 BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& k) const
{ return size_type(this->icont().count(k, KeyNodeCompare(key_comp()))); } { 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) BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k)
{ return iterator(this->icont().lower_bound(k, KeyNodeCompare(key_comp()))); } { return iterator(this->icont().lower_bound(k, KeyNodeCompare(key_comp()))); }
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const 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()))); } { 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) BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k)
{ return iterator(this->icont().upper_bound(k, KeyNodeCompare(key_comp()))); } { return iterator(this->icont().upper_bound(k, KeyNodeCompare(key_comp()))); }
BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const 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()))); } { 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<iterator,iterator> equal_range(const key_type& k)
{ {
std::pair<iiterator, iiterator> ret = std::pair<iiterator, iiterator> ret =
@@ -1290,6 +1348,27 @@ class tree
(const_iterator(ret.first), const_iterator(ret.second)); (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<iterator,iterator> lower_bound_range(const key_type& k)
{ {
std::pair<iiterator, iiterator> ret = std::pair<iiterator, iiterator> ret =
@@ -1305,6 +1384,27 @@ class tree
(const_iterator(ret.first), const_iterator(ret.second)); (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() BOOST_CONTAINER_FORCEINLINE void rebalance()
{ intrusive_tree_proxy_t::rebalance(this->icont()); } { 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 BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); } { 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>Returns</b>: The number of elements with key equivalent to x.
//! //!
//! <b>Complexity</b>: log(size())+count(k) //! <b>Complexity</b>: log(size())+count(k)
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const 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()); } { 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 //! <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. //! 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 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>: 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 //! <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. //! 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 BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); } { 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>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//! //!
//! <b>Complexity</b>: Logarithmic. //! <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 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)); } { 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>Effects</b>: Extracts the internal sequence container.
//! //!
//! <b>Complexity</b>: Same as the move constructor of sequence_type, usually constant. //! <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 BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); } { 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>Returns</b>: The number of elements with key equivalent to x.
//! //!
//! <b>Complexity</b>: log(size())+count(k) //! <b>Complexity</b>: log(size())+count(k)
BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const
{ return m_flat_tree.count(x); } { 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 //! <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. //! than k, or a.end() if such an element is not found.
//! //!
@@ -2456,13 +2584,35 @@ class flat_multimap
BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& x) BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& x)
{ return dtl::force_copy<iterator>(m_flat_tree.lower_bound(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 //! <b>Returns</b>: An iterator pointing to the first element with key not less
//! not less than k, or a.end() if such an element is not found. //! than k, or a.end() if such an element is not found.
//! //!
//! <b>Complexity</b>: Logarithmic //! <b>Complexity</b>: Logarithmic
BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const 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 //! <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. //! 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 BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const
{ return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); } { 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>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
//! //!
//! <b>Complexity</b>: Logarithmic //! <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 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)); } { 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>Effects</b>: Extracts the internal sequence container.
//! //!
//! <b>Complexity</b>: Same as the move constructor of sequence_type, usually constant. //! <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. //! <b>Complexity</b>: Logarithmic.
const_iterator find(const key_type& x) const; 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>Requires</b>: size() >= n.
//! //!
//! <b>Effects</b>: Returns an iterator to the nth element //! <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 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()); } { 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) #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Returns</b>: An iterator pointing to the first element with key not less //! <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. //! than k, or a.end() if such an element is not found.
@@ -894,6 +924,26 @@ class flat_set
//! <b>Complexity</b>: Logarithmic //! <b>Complexity</b>: Logarithmic
const_iterator lower_bound(const key_type& x) const; 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 //! <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. //! than x, or end() if such an element is not found.
//! //!
@@ -906,6 +956,26 @@ class flat_set
//! <b>Complexity</b>: Logarithmic //! <b>Complexity</b>: Logarithmic
const_iterator upper_bound(const key_type& x) const; 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) #endif // #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! <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) BOOST_CONTAINER_FORCEINLINE std::pair<iterator,iterator> equal_range(const key_type& x)
{ return this->tree_t::lower_bound_range(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) #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Returns true if x and y are equal //! <b>Effects</b>: Returns true if x and y are equal

View File

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

View File

@@ -734,6 +734,26 @@ class set
//! <b>Complexity</b>: Logarithmic. //! <b>Complexity</b>: Logarithmic.
const_iterator find(const key_type& x) const; 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) #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Returns</b>: The number of elements with key equivalent to x. //! <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 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()); } { 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>Returns</b>: The number of elements with key equivalent to x.
//! //!
//! <b>Complexity</b>: log(size())+count(k) //! <b>Complexity</b>: log(size())+count(k)
@@ -762,6 +792,26 @@ class set
//! <b>Complexity</b>: Logarithmic //! <b>Complexity</b>: Logarithmic
const_iterator lower_bound(const key_type& x) const; 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 //! <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. //! than x, or end() if such an element is not found.
//! //!
@@ -774,6 +824,26 @@ class set
//! <b>Complexity</b>: Logarithmic //! <b>Complexity</b>: Logarithmic
const_iterator upper_bound(const key_type& x) const; 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) #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! <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 BOOST_CONTAINER_FORCEINLINE std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const
{ return this->base_t::lower_bound_range(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<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) #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>Effects</b>: Rebalances the tree. It's a no-op for Red-Black and AVL trees.
//! //!
//! <b>Complexity</b>: Linear //! <b>Complexity</b>: Linear
@@ -1330,27 +1410,63 @@ class multiset
//! @copydoc ::boost::container::set::find(const key_type& ) const //! @copydoc ::boost::container::set::find(const key_type& ) const
const_iterator find(const key_type& x) 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 //! @copydoc ::boost::container::set::count(const key_type& ) const
size_type count(const key_type& x) 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& ) //! @copydoc ::boost::container::set::lower_bound(const key_type& )
iterator lower_bound(const key_type& x); iterator lower_bound(const key_type& x);
//! @copydoc ::boost::container::set::lower_bound(const key_type& ) const //! @copydoc ::boost::container::set::lower_bound(const key_type& ) const
const_iterator lower_bound(const key_type& x) 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& ) //! @copydoc ::boost::container::set::upper_bound(const key_type& )
iterator upper_bound(const key_type& x); iterator upper_bound(const key_type& x);
//! @copydoc ::boost::container::set::upper_bound(const key_type& ) const //! @copydoc ::boost::container::set::upper_bound(const key_type& ) const
const_iterator upper_bound(const key_type& x) 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 //! @copydoc ::boost::container::set::equal_range(const key_type& ) const
std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const; std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
//! @copydoc ::boost::container::set::equal_range(const key_type& ) //! @copydoc ::boost::container::set::equal_range(const key_type& )
std::pair<iterator,iterator> equal_range(const key_type& x); 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() //! @copydoc ::boost::container::set::rebalance()
void rebalance(); void rebalance();

View File

@@ -108,6 +108,17 @@ bool CheckEqualPairContainers(const MyBoostCont &boostcont, const MyStdCont &std
return true; 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 test{
} //namespace container { } //namespace container {
} //namespace boost{ } //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; 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 }}} //namespace boost::container::test
template<class VoidAllocatorOrContainer> template<class VoidAllocatorOrContainer>
@@ -527,6 +606,9 @@ int main()
if (!boost::container::test::instantiate_constructors<flat_map<int, int>, flat_multimap<int, int> >()) if (!boost::container::test::instantiate_constructors<flat_map<int, int>, flat_multimap<int, int> >())
return 1; return 1;
if (!test_heterogeneous_lookups())
return 1;
//////////////////////////////////// ////////////////////////////////////
// Testing allocator implementations // Testing allocator implementations
//////////////////////////////////// ////////////////////////////////////

View File

@@ -450,6 +450,84 @@ bool flat_tree_extract_adopt_test()
return true; 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> template<class VoidAllocatorOrContainer>
@@ -636,6 +714,10 @@ int main()
if (!boost::container::test::instantiate_constructors<flat_set<int>, flat_multiset<int> >()) if (!boost::container::test::instantiate_constructors<flat_set<int>, flat_multiset<int> >())
return 1; return 1;
if(!test_heterogeneous_lookups()){
return 1;
}
//////////////////////////////////// ////////////////////////////////////
// Testing allocator implementations // Testing allocator implementations
//////////////////////////////////// ////////////////////////////////////

View File

@@ -320,6 +320,85 @@ void test_merge_from_different_comparison()
map1.merge(map2); 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 }}} //namespace boost::container::test
int main () int main ()
@@ -437,6 +516,9 @@ int main ()
test::test_merge_from_different_comparison(); test::test_merge_from_different_comparison();
if(!test::test_heterogeneous_lookups())
return 1;
//////////////////////////////////// ////////////////////////////////////
// Test optimize_size option // Test optimize_size option
//////////////////////////////////// ////////////////////////////////////

View File

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

View File

@@ -318,6 +318,84 @@ void test_merge_from_different_comparison()
set1.merge(set2); 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 () int main ()
{ {
//Recursive container instantiation //Recursive container instantiation
@@ -349,6 +427,9 @@ int main ()
test_merge_from_different_comparison(); test_merge_from_different_comparison();
if(!test_heterogeneous_lookups())
return 1;
//////////////////////////////////// ////////////////////////////////////
// Testing allocator implementations // Testing allocator implementations
//////////////////////////////////// ////////////////////////////////////