diff --git a/doc/unordered/changes.adoc b/doc/unordered/changes.adoc index 3c3f15f6..5a038239 100644 --- a/doc/unordered/changes.adoc +++ b/doc/unordered/changes.adoc @@ -6,6 +6,11 @@ :github-pr-url: https://github.com/boostorg/unordered/pull :cpp: C++ +== Release 1.82.0 + +* Extended heterogeneous lookup to more member functions as specified in + https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2363r3.html[P2363]. + == Release 1.81.0 - Major update * Added fast containers `boost::unordered_flat_map` and `boost::unordered_flat_set` diff --git a/doc/unordered/unordered_flat_map.adoc b/doc/unordered/unordered_flat_map.adoc index 27af35cd..e1b27499 100644 --- a/doc/unordered/unordered_flat_map.adoc +++ b/doc/unordered/unordered_flat_map.adoc @@ -134,23 +134,31 @@ namespace boost { std::pair xref:#unordered_flat_map_try_emplace[try_emplace](const key_type& k, Args&&... args); template std::pair xref:#unordered_flat_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template + std::pair xref:#unordered_flat_map_try_emplace[try_emplace](K&& k, Args&&... args); template iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); template iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); + template + iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); template std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); template std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template + std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); template iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj); template iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj); + template + iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj); void xref:#unordered_flat_map_erase_by_position[erase](iterator position); void xref:#unordered_flat_map_erase_by_position[erase](const_iterator position); size_type xref:#unordered_flat_map_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_flat_map_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_flat_map_erase_by_key[erase](K&& k); iterator xref:#unordered_flat_map_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_flat_map_swap[swap](unordered_flat_map& other) noexcept(boost::allocator_traits::is_always_equal::value || @@ -189,8 +197,11 @@ namespace boost { // element access mapped_type& xref:#unordered_flat_map_operator[operator[+]+](const key_type& k); mapped_type& xref:#unordered_flat_map_operator[operator[+]+](key_type&& k); + template mapped_type& xref:#unordered_flat_map_operator[operator[+]+](K&& k); mapped_type& xref:#unordered_flat_map_at[at](const key_type& k); const mapped_type& xref:#unordered_flat_map_at[at](const key_type& k) const; + template mapped_type& xref:#unordered_flat_map_at[at](const K& k); + template const mapped_type& xref:#unordered_flat_map_at[at](const K& k) const; // bucket interface size_type xref:#unordered_flat_map_bucket_count[bucket_count]() const noexcept; @@ -860,6 +871,8 @@ template std::pair try_emplace(const key_type& k, Args&&... args); template std::pair try_emplace(key_type&& k, Args&&... args); +template + std::pair try_emplace(K&& k, Args&&... args); ``` Inserts a new node into the container if there is no existing element with key `k` contained within it. @@ -876,15 +889,23 @@ if there is an element with an equivalent key; otherwise, the construction is of + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` unlike xref:#unordered_flat_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor. Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + -- --- @@ -895,6 +916,8 @@ template iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); ``` Inserts a new node into the container if there is no existing element with key `k` contained within it. @@ -911,15 +934,23 @@ if there is an element with an equivalent key; otherwise, the construction is of + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` unlike xref:#unordered_flat_map_emplace_hint[emplace_hint], which simply forwards all arguments to ``value_type``'s constructor. Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + -- --- @@ -930,6 +961,8 @@ template std::pair insert_or_assign(const key_type& k, M&& obj); template std::pair insert_or_assign(key_type&& k, M&& obj); +template + std::pair insert_or_assign(K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -938,9 +971,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` [horizontal] @@ -948,7 +987,9 @@ Returns:;; The `bool` component of the return type is `true` if an insert took p + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. + +Notes:;; Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -958,6 +999,8 @@ template iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -966,9 +1009,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` `hint` is a suggestion to where the element should be inserted. This implementation ignores it. @@ -976,7 +1025,9 @@ value_type(std::piecewise_construct, [horizontal] Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -998,28 +1049,15 @@ Throws:;; Nothing. ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1172,13 +1210,16 @@ Notes:;; The `template ` overloads only participate in overload reso ```c++ mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k); +template mapped_type& operator[](K&& k); ``` [horizontal] Effects:;; If the container does not already contain an element with a key equivalent to `k`, inserts the value `std::pair(k, mapped_type())`. Returns:;; A reference to `x.second` where `x` is the element already in the container, or the newly inserted element with a key equivalent to `k`. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1186,11 +1227,14 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse ```c++ mapped_type& at(const key_type& k); const mapped_type& at(const key_type& k) const; +template mapped_type& at(const K& k); +template const mapped_type& at(const K& k) const; ``` [horizontal] Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`. Throws:;; An exception object of type `std::out_of_range` if no such element is present. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- diff --git a/doc/unordered/unordered_flat_set.adoc b/doc/unordered/unordered_flat_set.adoc index cd22733a..7d3d69f8 100644 --- a/doc/unordered/unordered_flat_set.adoc +++ b/doc/unordered/unordered_flat_set.adoc @@ -116,15 +116,17 @@ namespace boost { template iterator xref:#unordered_flat_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args); std::pair xref:#unordered_flat_set_copy_insert[insert](const value_type& obj); std::pair xref:#unordered_flat_set_move_insert[insert](value_type&& obj); - iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); - iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template std::pair xref:#unordered_flat_set_transparent_insert[insert](K&& k); + iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list); void xref:#unordered_flat_set_erase_by_position[erase](iterator position); void xref:#unordered_flat_set_erase_by_position[erase](const_iterator position); size_type xref:#unordered_flat_set_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_flat_set_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_flat_set_erase_by_key[erase](K&& k); iterator xref:#unordered_flat_set_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_flat_set_swap[swap](unordered_flat_set& other) noexcept(boost::allocator_traits::is_always_equal::value || @@ -736,6 +738,25 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse --- +==== Transparent Insert +```c++ +template std::pair insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Copy Insert with Hint ```c++ iterator insert(const_iterator hint, const value_type& obj); @@ -773,6 +794,27 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse --- +==== Transparent Insert with Hint +```c++ +template std::pair insert(const_iterator hint, K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Insert Iterator Range ```c++ template void insert(InputIterator first, InputIterator last); @@ -818,28 +860,15 @@ Throws:;; Nothing. ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- diff --git a/doc/unordered/unordered_map.adoc b/doc/unordered/unordered_map.adoc index 40e1ba84..2cc08369 100644 --- a/doc/unordered/unordered_map.adoc +++ b/doc/unordered/unordered_map.adoc @@ -113,29 +113,37 @@ namespace boost { std::pair xref:#unordered_map_try_emplace[try_emplace](const key_type& k, Args&&... args); template std::pair xref:#unordered_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template + std::pair xref:#unordered_map_try_emplace[try_emplace](K&& k, Args&&... args); template iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); template iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); + template + iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); template std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); template std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template + std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); template iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj); template iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj); + template + iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj); node_type xref:#unordered_map_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_map_extract_by_key[extract](const key_type& k); - template node_type xref:#unordered_map_transparent_extract_by_key[extract](K&& k); + template node_type xref:#unordered_map_extract_by_key[extract](K&& k); insert_return_type xref:#unordered_map_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_map_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_map_erase_by_position[erase](iterator position); iterator xref:#unordered_map_erase_by_position[erase](const_iterator position); size_type xref:#unordered_map_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_map_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_map_erase_by_key[erase](K&& k); iterator xref:#unordered_map_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_map_quick_erase[quick_erase](const_iterator position); void xref:#unordered_map_erase_return_void[erase_return_void](const_iterator position); @@ -187,14 +195,18 @@ namespace boost { // element access mapped_type& xref:#unordered_map_operator[operator[+]+](const key_type& k); mapped_type& xref:#unordered_map_operator[operator[+]+](key_type&& k); + template mapped_type& xref:#unordered_map_operator[operator[+]+](K&& k); mapped_type& xref:#unordered_map_at[at](const key_type& k); const mapped_type& xref:#unordered_map_at[at](const key_type& k) const; + template mapped_type& xref:#unordered_map_at[at](const K& k); + template const mapped_type& xref:#unordered_map_at[at](const K& k) const; // bucket interface size_type xref:#unordered_map_bucket_count[bucket_count]() const noexcept; size_type xref:#unordered_map_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_map_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_map_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_map_bucket[bucket](const K& k) const; local_iterator xref:#unordered_map_begin_2[begin](size_type n); const_local_iterator xref:#unordered_map_begin_2[begin](size_type n) const; local_iterator xref:#unordered_map_end_2[end](size_type n); @@ -997,6 +1009,8 @@ template std::pair try_emplace(const key_type& k, Args&&... args); template std::pair try_emplace(key_type&& k, Args&&... args); +template + std::pair try_emplace(K&& k, Args&&... args) ``` Inserts a new node into the container if there is no existing element with key `k` contained within it. @@ -1012,9 +1026,15 @@ Notes:;; This function is similiar to xref:#unordered_map_emplace[emplace] excep + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` instead of xref:#unordered_map_emplace[emplace] which simply forwards all arguments to ``value_type``'s constructor. @@ -1023,6 +1043,8 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr Pointers and references to elements are never invalidated. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. @@ -1036,6 +1058,8 @@ template iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); ``` Inserts a new node into the container if there is no existing element with key `k` contained within it. @@ -1051,9 +1075,15 @@ Notes:;; This function is similiar to xref:#unordered_map_emplace_hint[emplace_h + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` instead of xref:#unordered_map_emplace_hint[emplace_hint] which simply forwards all arguments to ``value_type``'s constructor. @@ -1064,6 +1094,8 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr Pointers and references to elements are never invalidated. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. @@ -1077,6 +1109,8 @@ template std::pair insert_or_assign(const key_type& k, M&& obj); template std::pair insert_or_assign(key_type&& k, M&& obj); +template + std::pair insert_or_assign(K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -1085,9 +1119,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` [horizontal] @@ -1097,7 +1137,9 @@ If an insert took place, then the iterator points to the newly inserted element. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + + -Pointers and references to elements are never invalidated. +Pointers and references to elements are never invalidated. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1107,6 +1149,8 @@ template iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -1115,9 +1159,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` `hint` is a suggestion to where the element should be inserted. @@ -1129,7 +1179,9 @@ Notes:;; The standard is fairly vague on the meaning of the hint. But the only p + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + + -Pointers and references to elements are never invalidated. +Pointers and references to elements are never invalidated. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1149,30 +1201,17 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u ==== Extract by Key ```c++ node_type extract(const key_type& k); -``` - -Removes an element with key equivalent to `k`. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. - ---- - -==== Transparent Extract by Key -```c++ template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1251,28 +1290,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1490,6 +1516,7 @@ Notes:;; The `template ` overloads only participate in overload reso ```c++ mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k); +template mapped_type& operator[](K&& k); ``` [horizontal] @@ -1498,7 +1525,9 @@ Returns:;; A reference to `x.second` where `x` is the element already in the con Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + + -Pointers and references to elements are never invalidated. +Pointers and references to elements are never invalidated. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1506,11 +1535,14 @@ Pointers and references to elements are never invalidated. ```c++ mapped_type& at(const key_type& k); const mapped_type& at(const key_type& k) const; +template mapped_type& at(const K& k); +template const mapped_type& at(const K& k) const; ``` [horizontal] Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`. Throws:;; An exception object of type `std::out_of_range` if no such element is present. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1550,11 +1582,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- diff --git a/doc/unordered/unordered_multimap.adoc b/doc/unordered/unordered_multimap.adoc index 9237d747..ab5ccbbb 100644 --- a/doc/unordered/unordered_multimap.adoc +++ b/doc/unordered/unordered_multimap.adoc @@ -111,14 +111,14 @@ namespace boost { node_type xref:#unordered_multimap_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_multimap_extract_by_key[extract](const key_type& k); - template node_type xref:#unordered_multimap_transparent_extract_by_key[extract](K&& k); + template node_type xref:#unordered_multimap_extract_by_key[extract](K&& k); iterator xref:#unordered_multimap_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_multimap_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_multimap_erase_by_position[erase](iterator position); iterator xref:#unordered_multimap_erase_by_position[erase](const_iterator position); size_type xref:#unordered_multimap_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_multimap_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_multimap_erase_by_key[erase](K&& k); iterator xref:#unordered_multimap_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_multimap_quick_erase[quick_erase](const_iterator position); void xref:#unordered_multimap_erase_return_void[erase_return_void](const_iterator position); @@ -172,6 +172,7 @@ namespace boost { size_type xref:#unordered_multimap_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_multimap_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_multimap_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_multimap_bucket[bucket](const K& k) const; local_iterator xref:#unordered_multimap_begin_2[begin](size_type n); const_local_iterator xref:#unordered_multimap_begin_2[begin](size_type n) const; local_iterator xref:#unordered_multimap_end_2[end](size_type n); @@ -964,30 +965,17 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u ==== Extract by Key ```c++ node_type extract(const key_type& k); -``` - -Removes an element with key equivalent to `k`. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. - ---- - -==== Transparent Extract by Key -```c++ template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1060,28 +1048,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1330,11 +1305,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- diff --git a/doc/unordered/unordered_multiset.adoc b/doc/unordered/unordered_multiset.adoc index ebaec9a5..2495e570 100644 --- a/doc/unordered/unordered_multiset.adoc +++ b/doc/unordered/unordered_multiset.adoc @@ -107,14 +107,14 @@ namespace boost { node_type xref:#unordered_multiset_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_multiset_extract_by_value[extract](const key_type& k); - template node_type xref:#unordered_multiset_transparent_extract_by_value[extract](K&& k); + template node_type xref:#unordered_multiset_extract_by_value[extract](K&& k); iterator xref:#unordered_multiset_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_multiset_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_multiset_erase_by_position[erase](iterator position); iterator xref:#unordered_multiset_erase_by_position[erase](const_iterator position); size_type xref:#unordered_multiset_erase_by_value[erase](const key_type& k); - template size_type xref:#unordered_multiset_transparent_erase_by_value[erase](K&& x); + template size_type xref:#unordered_multiset_erase_by_value[erase](K&& x); iterator xref:#unordered_multiset_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_multiset_quick_erase[quick_erase](const_iterator position); void xref:#unordered_multiset_erase_return_void[erase_return_void](const_iterator position); @@ -168,6 +168,7 @@ namespace boost { size_type xref:#unordered_multiset_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_multiset_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_multiset_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_multiset_bucket[bucket](const K& k) const; local_iterator xref:#unordered_multiset_begin_2[begin](size_type n); const_local_iterator xref:#unordered_multiset_begin_2[begin](size_type n) const; local_iterator xref:#unordered_multiset_end_2[end](size_type n); @@ -922,6 +923,7 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u ==== Extract by Value ```c++ node_type extract(const key_type& k); +template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. @@ -929,23 +931,9 @@ Removes an element with key equivalent to `k`. [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. - ---- - -==== Transparent Extract by Value -```c++ -template node_type extract(K&& k); -``` - -Removes an element with key equivalent to `k`. - -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.[horizontal] -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1018,28 +1006,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Value ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Value -```c++ template size_type erase(K&& x); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1288,11 +1263,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- diff --git a/doc/unordered/unordered_set.adoc b/doc/unordered/unordered_set.adoc index f8fdd117..8530b4d4 100644 --- a/doc/unordered/unordered_set.adoc +++ b/doc/unordered/unordered_set.adoc @@ -100,21 +100,23 @@ namespace boost { template iterator xref:#unordered_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args); std::pair xref:#unordered_set_copy_insert[insert](const value_type& obj); std::pair xref:#unordered_set_move_insert[insert](value_type&& obj); + template std::pair xref:#unordered_set_transparent_insert[insert](K&& k); iterator xref:#unordered_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); iterator xref:#unordered_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template void xref:#unordered_set_insert_iterator_range[insert](InputIterator first, InputIterator last); void xref:#unordered_set_insert_initializer_list[insert](std::initializer_list); node_type xref:#unordered_set_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_set_extract_by_value[extract](const key_type& k); - template node_type xref:#unordered_set_transparent_extract_by_value[extract](K&& k); + template node_type xref:#unordered_set_extract_by_value[extract](K&& k); insert_return_type xref:#unordered_set_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_set_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_set_erase_by_position[erase](iterator position); iterator xref:#unordered_set_erase_by_position[erase](const_iterator position); size_type xref:#unordered_set_erase_by_value[erase](const key_type& k); - template size_type xref:#unordered_set_transparent_erase_by_value[erase](K&& k); + template size_type xref:#unordered_set_erase_by_value[erase](K&& k); iterator xref:#unordered_set_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_set_quick_erase[quick_erase](const_iterator position); void xref:#unordered_set_erase_return_void[erase_return_void](const_iterator position); @@ -168,6 +170,7 @@ namespace boost { size_type xref:#unordered_set_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_set_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_set_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_set_bucket[bucket](const K& k) const; local_iterator xref:#unordered_set_begin_2[begin](size_type n); const_local_iterator xref:#unordered_set_begin_2[begin](size_type n) const; local_iterator xref:#unordered_set_end_2[end](size_type n); @@ -847,6 +850,27 @@ Pointers and references to elements are never invalidated. --- +==== Transparent Insert +```c++ +template std::pair insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Copy Insert with Hint ```c++ iterator insert(const_iterator hint, const value_type& obj); @@ -888,6 +912,29 @@ Pointers and references to elements are never invalidated. --- +==== Transparent Insert with Hint +```c++ +template iterator insert(const_iterator hint, K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Insert Iterator Range ```c++ template void insert(InputIterator first, InputIterator last); @@ -936,30 +983,17 @@ Notes:;; In C++17 a node extracted using this method can be inserted into a comp ==== Extract by Value ```c++ node_type extract(const key_type& k); -``` - -Removes an element with key equivalent to `k`. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. - ---- - -==== Transparent Extract by Value -```c++ template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. +Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1038,28 +1072,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Value ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Value -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1309,11 +1330,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index d953b313..13351171 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1477,7 +1477,22 @@ namespace boost { } #endif - } + + template + inline typename boost::allocator_pointer::type + construct_node_from_key(T*, Alloc& alloc, BOOST_FWD_REF(Key) k) + { + return construct_node(alloc, boost::forward(k)); + } + + template + inline typename boost::allocator_pointer::type + construct_node_from_key( + std::pair*, Alloc& alloc, BOOST_FWD_REF(Key) k) + { + return construct_node_pair(alloc, boost::forward(k)); + } + } // namespace func } } } @@ -2640,8 +2655,10 @@ namespace boost { } else { node_allocator_type alloc = node_alloc(); - node_tmp tmp( - detail::func::construct_node_pair(alloc, boost::forward(k)), + value_type* dispatch = BOOST_NULLPTR; + + node_tmp tmp(detail::func::construct_node_from_key( + dispatch, alloc, boost::forward(k)), alloc); if (size_ + 1 > max_load_) { @@ -2660,7 +2677,7 @@ namespace boost { template iterator try_emplace_hint_unique(c_iterator hint, BOOST_FWD_REF(Key) k) { - if (hint.p && this->key_eq()(hint->first, k)) { + if (hint.p && this->key_eq()(extractor::extract(*hint), k)) { return iterator(hint.p, hint.itb); } else { return try_emplace_unique(k).first; diff --git a/include/boost/unordered/detail/type_traits.hpp b/include/boost/unordered/detail/type_traits.hpp index 3fe2f404..fd37a8e4 100644 --- a/include/boost/unordered/detail/type_traits.hpp +++ b/include/boost/unordered/detail/type_traits.hpp @@ -53,10 +53,10 @@ namespace boost { { }; - template struct are_transparent + template struct are_transparent { static bool const value = - is_transparent::value && is_transparent::value; + is_transparent::value && is_transparent::value; }; template struct transparent_non_iterable diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index ce09af90..16d4f3bd 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -278,24 +278,37 @@ namespace boost { template std::pair insert_or_assign(key_type const& key, M&& obj) { - auto iter_bool_pair = table_.try_emplace(key, std::forward(obj)); - if (iter_bool_pair.second) { - return iter_bool_pair; + auto ibp = table_.try_emplace(key, std::forward(obj)); + if (ibp.second) { + return ibp; } - iter_bool_pair.first->second = std::forward(obj); - return iter_bool_pair; + ibp.first->second = std::forward(obj); + return ibp; } template std::pair insert_or_assign(key_type&& key, M&& obj) { - auto iter_bool_pair = - table_.try_emplace(std::move(key), std::forward(obj)); - if (iter_bool_pair.second) { - return iter_bool_pair; + auto ibp = table_.try_emplace(std::move(key), std::forward(obj)); + if (ibp.second) { + return ibp; } - iter_bool_pair.first->second = std::forward(obj); - return iter_bool_pair; + ibp.first->second = std::forward(obj); + return ibp; + } + + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + std::pair >::type + insert_or_assign(K&& k, M&& obj) + { + auto ibp = table_.try_emplace(std::forward(k), std::forward(obj)); + if (ibp.second) { + return ibp; + } + ibp.first->second = std::forward(obj); + return ibp; } template @@ -311,6 +324,16 @@ namespace boost { .first; } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + iterator>::type + insert_or_assign(const_iterator, K&& k, M&& obj) + { + return this->insert_or_assign(std::forward(k), std::forward(obj)) + .first; + } + template BOOST_FORCEINLINE std::pair emplace(Args&&... args) { @@ -337,6 +360,17 @@ namespace boost { return table_.try_emplace(std::move(key), std::forward(args)...); } + template + BOOST_FORCEINLINE typename std::enable_if< + boost::unordered::detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(K&& key, Args&&... args) + { + return table_.try_emplace( + std::forward(key), std::forward(args)...); + } + template BOOST_FORCEINLINE iterator try_emplace( const_iterator, key_type const& key, Args&&... args) @@ -352,6 +386,18 @@ namespace boost { .first; } + template + BOOST_FORCEINLINE typename std::enable_if< + boost::unordered::detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator, K&& key, Args&&... args) + { + return table_ + .try_emplace(std::forward(key), std::forward(args)...) + .first; + } + BOOST_FORCEINLINE void erase(iterator pos) { table_.erase(pos); } BOOST_FORCEINLINE void erase(const_iterator pos) { @@ -427,6 +473,34 @@ namespace boost { std::out_of_range("key was not found in unordered_flat_map")); } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + mapped_type&>::type + at(K&& key) + { + auto pos = table_.find(std::forward(key)); + if (pos != table_.end()) { + return pos->second; + } + boost::throw_exception( + std::out_of_range("key was not found in unordered_flat_map")); + } + + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + mapped_type const&>::type + at(K&& key) const + { + auto pos = table_.find(std::forward(key)); + if (pos != table_.end()) { + return pos->second; + } + boost::throw_exception( + std::out_of_range("key was not found in unordered_flat_map")); + } + BOOST_FORCEINLINE mapped_type& operator[](key_type const& key) { return table_.try_emplace(key).first->second; @@ -437,6 +511,15 @@ namespace boost { return table_.try_emplace(std::move(key)).first->second; } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + mapped_type&>::type + operator[](K&& key) + { + return table_.try_emplace(std::forward(key)).first->second; + } + BOOST_FORCEINLINE size_type count(key_type const& key) const { auto pos = table_.find(key); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 29c53596..1599ba55 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -231,6 +231,15 @@ namespace boost { return table_.insert(std::move(value)); } + template + BOOST_FORCEINLINE typename std::enable_if< + detail::transparent_non_iterable::value, + std::pair >::type + insert(K&& k) + { + return table_.try_emplace(std::forward(k)); + } + BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value) { return table_.insert(value).first; @@ -241,6 +250,15 @@ namespace boost { return table_.insert(std::move(value)).first; } + template + BOOST_FORCEINLINE typename std::enable_if< + detail::transparent_non_iterable::value, + iterator>::type + insert(const_iterator, K&& k) + { + return table_.try_emplace(std::forward(k)).first; + } + template void insert(InputIterator first, InputIterator last) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 9d80d743..6d05471c 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -486,6 +486,16 @@ namespace boost { boost::move(k), boost::forward(args)...); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(Key&& k, Args&&... args) + { + return table_.try_emplace_unique( + boost::forward(k), boost::forward(args)...); + } + template iterator try_emplace( const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) @@ -502,6 +512,16 @@ namespace boost { hint, boost::move(k), boost::forward(args)...); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator hint, Key&& k, Args&&... args) + { + return table_.try_emplace_hint_unique( + hint, boost::forward(k), boost::forward(args)...); + } + #else // In order to make this a template, this handles both: @@ -582,6 +602,43 @@ namespace boost { boost::forward(a1), boost::forward(a2))); } + // try_emplace(Key&&, Args&&...) + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_unique( + boost::forward(k), boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace( + BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_unique(boost::forward(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0, + BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_unique(boost::forward(k), + boost::unordered::detail::create_emplace_args(boost::forward(a0), + boost::forward(a1), boost::forward(a2))); + } + // try_emplace(const_iterator hint, key const&, Args&&...) template @@ -640,6 +697,44 @@ namespace boost { boost::forward(a1), boost::forward(a2))); } + // try_emplace(const_iterator hint, Key&&, Args&&...) + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace( + const_iterator hint, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k), + boost::unordered::detail::create_emplace_args(boost::forward(a0), + boost::forward(a1), boost::forward(a2))); + } + #define BOOST_UNORDERED_TRY_EMPLACE(z, n, _) \ \ template \ @@ -706,6 +801,15 @@ namespace boost { boost::move(k), boost::forward(obj)); } + template + typename boost::enable_if_c::value, + std::pair >::type + insert_or_assign(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) + { + return table_.insert_or_assign_unique( + boost::forward(k), boost::forward(obj)); + } + template iterator insert_or_assign( const_iterator, key_type const& k, BOOST_FWD_REF(M) obj) @@ -722,6 +826,18 @@ namespace boost { .first; } + template + typename boost::enable_if_c::value, + iterator>::type + insert_or_assign( + const_iterator, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) + { + return table_ + .insert_or_assign_unique( + boost::forward(k), boost::forward(obj)) + .first; + } + iterator erase(iterator); iterator erase(const_iterator); size_type erase(const key_type&); @@ -856,9 +972,23 @@ namespace boost { mapped_type& operator[](const key_type&); mapped_type& operator[](BOOST_RV_REF(key_type)); + + template + typename boost::enable_if_c::value, + mapped_type&>::type + operator[](BOOST_FWD_REF(Key) k); + mapped_type& at(const key_type&); mapped_type const& at(const key_type&) const; + template + typename boost::enable_if_c::value, + mapped_type&>::type at(BOOST_FWD_REF(Key) k); + + template + typename boost::enable_if_c::value, + mapped_type const&>::type at(BOOST_FWD_REF(Key) k) const; + // bucket interface size_type bucket_count() const BOOST_NOEXCEPT @@ -878,6 +1008,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return table_.begin(n); @@ -1584,6 +1722,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return local_iterator(table_.begin(n)); @@ -2098,6 +2244,15 @@ namespace boost { return table_.try_emplace_unique(boost::move(k)).first->second; } + template + template + typename boost::enable_if_c::value, + typename unordered_map::mapped_type&>::type + unordered_map::operator[](BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_unique(boost::forward(k)).first->second; + } + template typename unordered_map::mapped_type& unordered_map::at(const key_type& k) @@ -2130,6 +2285,42 @@ namespace boost { std::out_of_range("Unable to find key in unordered_map.")); } + template + template + typename boost::enable_if_c::value, + typename unordered_map::mapped_type&>::type + unordered_map::at(BOOST_FWD_REF(Key) k) + { + typedef typename table::node_pointer node_pointer; + + if (table_.size_) { + node_pointer p = table_.find_node(boost::forward(k)); + if (p) + return p->value().second; + } + + boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + + template + template + typename boost::enable_if_c::value, + typename unordered_map::mapped_type const&>::type + unordered_map::at(BOOST_FWD_REF(Key) k) const + { + typedef typename table::node_pointer node_pointer; + + if (table_.size_) { + node_pointer p = table_.find_node(boost::forward(k)); + if (p) + return p->value().second; + } + + boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + template typename unordered_map::size_type unordered_map::bucket_size(size_type n) const diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index a054ed64..1bd4ba3d 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -390,6 +390,15 @@ namespace boost { return this->emplace(boost::move(x)); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + insert(BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_unique(boost::forward(k)); + } + iterator insert(const_iterator hint, value_type const& x) { return this->emplace_hint(hint, x); @@ -400,6 +409,15 @@ namespace boost { return this->emplace_hint(hint, boost::move(x)); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + insert(const_iterator hint, BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k)); + } + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -571,6 +589,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return local_iterator(table_.begin(n)); @@ -1212,6 +1238,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return local_iterator(table_.begin(n)); diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 9852fa84..8d1f781b 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1478,6 +1478,312 @@ template void test_map_non_transparent_extract() #endif } +template void test_map_transparent_try_emplace() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + + std::pair r = map.try_emplace(0, 7331); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_NOT(r.second); + BOOST_TEST_EQ(key::count_, key_count); + + r = map.try_emplace(4, 7331); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + + iterator p = map.try_emplace(map.cbegin(), 0, 7331); + BOOST_TEST(p == map.find(0)); + BOOST_TEST_EQ(key::count_, key_count); + + p = map.try_emplace(map.begin(), 5, 7331); + BOOST_TEST(p == map.find(5)); + BOOST_TEST_EQ(key::count_, key_count + 1); +} + +template void test_map_non_transparent_try_emplace() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + + std::pair r = map.try_emplace(0, 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_NOT(r.second); + + key_count = key::count_; + r = map.try_emplace(4, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + + key_count = key::count_; + iterator p = map.try_emplace(map.cbegin(), 0, 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(p == map.find(0)); + + key_count = key::count_; + p = map.try_emplace(map.begin(), 5, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(p == map.find(5)); +} + +template void test_map_transparent_insert_or_assign() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + + std::pair r = map.insert_or_assign(0, 7331); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_EQ(r.first->second, 7331); + BOOST_TEST_NOT(r.second); + BOOST_TEST_EQ(key::count_, key_count); + + r = map.insert_or_assign(4, 7331); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + + iterator p = map.insert_or_assign(map.cbegin(), 0, 1111); + BOOST_TEST(p == map.find(0)); + BOOST_TEST_EQ(p->second, 1111); + BOOST_TEST_EQ(key::count_, key_count); + + p = map.insert_or_assign(map.begin(), 5, 7331); + BOOST_TEST(p == map.find(5)); + BOOST_TEST_EQ(key::count_, key_count + 1); +} + +template void test_map_non_transparent_insert_or_assign() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + + std::pair r = map.insert_or_assign(0, 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_EQ(r.first->second, 7331); + BOOST_TEST_NOT(r.second); + + key_count = key::count_; + r = map.insert_or_assign(4, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + + key_count = key::count_; + iterator p = map.insert_or_assign(map.cbegin(), 0, 1111); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(p == map.find(0)); + BOOST_TEST_EQ(p->second, 1111); + + key_count = key::count_; + p = map.insert_or_assign(map.begin(), 5, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(p == map.find(5)); +} + +template void test_map_transparent_subscript() +{ + count_reset(); + + UnorderedMap map; + + map[0] = 1337; + map[1] = 1338; + map[2] = 1339; + map[0] = 1340; + map[0] = 1341; + map[0] = 1342; + + int key_count = key::count_; + + map[0] = 7331; + BOOST_ASSERT(BOOST_TEST_EQ(key::count_, key_count)); + + map[4] = 7331; + BOOST_TEST_EQ(key::count_, key_count + 1); +} + +template void test_map_non_transparent_subscript() +{ + count_reset(); + + UnorderedMap map; + + map[0] = 1337; + map[1] = 1338; + map[2] = 1339; + map[0] = 1340; + map[0] = 1341; + map[0] = 1342; + + int key_count = key::count_; + + map[0] = 7331; + BOOST_ASSERT(BOOST_TEST_EQ(key::count_, key_count + 1)); + + key_count = key::count_; + map[4] = 7331; + BOOST_TEST_EQ(key::count_, key_count + 2); +} + +template void test_map_transparent_at() +{ + count_reset(); + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + + map.at(0) = 7331; + BOOST_TEST_EQ(key::count_, key_count); + + BOOST_TEST_THROWS(map.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count); + + UnorderedMap const& m = map; + BOOST_TEST_EQ(m.at(0), 7331); + BOOST_TEST_EQ(key::count_, key_count); + + BOOST_TEST_THROWS(m.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count); +} + +template void test_map_non_transparent_at() +{ + count_reset(); + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + + map.at(0) = 7331; + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + BOOST_TEST_THROWS(map.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + UnorderedMap const& m = map; + BOOST_TEST_EQ(m.at(0), 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + BOOST_TEST_THROWS(m.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count + 1); +} + +template void test_map_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + map.bucket(0); + map.bucket(4); + BOOST_TEST_EQ(key::count_, key_count); +#endif +} + +template void test_map_non_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedMap map; + + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int key_count = key::count_; + map.bucket(0); + map.bucket(4); + BOOST_TEST_EQ(key::count_, key_count + 2); +#endif +} + #ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_set::node_type set_extract_overload_compile_test() { @@ -1626,6 +1932,134 @@ template void test_set_non_transparent_extract() #endif } +template void test_set_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + set.bucket(0); + set.bucket(4); + BOOST_TEST_EQ(key::count_, key_count); +#endif +} + +template void test_set_non_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + set.bucket(0); + set.bucket(4); + BOOST_TEST_EQ(key::count_, key_count + 2); +#endif +} + +template void test_set_transparent_insert() +{ + count_reset(); + + typedef typename UnorderedSet::iterator iterator; + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + + std::pair p = set.insert(0); + BOOST_TEST(p.first == set.find(0)); + BOOST_TEST_NOT(p.second); + BOOST_TEST_EQ(key::count_, key_count); + + key_count = key::count_; + p = set.insert(4); + BOOST_TEST(p.first == set.find(4)); + BOOST_TEST(p.second); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + iterator pos = set.insert(set.begin(), 0); + BOOST_TEST(pos == set.find(0)); + BOOST_TEST_EQ(key::count_, key_count); + + key_count = key::count_; + pos = set.insert(set.begin(), 5); + BOOST_TEST(pos == set.find(5)); + BOOST_TEST_EQ(key::count_, key_count + 1); + + // check for collisions with insert(iterator, iterator) + // note: this precludes Key from being convertible to an iterator which isn't + // explicitly stated by p2363r3 + // + set.insert(set.begin(), set.end()); +} + +template void test_set_non_transparent_insert() +{ + count_reset(); + + typedef typename UnorderedSet::iterator iterator; + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + + std::pair p = set.insert(0); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(p.first == set.find(0)); + BOOST_TEST_NOT(p.second); + + key_count = key::count_; + p = set.insert(4); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(p.first == set.find(4)); + BOOST_TEST(p.second); + + key_count = key::count_; + iterator pos = set.insert(set.begin(), 0); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(pos == set.find(0)); + + key_count = key::count_; + pos = set.insert(set.begin(), 5); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(pos == set.find(5)); + + set.insert(set.begin(), set.end()); +} + template struct map_type { #ifdef BOOST_UNORDERED_FOA_TESTS @@ -1646,6 +2080,11 @@ void test_unordered_map() test_map_transparent_equal_range(); test_map_transparent_erase(); test_map_transparent_extract(); + test_map_transparent_try_emplace(); + test_map_transparent_insert_or_assign(); + test_map_transparent_subscript(); + test_map_transparent_at(); + test_map_transparent_bucket(); } { @@ -1658,6 +2097,11 @@ void test_unordered_map() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_try_emplace(); + test_map_non_transparent_insert_or_assign(); + test_map_non_transparent_subscript(); + test_map_non_transparent_at(); + test_map_non_transparent_bucket(); } { @@ -1671,6 +2115,11 @@ void test_unordered_map() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_try_emplace(); + test_map_non_transparent_insert_or_assign(); + test_map_non_transparent_subscript(); + test_map_non_transparent_at(); + test_map_non_transparent_bucket(); } { @@ -1684,6 +2133,11 @@ void test_unordered_map() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_try_emplace(); + test_map_non_transparent_insert_or_assign(); + test_map_non_transparent_subscript(); + test_map_non_transparent_at(); + test_map_non_transparent_bucket(); } } @@ -1700,6 +2154,7 @@ void test_unordered_multimap() test_map_transparent_equal_range(); test_map_transparent_erase(); test_map_transparent_extract(); + test_map_transparent_bucket(); } { @@ -1713,6 +2168,7 @@ void test_unordered_multimap() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_bucket(); } { @@ -1726,6 +2182,7 @@ void test_unordered_multimap() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_bucket(); } { @@ -1739,6 +2196,7 @@ void test_unordered_multimap() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_bucket(); } } #endif @@ -1763,6 +2221,8 @@ void test_unordered_set() test_set_transparent_erase(); test_set_transparent_equal_range(); test_set_transparent_extract(); + test_set_transparent_bucket(); + test_set_transparent_insert(); } { @@ -1775,6 +2235,8 @@ void test_unordered_set() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); + test_set_non_transparent_insert(); } { @@ -1787,6 +2249,8 @@ void test_unordered_set() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); + test_set_non_transparent_insert(); } { @@ -1799,6 +2263,8 @@ void test_unordered_set() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); + test_set_non_transparent_insert(); } } @@ -1815,6 +2281,7 @@ void test_unordered_multiset() test_set_transparent_erase(); test_set_transparent_equal_range(); test_set_transparent_extract(); + test_set_transparent_bucket(); } { @@ -1827,6 +2294,7 @@ void test_unordered_multiset() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } { @@ -1840,6 +2308,7 @@ void test_unordered_multiset() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } { @@ -1853,6 +2322,7 @@ void test_unordered_multiset() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } } #endif