From f8cfad8aaef749e2605d20358f11ae600c4690eb Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Mon, 7 Jan 2019 19:05:18 +0100 Subject: [PATCH 1/3] Implement `size_hint` and `ExactSizeIterator` for all three iterators --- CHANGELOG.md | 3 +++ src/lib.rs | 43 +++++++++++++++++++++++++++++++++++++++---- src/tests.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68dc41a..9b3af6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- All three iterators implement `Iterator::size_hint` and `ExactSizeIterator` + now and report the correct length. ## [0.2.1] - 2018-09-26 ### Added diff --git a/src/lib.rs b/src/lib.rs index 76f5cdc..cf7af32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -731,7 +731,7 @@ impl StableVec { /// } /// ``` pub fn iter(&self) -> Iter { - Iter { sv: self, pos: 0 } + Iter { sv: self, pos: 0, count: self.used_count } } /// Returns an iterator over mutable references to the existing elements @@ -781,6 +781,7 @@ impl StableVec { pub fn iter_mut(&mut self) -> IterMut { IterMut { deleted: &mut self.deleted, + count: self.used_count, used_count: &mut self.used_count, vec_iter: self.data.iter_mut(), pos: 0, @@ -817,6 +818,7 @@ impl StableVec { Keys { deleted: &self.deleted, pos: 0, + count: self.used_count, } } @@ -1068,16 +1070,28 @@ impl<'a, T> IntoIterator for &'a mut StableVec { pub struct Iter<'a, T: 'a> { sv: &'a StableVec, pos: usize, + count: usize, } impl<'a, T: 'a> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { - next_valid_index(&mut self.pos, &self.sv.deleted) - .map(|i| &self.sv.data[i]) + let out = next_valid_index(&mut self.pos, &self.sv.deleted) + .map(|i| &self.sv.data[i]); + if out.is_some() { + self.count -= 1; + } + + out + } + + fn size_hint(&self) -> (usize, Option) { + (self.count, Some(self.count)) } } +impl ExactSizeIterator for Iter<'_, T> {} + /// Iterator over mutable references to the elements of a `StableVec`. /// /// Use the method [`StableVec::iter_mut()`](struct.StableVec.html#method.iter_mut) @@ -1089,6 +1103,7 @@ pub struct IterMut<'a, T: 'a> { used_count: &'a mut usize, vec_iter: ::std::slice::IterMut<'a, T>, pos: usize, + count: usize, } impl<'a, T: 'a> IterMut<'a, T> { @@ -1124,11 +1139,19 @@ impl<'a, T> Iterator for IterMut<'a, T> { } else { // Advance the iterator by one and return current element. self.pos += 1; + self.count -= 1; self.vec_iter.next() } } + + fn size_hint(&self) -> (usize, Option) { + (self.count, Some(self.count)) + } } +impl ExactSizeIterator for IterMut<'_, T> {} + + /// Iterator over all valid indices of a `StableVec`. /// /// Use the method [`StableVec::keys()`](struct.StableVec.html#method.keys) to @@ -1137,15 +1160,27 @@ impl<'a, T> Iterator for IterMut<'a, T> { pub struct Keys<'a> { deleted: &'a BitVec, pos: usize, + count: usize, } impl<'a> Iterator for Keys<'a> { type Item = usize; fn next(&mut self) -> Option { - next_valid_index(&mut self.pos, self.deleted) + let out = next_valid_index(&mut self.pos, self.deleted); + if out.is_some() { + self.count -= 1; + } + + out + } + + fn size_hint(&self) -> (usize, Option) { + (self.count, Some(self.count)) } } +impl ExactSizeIterator for Keys<'_> {} + /// Advances the index `pos` while it points to a deleted element. Stops /// advancing once an existing element is found or the end is reached. In the /// former case, this element's index is returned; in the latter case, `None` diff --git a/src/tests.rs b/src/tests.rs index 5033fc6..e025349 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -112,3 +112,35 @@ fn insert_into_hole_and_grow() { assert_eq!(sv.num_elements(), 3); assert_eq!(sv.clone().into_vec(), &['a', 'c', 'd']); } + +#[test] +fn size_hints() { + let mut sv = StableVec::<()>::new(); + + assert_eq!(sv.iter().size_hint(), (0, Some(0))); + assert_eq!(sv.iter_mut().size_hint(), (0, Some(0))); + assert_eq!(sv.keys().size_hint(), (0, Some(0))); + + + let mut sv = StableVec::from(&[0, 1, 2, 3, 4]); + sv.remove(1); + + macro_rules! check_iter { + ($it:expr) => {{ + let mut it = $it; + assert_eq!(it.size_hint(), (4, Some(4))); + assert!(it.next().is_some()); + assert_eq!(it.size_hint(), (3, Some(3))); + assert!(it.next().is_some()); + assert_eq!(it.size_hint(), (2, Some(2))); + assert!(it.next().is_some()); + assert_eq!(it.size_hint(), (1, Some(1))); + assert!(it.next().is_some()); + assert_eq!(it.size_hint(), (0, Some(0))); + }} + } + + check_iter!(sv.iter()); + check_iter!(sv.iter_mut()); + check_iter!(sv.keys()); +} From fa1f25aab54d1d05cdf043328fc944dd23b9332b Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Mon, 7 Jan 2019 21:52:18 +0100 Subject: [PATCH 2/3] Rewrite `StableVec::retain` not to use `IterMut` --- src/lib.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cf7af32..4d509d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -886,8 +886,8 @@ impl StableVec { /// Retains only the elements specified by the given predicate. /// - /// Each element `e` for which `predicate(&e)` returns `false` is removed - /// from the stable vector. + /// Each element `e` for which `should_be_kept(&e)` returns `false` is + /// removed from the stable vector. /// /// # Example /// @@ -898,14 +898,15 @@ impl StableVec { /// /// assert_eq!(sv, &[2, 4] as &[_]); /// ``` - pub fn retain

(&mut self, mut predicate: P) + pub fn retain

(&mut self, mut should_be_kept: P) where P: FnMut(&T) -> bool, { - let mut it = self.iter_mut(); - while let Some(e) = it.next() { - if !predicate(e) { - it.remove_current(); + let mut pos = 0; + + while let Some(idx) = next_valid_index(&mut pos, &self.deleted) { + if !should_be_kept(&self[idx]) { + self.remove(idx); } } } From c3df049a31760ef854b05cc2367d3d2caf719121 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Mon, 7 Jan 2019 21:58:18 +0100 Subject: [PATCH 3/3] Bump version to 0.2.2 --- CHANGELOG.md | 5 ++++- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b3af6e..6d9a85b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [0.2.2] - 2019-01-07 ### Added - All three iterators implement `Iterator::size_hint` and `ExactSizeIterator` now and report the correct length. @@ -68,7 +70,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Everything. -[Unreleased]: https://github.com/LukasKalbertodt/stable-vec/compare/v0.2.1...HEAD +[Unreleased]: https://github.com/LukasKalbertodt/stable-vec/compare/v0.2.2...HEAD +[0.2.2]: https://github.com/LukasKalbertodt/stable-vec/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/LukasKalbertodt/stable-vec/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/LukasKalbertodt/stable-vec/compare/v0.1.2...v0.2.0 [0.1.2]: https://github.com/LukasKalbertodt/stable-vec/compare/v0.1.1...v0.1.2 diff --git a/Cargo.toml b/Cargo.toml index d528c7b..c711ce6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stable-vec" -version = "0.2.1" +version = "0.2.2" authors = ["Lukas Kalbertodt "] description = """