On 22/05/21 18:35 +0200, François Dumont wrote:
This was indeed the right approach.
The only minor drawback is that __is_noexcept_invocable<> combines
noexcept qualification of the conversion and of the hash functor. So
if the hash functor is not noexcept we could end up creating
temporaries for nothing.
So I've eventually used this condition:
__and_<__is_nothrow_invocable<_Hash&, const key_type&>,
__not_<__is_nothrow_invocable<_Hash&, _Kt>>>::value,
so that we do not create a temporary key_type if invoking _Hash
with it can still throw.
libstdc++: Limit allocation on iterator insertion in Hashtable [PR
96088]
When inserting into unordered_multiset or unordered_multimap first
instantiate
the node to store and compute the hash code from it to avoid a
potential
intermediate key_type instantiation.
When inserting into unordered_set or unordered_map check if
invoking the hash
functor with container key_type is noexcept and invoking the same
hash functor
with key part of the iterator value_type can throw. In this case
create a
temporary key_type instance at Hashtable level and use it to
compute the hash
code. This temporary instance is moved to the final storage
location if needed.
libstdc++-v3/ChangeLog:
PR libstdc++/96088
* include/bits/hashtable_policy.h (_Select2nd): New.
(_NodeBuilder<>): New.
(_ReuseOrAllocNode<>::operator()): Use variadic template args.
(_AllocNode<>::operator()): Likewise.
* include/bits/hashtable.h
(_Hashtable<>::__node_builder_t): New.
(_Hashtable<>::_M_insert_unique<>(_Kt&&, _Arg&&, const _NodeGenerator&)):
New.
(_Hashtable<>::_S_forward_key): New.
(_Hashtable<>::_M_insert): Use latter.
(_Hashtable<>::_M_insert(const_iterator, _Arg&&, const
_NodeGenerator&, false_type)):
Instantiate node first, compute hash code second.
* testsuite/23_containers/unordered_map/96088.cc: New test.
* testsuite/23_containers/unordered_multimap/96088.cc: New
test.
* testsuite/23_containers/unordered_multiset/96088.cc: New
test.
* testsuite/23_containers/unordered_set/96088.cc: New test.
* testsuite/util/replacement_memory_operators.h
(counter::_M_increment): New.
(counter::_M_decrement): New.
(counter::reset()): New.
Tested under Linux x64.
Ok to commit ?
OK for trunk, thanks.