This is an archive of the discontinued LLVM Phabricator instance.

[libc++] Use multi-key tree search for {map, set}::{count, equal_range}
ClosedPublic

Authored by ng on Jan 20 2018, 7:49 PM.

Details

Summary

As described in http://bugs.llvm.org/show_bug.cgi?id=30959, the current implementation of std::{map, key}::{count, equal_range} in libcxx is non-conforming. Quoting ISO/IEC 14882:2014 section 23.2.4:

The phrase “equivalence of keys” means the equivalence relation imposed by the comparison and not the
operator== on keys. That is, two keys k1 and k2 are considered to be equivalent if for the comparison
object comp, comp(k1, k2) == false && comp(k2, k1) == false.

In the same section, the requirements table states the following:

a.equal_range(k) equivalent to make_pair(a.lower_bound(k), a.upper_bound(k))
a.count(k) returns the number of elements with key equivalent to k

The behaviour of libstdc++ seems to conform to the standard here.

Diff Detail

Event Timeline

ng created this revision.Jan 20 2018, 7:49 PM

Could you provide tests that demonstrate the previously incorrect behavior?

rsmith added a subscriber: rsmith.Jan 20 2018, 9:44 PM

Shouldn't we be changing only the heterogeneous functions here?

@rsmith Yes. I agree this should only be applied in that case

ng updated this revision to Diff 130812.Jan 21 2018, 8:54 AM

As per the above suggestions, enabled _multi tree search only for transparent comparator functions, and added tests.

Sometimes you get lucky ;-)
I have a task for next week that says "The transparent lookup stuff in the associative containers needs tests", and here is this patch.

Instead of "transparent_count.pass.cpp", please name the test "count_transparent.pass.cpp" so it will sort with all the other count tests.

libcxx/test/std/containers/associative/map/map.ops/transparent_count.pass.cpp
25 ↗(On Diff #130812)

Instead of this, just put

//  UNSUPPORTED:  c++98, c++03, c++11

near the top of the file.

libcxx/test/std/containers/associative/map/map.ops/transparent_equal_range.pass.cpp
28 ↗(On Diff #130812)

Same here.

libcxx/test/std/containers/associative/set/transparent_count.pass.cpp
27 ↗(On Diff #130812)

same here.

libcxx/test/std/containers/associative/set/transparent_equal_range.pass.cpp
29 ↗(On Diff #130812)

and here.

mclow.lists added a comment.EditedJan 21 2018, 9:21 AM
This comment has been deleted.
ng added a comment.Jan 21 2018, 9:24 AM

Shouldn't there be tests for multimap and multiset, too?

Sure; will the same tests as for map/set be alright?

In D42344#983265, @ng wrote:

Shouldn't there be tests for multimap and multiset, too?

Sure; will the same tests as for map/set be alright?

Actually, I think there are already tests for multimap and multiset.
(which is why I deleted my comment)

But the tests there are not like these, where the comparator uses only part of the key.
So, yes; same tests would be OK - but you might want to adjust the data so that there are duplicate keys.

ng updated this revision to Diff 130814.Jan 21 2018, 9:46 AM

Renamed tests for map/set, and added multimap/multiset tests

ng updated this revision to Diff 130817.Jan 21 2018, 10:57 AM

Fix multiset variable definition in tests

ng added a comment.Feb 9 2018, 12:42 AM

Could you please commit this on my behalf? I don't have commit access.

EricWF accepted this revision.Feb 9 2018, 6:44 PM
This revision is now accepted and ready to land.Feb 9 2018, 6:44 PM
EricWF closed this revision.Feb 9 2018, 6:55 PM

Committed as r324799.

Thank you!