[PATCH] libstdc++/91223 Improve unordered containers == operator
Jonathan Wakely
jwakely@redhat.com
Tue Jan 14 11:07:00 GMT 2020
On 13/01/20 22:41 +0100, François Dumont wrote:
>On 1/10/20 11:01 PM, Jonathan Wakely wrote:
>>On 10/01/20 18:54 +0100, François Dumont wrote:
>>>Hi
>>>
>>> Here is my attempt to improve == operator.
>>>
>>> There is a small optimization for the std::unordered_mutiXXX
>>>containers but the main enhancement rely on some partial template
>>>specialization of the _Equality type. I limit it to usage of
>>>unordered containers with std::equal_to to be sure that the
>>>container _Equal functor is like the key type ==.
>>
>>I think we can assume that for any _Equal, not just std::equal_to:
>>http://eel.is/c++draft/unord.req#12.sentence-5
>>
>>However ...
>
>Ok but...
>
>>
>>> Do I need to also consider user partial template
>>>specialization of std::equal_to ? It is a well know bad practice
>>>so I hope the Standard says that such a partial specialization
>>>leads to undefined behavior.
>>
>>It's certainly not undefined to specialize equal_to, and I'm not sure
>>how to make your optimisations valid in that case.
>
>This proposal is indeed invalid if you use a std::equal_to partial
>specialization, this is why I asked.
>
>>
>>Consider:
>>
>>struct X
>>{
>> int i;
>> int rounded() const { return i - (i % 10); }
>> bool operator==(X x) const { return i == x.i; }
>>};
>>
>>template<> struct std::equal_to<X>
>>{
>> bool operator()(X l, X r) const
>> { return l.rounded() == r.rounded(); }
>>};
>>
>>template<> std::hash<X>
>>{
>> bool operator()(X x) const { return hash<int>()(x.rounded()); }
>>};
>>
>>std::unordered_multiset<X> u{ X{10}, X{11}, X{12} };
>>std::unordered_multiset<X> v{ X{15}, X{16}, X{17} };
>>bool b1 = u == v;
>>bool b2 = std::is_permutation(u.begin(), u.end(), v.begin());
>>assert(b1 == b2);
>>
>>I think the last new specialization in your patch would be used for
>>this case, and because __x_count == v.count(*u.begin()) it will say
>>they're equal. But the is_permutation call says they're not.
>>
>>So I think the assertion would fail, but the standard says it should
>>pass. Am I mistaken?
>
>I agree, it would fail and the Standard says it should pass.
>
>So here is a new proposal. For the unique keys case I think we are
>good, I do not see any other optimization.
>
>For the multi-keys we could still avoid redundant comparisons when
>_Equal is just doing == on the key type. On unordered_multiset we
>could just avoids the call to is_permuation and on the
>unordered_multimap we could check the is_permutation only on the
>associated value rather than on the std::pair.
>
>In order to detect that _Equal is the std::equal_to from
>stl_function.h it would be great to have something like a
>__builtin_is_system returning true for types defined in system
>headers. For now I try to propose something similar without compiler
>help.
I don't think that's necessary, or helpful.
The idea of https://gcc.gnu.org/ml/libstdc++/2020-01/msg00070.html is
that you shouldn't be using _Equal at all, and therefore it doesn't
matter whether it's std::equal_to or not.
More information about the Libstdc++
mailing list