Skip to content

Implement into_keys and into_values for associative maps #75163

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

Merged
merged 8 commits into from
Aug 8, 2020
148 changes: 148 additions & 0 deletions library/alloc/src/collections/btree/map.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore-tidy-filelength
Copy link
Contributor

Choose a reason for hiding this comment

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

I think IntoKeys and impls should be moved to a module file to remove this tidy ignore.


use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::Debug;
Expand Down Expand Up @@ -355,6 +357,30 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
inner: IterMut<'a, K, V>,
}

/// An owning iterator over the keys of a `BTreeMap`.
///
/// This `struct` is created by the [`into_keys`] method on [`BTreeMap`].
/// See its documentation for more.
///
/// [`into_keys`]: BTreeMap::into_keys
#[unstable(feature = "map_into_keys_values", issue = "75294")]
#[derive(Debug)]
pub struct IntoKeys<K, V> {
inner: IntoIter<K, V>,
}

/// An owning iterator over the values of a `BTreeMap`.
///
/// This `struct` is created by the [`into_values`] method on [`BTreeMap`].
/// See its documentation for more.
///
/// [`into_values`]: BTreeMap::into_values
#[unstable(feature = "map_into_keys_values", issue = "75294")]
#[derive(Debug)]
pub struct IntoValues<K, V> {
inner: IntoIter<K, V>,
}

/// An iterator over a sub-range of entries in a `BTreeMap`.
///
/// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its
Expand Down Expand Up @@ -1291,6 +1317,52 @@ impl<K: Ord, V> BTreeMap<K, V> {

self.length = dfs(self.root.as_ref().unwrap().as_ref());
}

/// Creates a consuming iterator visiting all the keys, in sorted order.
/// The map cannot be used after calling this.
/// The iterator element type is `K`.
///
/// # Examples
///
/// ```
/// #![feature(map_into_keys_values)]
/// use std::collections::BTreeMap;
///
/// let mut a = BTreeMap::new();
/// a.insert(2, "b");
/// a.insert(1, "a");
///
/// let keys: Vec<i32> = a.into_keys().collect();
/// assert_eq!(keys, [1, 2]);
/// ```
#[inline]
#[unstable(feature = "map_into_keys_values", issue = "75294")]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
}

/// Creates a consuming iterator visiting all the values, in order by key.
/// The map cannot be used after calling this.
/// The iterator element type is `V`.
///
/// # Examples
///
/// ```
/// #![feature(map_into_keys_values)]
/// use std::collections::BTreeMap;
///
/// let mut a = BTreeMap::new();
/// a.insert(1, "hello");
/// a.insert(2, "goodbye");
///
/// let values: Vec<&str> = a.into_values().collect();
/// assert_eq!(values, ["hello", "goodbye"]);
/// ```
#[inline]
#[unstable(feature = "map_into_keys_values", issue = "75294")]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -1781,6 +1853,82 @@ impl<'a, K, V> Range<'a, K, V> {
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> Iterator for IntoKeys<K, V> {
type Item = K;

fn next(&mut self) -> Option<K> {
self.inner.next().map(|(k, _)| k)
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}

fn last(mut self) -> Option<K> {
self.next_back()
}

fn min(mut self) -> Option<K> {
self.next()
}

fn max(mut self) -> Option<K> {
self.next_back()
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> DoubleEndedIterator for IntoKeys<K, V> {
fn next_back(&mut self) -> Option<K> {
self.inner.next_back().map(|(k, _)| k)
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
fn len(&self) -> usize {
self.inner.len()
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> FusedIterator for IntoKeys<K, V> {}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> Iterator for IntoValues<K, V> {
type Item = V;

fn next(&mut self) -> Option<V> {
self.inner.next().map(|(_, v)| v)
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}

fn last(mut self) -> Option<V> {
self.next_back()
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> DoubleEndedIterator for IntoValues<K, V> {
fn next_back(&mut self) -> Option<V> {
self.inner.next_back().map(|(_, v)| v)
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> ExactSizeIterator for IntoValues<K, V> {
fn len(&self) -> usize {
self.inner.len()
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> FusedIterator for IntoValues<K, V> {}

#[stable(feature = "btree_range", since = "1.17.0")]
impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> {
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
Expand Down
24 changes: 24 additions & 0 deletions library/alloc/tests/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1461,3 +1461,27 @@ fn test_into_iter_drop_leak_height_1() {
assert_eq!(DROPS.load(Ordering::SeqCst), size);
}
}

#[test]
fn test_into_keys() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: BTreeMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();

assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
assert!(keys.contains(&2));
assert!(keys.contains(&3));
}

#[test]
fn test_into_values() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: BTreeMap<_, _> = vec.into_iter().collect();
let values: Vec<_> = map.into_values().collect();

assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
assert!(values.contains(&'b'));
assert!(values.contains(&'c'));
}
1 change: 1 addition & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(map_first_last)]
#![feature(map_into_keys_values)]
#![feature(new_uninit)]
#![feature(pattern)]
#![feature(str_split_once)]
Expand Down
152 changes: 152 additions & 0 deletions library/std/src/collections/hash/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,52 @@ where
{
self.base.retain(f)
}

/// Creates a consuming iterator visiting all the keys in arbitrary order.
/// The map cannot be used after calling this.
/// The iterator element type is `K`.
///
/// # Examples
///
/// ```
/// #![feature(map_into_keys_values)]
/// use std::collections::HashMap;
///
/// let mut map = HashMap::new();
/// map.insert("a", 1);

Choose a reason for hiding this comment

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

Perhaps it's better an example with HashMap<String> instead of HashMap<&str> ?

/// map.insert("b", 2);
/// map.insert("c", 3);
///
/// let vec: Vec<&str> = map.into_keys().collect();
/// ```
#[inline]
#[unstable(feature = "map_into_keys_values", issue = "75294")]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
}

/// Creates a consuming iterator visiting all the values in arbitrary order.
/// The map cannot be used after calling this.
/// The iterator element type is `V`.
///
/// # Examples
///
/// ```
/// #![feature(map_into_keys_values)]
/// use std::collections::HashMap;
///
/// let mut map = HashMap::new();
/// map.insert("a", 1);
/// map.insert("b", 2);
/// map.insert("c", 3);
///
/// let vec: Vec<i32> = map.into_values().collect();
/// ```
#[inline]
#[unstable(feature = "map_into_keys_values", issue = "75294")]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }
}
}

impl<K, V, S> HashMap<K, V, S>
Expand Down Expand Up @@ -1154,6 +1200,28 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
inner: IterMut<'a, K, V>,
}

/// An owning iterator over the keys of a `HashMap`.
///
/// This `struct` is created by the [`into_keys`] method on [`HashMap`].
/// See its documentation for more.
///
/// [`into_keys`]: HashMap::into_keys
#[unstable(feature = "map_into_keys_values", issue = "75294")]
pub struct IntoKeys<K, V> {
inner: IntoIter<K, V>,
}

/// An owning iterator over the values of a `HashMap`.
///
/// This `struct` is created by the [`into_values`] method on [`HashMap`].
/// See its documentation for more.
///
/// [`into_values`]: HashMap::into_values
#[unstable(feature = "map_into_keys_values", issue = "75294")]
pub struct IntoValues<K, V> {
inner: IntoIter<K, V>,
}

/// A builder for computing where in a HashMap a key-value pair would be stored.
///
/// See the [`HashMap::raw_entry_mut`] docs for usage examples.
Expand Down Expand Up @@ -1827,6 +1895,66 @@ where
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> Iterator for IntoKeys<K, V> {
type Item = K;

#[inline]
fn next(&mut self) -> Option<K> {
self.inner.next().map(|(k, _)| k)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}
}
#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> FusedIterator for IntoKeys<K, V> {}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K: Debug, V: Debug> fmt::Debug for IntoKeys<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
}
}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> Iterator for IntoValues<K, V> {
type Item = V;

#[inline]
fn next(&mut self) -> Option<V> {
self.inner.next().map(|(_, v)| v)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> ExactSizeIterator for IntoValues<K, V> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}
}
#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K, V> FusedIterator for IntoValues<K, V> {}

#[unstable(feature = "map_into_keys_values", issue = "75294")]
impl<K: Debug, V: Debug> fmt::Debug for IntoValues<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
}
}

#[stable(feature = "drain", since = "1.6.0")]
impl<'a, K, V> Iterator for Drain<'a, K, V> {
type Item = (K, V);
Expand Down Expand Up @@ -3084,6 +3212,30 @@ mod test_map {
assert!(values.contains(&6));
}

#[test]
fn test_into_keys() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.into_keys().collect();

assert_eq!(keys.len(), 3);
assert!(keys.contains(&1));
assert!(keys.contains(&2));
assert!(keys.contains(&3));
}

#[test]
fn test_into_values() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: HashMap<_, _> = vec.into_iter().collect();
let values: Vec<_> = map.into_values().collect();

assert_eq!(values.len(), 3);
assert!(values.contains(&'a'));
assert!(values.contains(&'b'));
assert!(values.contains(&'c'));
}

#[test]
fn test_find() {
let mut m = HashMap::new();
Expand Down