Skip to content
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

Adds a OrderMap::drain() method #27

Merged
merged 2 commits into from
Apr 29, 2017
Merged

Adds a OrderMap::drain() method #27

merged 2 commits into from
Apr 29, 2017

Conversation

stevej
Copy link
Contributor

@stevej stevej commented Apr 20, 2017

Problem:
Porting some code that used HashMap's drain to OrderMap revealed a small
API gap.

Solution:
Added a drain method, mostly mirroring what std::collections::HashMap
offers except returning a standard Vec instead of a Drain.

drain() provides an efficient way to remove all values without shrinking
the capacity of the original OrderMap.

Validation:
Added unit tests and ported an existing HashMap::drain() user to
OrderMap::drain

@carllerche
Copy link

carllerche commented Apr 20, 2017

I'd probably try to avoid requiring the allocations as part of drain.

I'd suggest adding a new Drain type. Something like:

struct Drain<'a, K, V> {
    inner: std::vec::Drain<'a, Bucket<K, V>>,
}

Then, impl Iterator on drain to map out (K, V) in Iterator::next.

I'd probably also try to avoid the vec! allocation when resetting indices. Iterating the list and setting each entry to Pos::none() should be sufficient.

Problem:
Porting some code that used HashMap's drain to OrderMap revealed a small
API gap.

Solution:
Added a drain method, mirroring std::collection::HashMap's drain method.

drain() provides an efficient way to remove all values without shrinking
the capacity of the original OrderMap.

Validation:
Added unit tests and ported an existing HashMap::drain() user to
OrderMap::drain
@stevej
Copy link
Contributor Author

stevej commented Apr 20, 2017

Thank you, Carl! I rewrote the code to address those concerns. Please let me know if I made a mistake, I haven't implemented that many Iterators in Rust.

Copy link
Member

@bluss bluss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks both, it looks good this way.

OrderMap is an indexed hash map but I'm not sure we should hold this up for that, because we need to do some complicated index shifting if we remove a range.

Ideally we should implement an indexed drain, that follows the trajectory that the data structure is on. However it is also not receiving much of my time so I wouldn't have time to review something more involved.

What do you think of introducing this with a mandatory .. as argument? It would be a weird placeholder inbetween.

src/lib.rs Outdated
@@ -400,6 +400,18 @@ impl<K, V, S> OrderMap<K, V, S>
pub fn capacity(&self) -> usize {
usable_capacity(self.raw_capacity())
}

/// Clears the `OrderMap`, returning all key-value pairs as a `Drain`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iterators don't really have a type-identity, they are peculiar that way. The struct is just a vehicle for the implementation, so we don't call it a Drain but maybe a drain iterator.

I think that the method should move down the method list to be placed at a location that degrades it in importance and where users more expect it... after the other iterator methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

method moved.

src/lib.rs Outdated
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|bucket| (bucket.key, bucket.value))
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add size_hint, it's the next important iterator method. If the other OrderMap iterators are exact size iterators, this one should be too. I'm not too exited for any other iterator method implementations, we don't necessarily need those.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added by delegating to inner.size_hint()

src/lib.rs Outdated

#[test]
fn drain_basic() {
let mut map_a = OrderMap::new();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Not very actionable comment)

Quickcheck tests are always better than example tests. In this case we reuse a solid std iterator and we don't really need any particular test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've replaced the example unit tests with a drain quickcheck test. This is my first time using Rust's quickcheck, please let me know if you think I made some newbie error.

@carllerche
Copy link

@bluss the main problem w/ taking an argument right now is that RangeArgument isn't stable... maybe name the fn drain_all for now and reserve drain for when the trait does hit stable? Then deprecate drain_all.

@bluss
Copy link
Member

bluss commented Apr 24, 2017

unstable RangeArgument is not a problem. Simply provide an equivalent trait. (Arrayvec does this).

@bluss
Copy link
Member

bluss commented Apr 24, 2017

Even less of a problem is doing the simple stopgap solution which is to take a single .. as an argument in the initial version.

* Replaced unit tests with quickcheck tests.
* Added a size_hint method.
* drain now takes a `..` argument.
@stevej
Copy link
Contributor Author

stevej commented Apr 26, 2017

Let me know if you'd rather I squashed this into a single logical commit.

@bluss bluss merged commit 0096328 into indexmap-rs:master Apr 29, 2017
@bluss
Copy link
Member

bluss commented Apr 29, 2017

Thanks!

@bluss bluss mentioned this pull request Apr 29, 2017
21 tasks
@bluss
Copy link
Member

bluss commented Apr 29, 2017

This checks off an item on HashMap consistency list but adds another (That's my meddling).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants