-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
<flat_map>
: Can we separately compare key and mapped containers?
#5075
Comments
However, I think the wording in [container.reqmts]/44 still suggests that keys and values should be compared alternatingly. So are standard-compliant programs allowed to assume this alternation or observe divergence from it? |
The fact that both of the cited paragraphs are "Returns" elements is significant. They specify only the value that a function is expected to return, not a means by which that value is to be calculated nor any of the observable effects of doing so. See [structure.specifications]/3.8 which says that it's "a description of the value(s) returned by the function." We must return the same value as depicted in the Standard, but we may calculate that value in the way we deem to be best for our implementation. (I don't feel bad for anyone that puts incomparable values in a standard container and then tries to compare that container.) |
Oh, I'm sorry for forgetting LWG-3410. Is it intended that If so, I think we can try the strategy that compares key containers first. |
Yeah, but this alone is not sufficient for the transformation: If That said, designing such questionable equality comparators is just asking for trouble, so it's probably not worth thinking much about.
Yes, it may do more comparisons. But I doubt comparing keys first is worth it in terms of complexity of the implementation and computational runtime. First, the code transformation is not straightforward. To produce the same result, you would have to compute the index where keys first compare non-equal, then determine the index where values first compare non-equal and finally return the ordering at the smaller of these two indices. So you can't just delegate to Second, while you can get away with not fully determining the index for the values if it is the larger one, you have to determine the index for keys accurately if you decide to compare the keys first. And that means you might do lots of unnecessary comparisons between keys. |
We talked about this at the weekly maintainer meeting. We don't believe that the Standard should require us to tolerate non-comparable elements here. (We think the Standard's vagueness supports us here.) As for performance, we expect most equality comparisons to find equality, in which case all keys and all values must be inspected, so separately comparing the keys and then the values is better for locality (for all types) and better for vectorization. For spaceship, @StephanTLavavej thinks this will be uncommon for |
While I can't provide a benchmark, here is a back-of-the-envelope calculation how many more (key) comparisons the algorithm separating key and value comparison is expected to do compared to the alternating algorithm (which is optimal in the number of performed comparisons): Let's assume that comparisons are independent and that the probability that a pair of keys or a pair of values compares different is For simplicity of calculation, let's also assume that the algorithms are applied to sequences of infinite size. Then (Note that this calculation breaks down for containers of |
Currently, we're implementing
flat_(multi)map
's comparison operators in inconsistent ways:STL/stl/inc/flat_map
Lines 769 to 774 in fbe5394
STL/stl/inc/flat_map
Lines 776 to 780 in fbe5394
For
operator==
, key and mapped containers are compared separately. Foroperator<=>
, they are compared step by step together.It seems to me that the standard wording only specifies the latter ([container.reqmts]/44, [container.opt.reqmts]/4). The current strategy for
operator==
possibly incorrectly behaves if the comparison beyond the index of the first inequivalent iterator pair doesn't have well-defined result (i.e. causes UB, terminates, or throws an exception).E.g. if
_Left_base._Data.values[0] != _Right_base._Data.values[0]
, perhaps we're generally disallowed to compare_Left_base._Data.keys[1]
with_Right_base._Data.keys[1]
.However, the separately comparing strategy might still be viable if the element types are "well-behaving" enough (e.g. if they are arithmetic types, or possibly
string
?).The text was updated successfully, but these errors were encountered: