-
Notifications
You must be signed in to change notification settings - Fork 49
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
basic drain
and into_iter
implementations
#33
Conversation
Codecov Report
|
…ry into implement_drain_and_into_iter
so that both threads start more syncronously
I'm a little strapped for time at the moment, but one thing to keep in mind is what exactly the contract is for std::mem::forget(map.drain()); Is |
I assumed this would get hard, but I thought I'd just experiment with it for a bit and see how far I get... I think there are two ways we can go about this:
The main difference is that the first option will also remove elements added during the drain while the second one is guaranteed to stop when it iterated over all the keys in it's snapshot, but has to store all of those keys somewhere... Regarding the return Value there are also two options:
But the first option will result in returning an I personally tend towards not Snapshotting the map, just returning a I'd be interested in hearing your opinion on this, but I probably also won't have too much free time until next weekend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ISTM that since you clone the keys, you should also be cloning the values.
Alternatively, for Drain
you could just return references (&'g K, &'g V)
which the user could choose to clone. Then the difference from plain Iter
is just that they are marked for removal along the way.
IntoIter
should have exclusive ownership of the map, no outstanding references, so it just needs a way for the map to avoid re-dropping items that the iterator already returned, like a true immediate removal.
src/iter/iter.rs
Outdated
|
||
if let Some(value) = self.map.remove(&node.key, self.guard) { | ||
return Some((node.key.clone(), unsafe { | ||
std::ptr::read(value as *const V) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this lead to a double-drop of V
? Once for the internal guard.defer_destroy(val)
, and again whenever the user is done with this read
copy of the value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I added this when playing around with giving the user a V
instead of a &V
, but we probably should just always give out &V
s and let them clone when they need to...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be nice to have the same signature as std::HashMap
, but since we're not implementing a trait I guess we can just have the user deal with it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fixed now. I'll write some tests to make sure there actually aren't any double-frees tomorrow.
|
||
let key = node.key.clone(); | ||
let value = node.value.load(Ordering::SeqCst, self.guard); | ||
let value = unsafe { std::ptr::read(value.as_ref().unwrap() as *const V) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also seems like a double-drop of the value, between the returned value and the whole map dropping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
Are we sure that's true? I think, since we load our values under the guard, the user can still have references to them even if they don't have access to the map anymore. I could be wrong about that though. Thank you for taking a look at this |
AFAIK all user references have double-borrowed lifetimes, from both |
Nice, we're good then, I wasn't sure if all |
FWIW, there's similar reasoning about exclusive access in Lines 1389 to 1396 in 9544337
|
drain now returns references reworked `IntoIter`
…ry into implement_drain_and_into_iter
I added that comment in |
I'm going to close this for the time being, and then we can re-open if you find time to pick it up again @soruh :) |
@jonhoo Great, thank you. I'll probably still be quite busy for a while but I should be able to contribute to discussions regarding this. |
I just took a quick look at implementing
drain
andinto_iter
.The tests seem to pass, but that might just be luck.
This code should probably not be merged, since it seems horrendously inefficient, but maybe it can be used to work towards an actual implementation.