diff --git a/doc/container.qbk b/doc/container.qbk index 032b046..5071dda 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -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`] [*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: diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 5f212e3..e9cbe38 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -1160,7 +1160,31 @@ class flat_tree return i; } - // set operations: + template + typename dtl::enable_if_transparent::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 + typename dtl::enable_if_transparent::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 p = this->equal_range(k); @@ -1168,6 +1192,15 @@ class flat_tree return n; } + template + typename dtl::enable_if_transparent::type + count(const K& k) const + { + std::pair p = this->equal_range(k); + size_type n = p.second - p.first; + return n; + } + template BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree& 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 + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::type + lower_bound(const K& k) + { return this->priv_lower_bound(this->begin(), this->end(), k); } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::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 + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::type + upper_bound(const K& k) + { return this->priv_upper_bound(this->begin(), this->end(), k); } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::type + upper_bound(const K& k) const + { return this->priv_upper_bound(this->cbegin(), this->cend(), k); } + BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& k) { return this->priv_equal_range(this->begin(), this->end(), k); } BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& k) const { return this->priv_equal_range(this->cbegin(), this->cend(), k); } + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::type + equal_range(const K& k) + { return this->priv_equal_range(this->begin(), this->end(), k); } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::type + equal_range(const K& k) const + { return this->priv_equal_range(this->cbegin(), this->cend(), k); } + + BOOST_CONTAINER_FORCEINLINE std::pair lower_bound_range(const key_type& k) { return this->priv_lower_bound_range(this->begin(), this->end(), k); } BOOST_CONTAINER_FORCEINLINE std::pair lower_bound_range(const key_type& k) const { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); } + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::type + lower_bound_range(const K& k) + { return this->priv_lower_bound_range(this->begin(), this->end(), k); } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::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)); } - template + template 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 + template 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 + template std::pair - 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(first, first); } - template - std::pair priv_lower_bound_range(RanIt first, RanIt last, const key_type& k) const + template + std::pair priv_lower_bound_range(RanIt first, RanIt last, const K& k) const { const Compare &key_cmp = this->m_data.get_comp(); KeyOfValue key_extract; diff --git a/include/boost/container/detail/mpl.hpp b/include/boost/container/detail/mpl.hpp index 4bb3cc7..385f7db 100644 --- a/include/boost/container/detail/mpl.hpp +++ b/include/boost/container/detail/mpl.hpp @@ -76,6 +76,24 @@ struct select1st { return const_cast(x.first); } }; +template +struct is_transparent +{ + static const bool value = false; +}; + +template +struct is_transparent +{ + static const bool value = true; +}; + +template +struct enable_if_transparent + : boost::move_detail::enable_if_c::value, R> +{}; + + } //namespace dtl { } //namespace container { } //namespace boost { diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 8d41158..c32e992 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -394,6 +394,7 @@ class RecyclingCloner intrusive_container &m_icont; }; + template struct key_node_compare : public boost::intrusive::detail::ebo_functor_holder @@ -407,6 +408,21 @@ struct key_node_compare typedef KeyOfValue key_of_value; typedef typename KeyOfValue::type key_type; + + template + BOOST_CONTAINER_FORCEINLINE static const key_type & + key_from(const tree_node &n) + { + return key_of_value()(n.get_data()); + } + + template + 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(*this); } @@ -418,15 +434,15 @@ struct key_node_compare template 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 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 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 @@ -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 + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::type + find(const K& k) + { return iterator(this->icont().find(k, KeyNodeCompare(key_comp()))); } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::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 + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::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 + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::type + lower_bound(const K& k) + { return iterator(this->icont().lower_bound(k, KeyNodeCompare(key_comp()))); } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::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 + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::type + upper_bound(const K& k) + { return iterator(this->icont().upper_bound(k, KeyNodeCompare(key_comp()))); } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent::type + upper_bound(const K& k) const + { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(key_comp()))); } + std::pair equal_range(const key_type& k) { std::pair ret = @@ -1290,6 +1348,27 @@ class tree (const_iterator(ret.first), const_iterator(ret.second)); } + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::type + equal_range(const K& k) + { + std::pair ret = + this->icont().equal_range(k, KeyNodeCompare(key_comp())); + return std::pair(iterator(ret.first), iterator(ret.second)); + } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::type + equal_range(const K& k) const + { + std::pair ret = + this->non_const_icont().equal_range(k, KeyNodeCompare(key_comp())); + return std::pair + (const_iterator(ret.first), const_iterator(ret.second)); + } + std::pair lower_bound_range(const key_type& k) { std::pair ret = @@ -1305,6 +1384,27 @@ class tree (const_iterator(ret.first), const_iterator(ret.second)); } + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::type + lower_bound_range(const K& k) + { + std::pair ret = + this->icont().lower_bound_range(k, KeyNodeCompare(key_comp())); + return std::pair(iterator(ret.first), iterator(ret.second)); + } + + template + BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent >::type + lower_bound_range(const K& k) const + { + std::pair ret = + this->non_const_icont().lower_bound_range(k, KeyNodeCompare(key_comp())); + return std::pair + (const_iterator(ret.first), const_iterator(ret.second)); + } + BOOST_CONTAINER_FORCEINLINE void rebalance() { intrusive_tree_proxy_t::rebalance(this->icont()); } diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index ffd0d05..6361352 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -1302,12 +1302,44 @@ class flat_map BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& x) const { return dtl::force_copy(m_flat_tree.find(x)); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE iterator find(const K& x) + { return dtl::force_copy(m_flat_tree.find(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE const_iterator find(const K& x) const + { return dtl::force_copy(m_flat_tree.find(x)); } + //! Returns: The number of elements with key equivalent to x. //! //! Complexity: log(size())+count(k) BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const { return static_cast(m_flat_tree.find(x) != m_flat_tree.end()); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + template + BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const + { return static_cast(m_flat_tree.find(x) != m_flat_tree.end()); } + //! Returns: 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(m_flat_tree.lower_bound(x)); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const K& x) + { return dtl::force_copy(m_flat_tree.lower_bound(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const + { return dtl::force_copy(m_flat_tree.lower_bound(x)); } + //! Returns: 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(m_flat_tree.upper_bound(x)); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const K& x) + { return dtl::force_copy(m_flat_tree.upper_bound(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const K& x) const + { return dtl::force_copy(m_flat_tree.upper_bound(x)); } + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! //! Complexity: Logarithmic. @@ -1348,6 +1424,26 @@ class flat_map BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& x) const { return dtl::force_copy >(m_flat_tree.lower_bound_range(x)); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) + { return dtl::force_copy >(m_flat_tree.lower_bound_range(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) const + { return dtl::force_copy >(m_flat_tree.lower_bound_range(x)); } + //! Effects: Extracts the internal sequence container. //! //! Complexity: 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(m_flat_tree.find(x)); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE iterator find(const K& x) + { return dtl::force_copy(m_flat_tree.find(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE const_iterator find(const K& x) const + { return dtl::force_copy(m_flat_tree.find(x)); } + //! Returns: The number of elements with key equivalent to x. //! //! Complexity: log(size())+count(k) BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const { return m_flat_tree.count(x); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + template + BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const + { return m_flat_tree.count(x); } + //! Returns: 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(m_flat_tree.lower_bound(x)); } - //! Returns: A const iterator pointing to the first element with key - //! not less than k, or a.end() if such an element is not found. + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const - { return dtl::force_copy(m_flat_tree.lower_bound(x)); } + { return dtl::force_copy(m_flat_tree.lower_bound(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const K& x) + { return dtl::force_copy(m_flat_tree.lower_bound(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const + { return dtl::force_copy(m_flat_tree.lower_bound(x)); } //! Returns: 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(m_flat_tree.upper_bound(x)); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const K& x) + {return dtl::force_copy(m_flat_tree.upper_bound(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key + //! not less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const K& x) const + { return dtl::force_copy(m_flat_tree.upper_bound(x)); } + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! //! Complexity: Logarithmic @@ -2489,6 +2661,26 @@ class flat_multimap BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& x) const { return dtl::force_copy >(m_flat_tree.equal_range(x)); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) + { return dtl::force_copy >(m_flat_tree.equal_range(x)); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const K& x) const + { return dtl::force_copy >(m_flat_tree.equal_range(x)); } + //! Effects: Extracts the internal sequence container. //! //! Complexity: Same as the move constructor of sequence_type, usually constant. diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 59ab573..a873b6a 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -823,6 +823,26 @@ class flat_set //! Complexity: Logarithmic. const_iterator find(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + iterator find(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + const_iterator find(const K& x) const; + //! Requires: size() >= n. //! //! Effects: 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(this->tree_t::find(x) != this->tree_t::cend()); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + template + BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const + { return static_cast(this->tree_t::find(x) != this->tree_t::cend()); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Returns: 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 //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator lower_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator lower_bound(const K& x) const; + //! Returns: 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 //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator upper_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator upper_bound(const K& x) const; + #endif // #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: 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 equal_range(const key_type& x) { return this->tree_t::lower_bound_range(x); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x) + { return this->tree_t::lower_bound_range(x); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x) const + { return this->tree_t::lower_bound_range(x); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Returns true if x and y are equal diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 63e10b4..93058bf 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -1079,6 +1079,26 @@ class map //! Complexity: Logarithmic. const_iterator find(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + iterator find(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + const_iterator find(const K& x) const; + #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Returns: 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(this->find(x) != this->cend()); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + template + BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const + { return static_cast(this->find(x) != this->cend()); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Returns: An iterator pointing to the first element with key not less @@ -1101,6 +1131,26 @@ class map //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator lower_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator lower_bound(const K& x) const; + //! Returns: 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 //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator upper_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator upper_bound(const K& x) const; + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! //! Complexity: Logarithmic @@ -1123,6 +1193,24 @@ class map //! Complexity: Logarithmic std::pair equal_range(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x) const; + //! Effects: Rebalances the tree. It's a no-op for Red-Black and AVL trees. //! //! Complexity: Linear @@ -1841,11 +1929,40 @@ class multimap //! Complexity: Logarithmic. const_iterator find(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + iterator find(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + const_iterator find(const K& x) const; + //! Returns: The number of elements with key equivalent to x. //! //! Complexity: log(size())+count(k) size_type count(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + template + size_type count(const K& x) const; + //! Returns: 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 //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator lower_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator lower_bound(const K& x) const; + //! Returns: 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 //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator upper_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator upper_bound(const K& x) const; + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! //! Complexity: Logarithmic @@ -1880,6 +2037,24 @@ class multimap //! Complexity: Logarithmic std::pair equal_range(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x) const; + //! Effects: Rebalances the tree. It's a no-op for Red-Black and AVL trees. //! //! Complexity: Linear diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index f6cde19..433d60d 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -734,6 +734,26 @@ class set //! Complexity: Logarithmic. const_iterator find(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + iterator find(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + template + const_iterator find(const K& x) const; + #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Returns: 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(this->base_t::find(x) != this->base_t::cend()); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + template + BOOST_CONTAINER_FORCEINLINE size_type count(const K& x) const + { return static_cast(this->find(x) != this->cend()); } + //! Returns: The number of elements with key equivalent to x. //! //! Complexity: log(size())+count(k) @@ -762,6 +792,26 @@ class set //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator lower_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator lower_bound(const K& x) const; + //! Returns: 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 //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + iterator upper_bound(const K& x); + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + template + const_iterator upper_bound(const K& x) const; + #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). @@ -788,18 +858,28 @@ class set BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& x) const { return this->base_t::lower_bound_range(x); } + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x) + { return this->base_t::lower_bound_range(x); } + + //! Requires: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + template + std::pair equal_range(const K& x) const + { return this->base_t::lower_bound_range(x); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x); - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) const; - //! Effects: Rebalances the tree. It's a no-op for Red-Black and AVL trees. //! //! Complexity: 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 + iterator find(const K& x); + + //! @copydoc ::boost::container::set::find(const K& ) + template + 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 + 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 + iterator lower_bound(const K& x); + + //! @copydoc ::boost::container::set::lower_bound(const K& ) const + template + 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 + iterator upper_bound(const K& x); + + //! @copydoc ::boost::container::set::upper_bound(const K& ) const + template + const_iterator upper_bound(const K& x) const; + //! @copydoc ::boost::container::set::equal_range(const key_type& ) const std::pair equal_range(const key_type& x) const; //! @copydoc ::boost::container::set::equal_range(const key_type& ) std::pair equal_range(const key_type& x); + //! @copydoc ::boost::container::set::equal_range(const K& ) const + template + std::pair equal_range(const K& x) const; + + //! @copydoc ::boost::container::set::equal_range(const K& ) + template + std::pair equal_range(const K& x); + //! @copydoc ::boost::container::set::rebalance() void rebalance(); diff --git a/test/check_equal_containers.hpp b/test/check_equal_containers.hpp index 617089d..e9b6607 100644 --- a/test/check_equal_containers.hpp +++ b/test/check_equal_containers.hpp @@ -108,6 +108,17 @@ bool CheckEqualPairContainers(const MyBoostCont &boostcont, const MyStdCont &std return true; } +struct less_transparent +{ + typedef void is_transparent; + + template + bool operator()(const T &t, const U &u) const + { + return t < u; + } +}; + } //namespace test{ } //namespace container { } //namespace boost{ diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index bb6326a..950502a 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -422,6 +422,85 @@ struct get_real_stored_allocator > typedef typename flat_multimap::impl_stored_allocator_type type; }; +bool test_heterogeneous_lookups() +{ + typedef flat_map map_t; + typedef flat_multimap 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 @@ -527,6 +606,9 @@ int main() if (!boost::container::test::instantiate_constructors, flat_multimap >()) return 1; + if (!test_heterogeneous_lookups()) + return 1; + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index e23cf7a..54f0359 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -450,6 +450,84 @@ bool flat_tree_extract_adopt_test() return true; } +bool test_heterogeneous_lookups() +{ + typedef flat_set set_t; + typedef flat_multiset 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 @@ -636,6 +714,10 @@ int main() if (!boost::container::test::instantiate_constructors, flat_multiset >()) return 1; + if(!test_heterogeneous_lookups()){ + return 1; + } + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// diff --git a/test/map_test.cpp b/test/map_test.cpp index 516d64a..ab131a1 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -320,6 +320,85 @@ void test_merge_from_different_comparison() map1.merge(map2); } +bool test_heterogeneous_lookups() +{ + typedef map map_t; + typedef multimap 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 //////////////////////////////////// diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 38678d7..c8513c0 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -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; }; diff --git a/test/set_test.cpp b/test/set_test.cpp index 57270c2..0f72a77 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -318,6 +318,84 @@ void test_merge_from_different_comparison() set1.merge(set2); } +bool test_heterogeneous_lookups() +{ + typedef set set_t; + typedef multiset 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 ////////////////////////////////////