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

Add FromIterator and IntoIterator impls for ThinVec #83821

Merged
merged 1 commit into from
Apr 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions compiler/rustc_data_structures/src/thin_vec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::stable_hasher::{HashStable, StableHasher};

use std::iter::FromIterator;

/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`).
/// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
/// which uses only a single (null) pointer.
Expand All @@ -10,6 +12,14 @@ impl<T> ThinVec<T> {
pub fn new() -> Self {
ThinVec(None)
}

pub fn iter(&self) -> std::slice::Iter<'_, T> {
self.into_iter()
}

pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
self.into_iter()
}
}
Comment on lines 12 to 23
Copy link
Member

Choose a reason for hiding this comment

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

It looks like this is also missing .push and .pop, I can add those separately. Seems weird that this derefs to a slice instead of a vec.

Copy link
Member

Choose a reason for hiding this comment

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

You couldn't DerefMut to a vec in the None case.


impl<T> From<Vec<T>> for ThinVec<T> {
Expand Down Expand Up @@ -46,6 +56,42 @@ impl<T> ::std::ops::DerefMut for ThinVec<T> {
}
}

impl<T> FromIterator<T> for ThinVec<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
// `Vec::from_iter()` should not allocate if the iterator is empty.
let vec: Vec<_> = iter.into_iter().collect();
if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) }
}
}

impl<T> IntoIterator for ThinVec<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;

fn into_iter(self) -> Self::IntoIter {
// This is still performant because `Vec::new()` does not allocate.
self.0.map_or_else(Vec::new, |ptr| *ptr).into_iter()
camelid marked this conversation as resolved.
Show resolved Hide resolved
}
}

impl<'a, T> IntoIterator for &'a ThinVec<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;

fn into_iter(self) -> Self::IntoIter {
self.as_ref().iter()
}
}
camelid marked this conversation as resolved.
Show resolved Hide resolved

impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;

fn into_iter(self) -> Self::IntoIter {
self.as_mut().iter_mut()
}
}

impl<T> Extend<T> for ThinVec<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
match *self {
Expand Down Expand Up @@ -80,3 +126,6 @@ impl<T> Default for ThinVec<T> {
Self(None)
}
}

#[cfg(test)]
mod tests;
42 changes: 42 additions & 0 deletions compiler/rustc_data_structures/src/thin_vec/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use super::*;

impl<T> ThinVec<T> {
fn into_vec(self) -> Vec<T> {
self.into()
}
}

#[test]
fn test_from_iterator() {
assert_eq!(std::iter::empty().collect::<ThinVec<String>>().into_vec(), Vec::<String>::new());
assert_eq!(std::iter::once(42).collect::<ThinVec<_>>().into_vec(), vec![42]);
assert_eq!(vec![1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
assert_eq!(vec![1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
}

#[test]
fn test_into_iterator_owned() {
assert_eq!(ThinVec::new().into_iter().collect::<Vec<String>>(), Vec::<String>::new());
assert_eq!(ThinVec::from(vec![1]).into_iter().collect::<Vec<_>>(), vec![1]);
assert_eq!(ThinVec::from(vec![1, 2]).into_iter().collect::<Vec<_>>(), vec![1, 2]);
assert_eq!(ThinVec::from(vec![1, 2, 3]).into_iter().collect::<Vec<_>>(), vec![1, 2, 3]);
}

#[test]
fn test_into_iterator_ref() {
assert_eq!(ThinVec::new().iter().collect::<Vec<&String>>(), Vec::<&String>::new());
assert_eq!(ThinVec::from(vec![1]).iter().collect::<Vec<_>>(), vec![&1]);
assert_eq!(ThinVec::from(vec![1, 2]).iter().collect::<Vec<_>>(), vec![&1, &2]);
assert_eq!(ThinVec::from(vec![1, 2, 3]).iter().collect::<Vec<_>>(), vec![&1, &2, &3]);
}

#[test]
fn test_into_iterator_ref_mut() {
assert_eq!(ThinVec::new().iter_mut().collect::<Vec<&mut String>>(), Vec::<&mut String>::new());
assert_eq!(ThinVec::from(vec![1]).iter_mut().collect::<Vec<_>>(), vec![&mut 1]);
assert_eq!(ThinVec::from(vec![1, 2]).iter_mut().collect::<Vec<_>>(), vec![&mut 1, &mut 2]);
assert_eq!(
ThinVec::from(vec![1, 2, 3]).iter_mut().collect::<Vec<_>>(),
vec![&mut 1, &mut 2, &mut 3],
);
}