Skip to content

Commit

Permalink
Auto merge of rust-lang#75163 - canova:map_into_keys_values, r=dtolnay
Browse files Browse the repository at this point in the history
Implement `into_keys` and `into_values` for associative maps

This PR implements `into_keys` and `into_values` for HashMap and BTreeMap types. They are implemented as unstable, under `map_into_keys_values` feature.
Fixes rust-lang#55214.
r? @dtolnay
  • Loading branch information
bors committed Aug 8, 2020
2 parents 3f091ba + 4cd2637 commit 1facd4a
Show file tree
Hide file tree
Showing 4 changed files with 325 additions and 0 deletions.
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

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 @@ -1780,6 +1852,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);
/// 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

0 comments on commit 1facd4a

Please sign in to comment.