Closed ToMe25 closed 4 months ago
I have one more optimization idea, which I will try tomorrow.
I honestly don't think any optimizations I will think of will cause a significant improvement at this point, so I'll stop trying around now :)
* It removes the `A: Allocator` generics bound from `BitOr` and `BitAnd`. It doesn't seem to be used for anything, and `Xor` and `Sub` already don't have it. I'd be fine with reverting that and adding it to the other operators as well, I just thought having it inconsistent was weird.
Actually it should be the other way around: these traits should be implemented for HashSet
with any A
, not just Global
(which is the default if you omit it).
I checked the standard library and it has the same issue. This should be fixed once hashbrown is updated in the standard library.
* It adds and implementation for `Add` for convenience. This does the same as `BitOr`, so let me know if I should remove it.
I don't think it makes sense to add this just for convenience. It would introduce confusion since now you have 2 operators that do the same thing.
Whoops, I forgot default generics are a thing and thought "No specified bound == No bound".
I'll add the Allocator bound everywhere and remove Add
and AddAssign
then.
I might not get around to that today, but if not I'll do it tomorrow.
Would adding "Add" as an alias to "BitOr" be fine, if libraries that aren't STD are allowed to do that?
I would prefer if Add
was not implemented at all.
I meant a doc alias, but thats fine too, then I just wont.
A doc alias wouldn't work well since it would only trigger if you specifically search for "add". It is unlikely you are specifically looking for set union in that case: you would most likely be searching for arithmetic addition.
Fair enough, if one purposefully searches the docs one will probably notice that for a set BitOr
and Add
would be the same soon anyway.
Oh btw the non-assign performance would have changed due to #530 being merged, do I have to re-test them all or is it fine to leave the PR description as is?
It's fine to leave the benchmark results as they are, but the rest of the description will need updating.
Yes, of course, once I implemented the changes I will go over everything in the description and adjust it to the changes in the PR. Its just that due to this PR not being currently on top of master benchmarking the changed non-assign ops vs the assign ops would be somewhat time consuming, so I wanted to avoid that if possible.
I implemented the changes I said I would, and rebased because of the recent CI fixes.
Though now I wonder: Would it be better to change the A
bound to Allocator + Default
and return a new set with the same type of allocator as the input sets?
Right now the resulting set always uses the default allocator.
Alternatively it would also be possible to change the bound to Allocator + Clone
and use a clone of the self allocator.
I believe that now would be the best time to add a restriction to Allocator + Default
, because right now that would only be a new restriction for two of the traits, while the other two would still be more relaxed, just not as much.
Another question would be whether set operations between sets with different allocators should be allowed.
If yes it might make sense to only restrict the self allocator to Allocator + Default
and leave the other allocator at Allocator
.
Though I would split this change into a separate PR, if it is wanted at all.
One other thing is that while I generally intend to port my recent hashbrown PR's to STD(atleast those which result in behavior changes), I wont have the time to do so in the next 3-4 weeks.
Another question would be whether set operations between sets with different allocators should be allowed. If yes it might make sense to only restrict the self allocator to
Allocator + Default
and leave the other allocator atAllocator
.
I don't think we should do this because then the operation becomes too generic and the compiler can't infer the correct allocator type to use.
Though now I wonder: Would it be better to change the
A
bound toAllocator + Default
and return a new set with the same type of allocator as the input sets? Right now the resulting set always uses the default allocator. Alternatively it would also be possible to change the bound toAllocator + Clone
and use a clone of the self allocator.
Allocator + Default
seems like the best way forward.
Ok, done, I implemented the Allocator + Default
change for the non-assigning set ops.
@bors r+
:pushpin: Commit 481ef396bf7c45c66adb42f00590a242085ddb1c has been approved by Amanieu
It is now in the queue for this repository.
:hourglass: Testing commit 481ef396bf7c45c66adb42f00590a242085ddb1c with merge f0eece41a0e46145692adb0bc9627b01f95ec4a5...
:sunny: Test successful - checks-actions Approved by: Amanieu Pushing f0eece41a0e46145692adb0bc9627b01f95ec4a5 to master...
This PR primarily implements the XxxAssign operation traits for
HashSet
.My primary motivation to do so is for convenience, but depending on the situation they can provide a significant performance improvement as well.*
In my tests, which may not be ideal because I don't have much benchmarking experience, the assigning operations are, with the exception of
Sub
, a minimum of 25% faster.*Note that when swapping the large and the small set around, some of these are significantly slower than the non-assigning variant.
Therefore using them is likely only worth it performance wise, if you already know which set is larger, and the right one of the sets just so happens to be the one you don't need to keep.
* Results may have changed due to #530 being merged
Here my exact benchmark results, done with the newly added benchmark suit:
<!DOCTYPE html>
In addition to the Assigning operators this PR changes a few more things:
A: Allocator + Default
.