rollup merge of #21882: Gankro/vec_entry
Building over night, posting for review now. Presumably not much should need change. I consider this necessary to move forward with a proper stabilization of the API. r? @huonw
This commit is contained in:
commit
5a35ad7100
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
|
pub use self::Entry::*;
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
@ -66,6 +68,32 @@ pub struct VecMap<V> {
|
|||||||
v: Vec<Option<V>>,
|
v: Vec<Option<V>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A view into a single entry in a map, which may either be vacant or occupied.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "precise API still under development")]
|
||||||
|
pub enum Entry<'a, V:'a> {
|
||||||
|
/// A vacant Entry
|
||||||
|
Vacant(VacantEntry<'a, V>),
|
||||||
|
/// An occupied Entry
|
||||||
|
Occupied(OccupiedEntry<'a, V>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A vacant Entry.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "precise API still under development")]
|
||||||
|
pub struct VacantEntry<'a, V:'a> {
|
||||||
|
map: &'a mut VecMap<V>,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An occupied Entry.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "precise API still under development")]
|
||||||
|
pub struct OccupiedEntry<'a, V:'a> {
|
||||||
|
map: &'a mut VecMap<V>,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<V> Default for VecMap<V> {
|
impl<V> Default for VecMap<V> {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
@ -485,6 +513,119 @@ impl<V> VecMap<V> {
|
|||||||
let result = &mut self.v[*key];
|
let result = &mut self.v[*key];
|
||||||
result.take()
|
result.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the given key's corresponding entry in the map for in-place manipulation.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::collections::VecMap;
|
||||||
|
/// use std::collections::vec_map::Entry;
|
||||||
|
///
|
||||||
|
/// let mut count: VecMap<u32> = VecMap::new();
|
||||||
|
///
|
||||||
|
/// // count the number of occurrences of numbers in the vec
|
||||||
|
/// for x in vec![1, 2, 1, 2, 3, 4, 1, 2, 4].iter() {
|
||||||
|
/// match count.entry(*x) {
|
||||||
|
/// Entry::Vacant(view) => {
|
||||||
|
/// view.insert(1);
|
||||||
|
/// },
|
||||||
|
/// Entry::Occupied(mut view) => {
|
||||||
|
/// let v = view.get_mut();
|
||||||
|
/// *v += 1;
|
||||||
|
/// },
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(count[1], 3);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "precise API still under development")]
|
||||||
|
pub fn entry(&mut self, key: usize) -> Entry<V> {
|
||||||
|
// FIXME(Gankro): this is basically the dumbest implementation of
|
||||||
|
// entry possible, because weird non-lexical borrows issues make it
|
||||||
|
// completely insane to do any other way. That said, Entry is a border-line
|
||||||
|
// useless construct on VecMap, so it's hardly a big loss.
|
||||||
|
if self.contains_key(&key) {
|
||||||
|
Occupied(OccupiedEntry {
|
||||||
|
map: self,
|
||||||
|
index: key,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Vacant(VacantEntry {
|
||||||
|
map: self,
|
||||||
|
index: key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, V> Entry<'a, V> {
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "matches collection reform v2 specification, waiting for dust to settle")]
|
||||||
|
/// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
|
||||||
|
pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, V>> {
|
||||||
|
match self {
|
||||||
|
Occupied(entry) => Ok(entry.into_mut()),
|
||||||
|
Vacant(entry) => Err(entry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V> VacantEntry<'a, V> {
|
||||||
|
/// Sets the value of the entry with the VacantEntry's key,
|
||||||
|
/// and returns a mutable reference to it.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "matches collection reform v2 specification, waiting for dust to settle")]
|
||||||
|
pub fn insert(self, value: V) -> &'a mut V {
|
||||||
|
let index = self.index;
|
||||||
|
self.map.insert(index, value);
|
||||||
|
&mut self.map[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V> OccupiedEntry<'a, V> {
|
||||||
|
/// Gets a reference to the value in the entry.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "matches collection reform v2 specification, waiting for dust to settle")]
|
||||||
|
pub fn get(&self) -> &V {
|
||||||
|
let index = self.index;
|
||||||
|
&self.map[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable reference to the value in the entry.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "matches collection reform v2 specification, waiting for dust to settle")]
|
||||||
|
pub fn get_mut(&mut self) -> &mut V {
|
||||||
|
let index = self.index;
|
||||||
|
&mut self.map[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the entry into a mutable reference to its value.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "matches collection reform v2 specification, waiting for dust to settle")]
|
||||||
|
pub fn into_mut(self) -> &'a mut V {
|
||||||
|
let index = self.index;
|
||||||
|
&mut self.map[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the value of the entry with the OccupiedEntry's key,
|
||||||
|
/// and returns the entry's old value.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "matches collection reform v2 specification, waiting for dust to settle")]
|
||||||
|
pub fn insert(&mut self, value: V) -> V {
|
||||||
|
let index = self.index;
|
||||||
|
self.map.insert(index, value).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes the value of the entry out of the map, and returns it.
|
||||||
|
#[unstable(feature = "collections",
|
||||||
|
reason = "matches collection reform v2 specification, waiting for dust to settle")]
|
||||||
|
pub fn remove(self) -> V {
|
||||||
|
let index = self.index;
|
||||||
|
self.map.remove(&index).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
@ -783,7 +924,7 @@ mod test_map {
|
|||||||
use prelude::*;
|
use prelude::*;
|
||||||
use core::hash::{hash, SipHasher};
|
use core::hash::{hash, SipHasher};
|
||||||
|
|
||||||
use super::VecMap;
|
use super::{VecMap, Occupied, Vacant};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_mut() {
|
fn test_get_mut() {
|
||||||
@ -1135,6 +1276,57 @@ mod test_map {
|
|||||||
|
|
||||||
map[4];
|
map[4];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_entry(){
|
||||||
|
let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
|
||||||
|
|
||||||
|
let mut map: VecMap<i32> = xs.iter().map(|&x| x).collect();
|
||||||
|
|
||||||
|
// Existing key (insert)
|
||||||
|
match map.entry(1) {
|
||||||
|
Vacant(_) => unreachable!(),
|
||||||
|
Occupied(mut view) => {
|
||||||
|
assert_eq!(view.get(), &10);
|
||||||
|
assert_eq!(view.insert(100), 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(map.get(&1).unwrap(), &100);
|
||||||
|
assert_eq!(map.len(), 6);
|
||||||
|
|
||||||
|
|
||||||
|
// Existing key (update)
|
||||||
|
match map.entry(2) {
|
||||||
|
Vacant(_) => unreachable!(),
|
||||||
|
Occupied(mut view) => {
|
||||||
|
let v = view.get_mut();
|
||||||
|
*v *= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(map.get(&2).unwrap(), &200);
|
||||||
|
assert_eq!(map.len(), 6);
|
||||||
|
|
||||||
|
// Existing key (take)
|
||||||
|
match map.entry(3) {
|
||||||
|
Vacant(_) => unreachable!(),
|
||||||
|
Occupied(view) => {
|
||||||
|
assert_eq!(view.remove(), 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(map.get(&3), None);
|
||||||
|
assert_eq!(map.len(), 5);
|
||||||
|
|
||||||
|
|
||||||
|
// Inexistent key (insert)
|
||||||
|
match map.entry(10) {
|
||||||
|
Occupied(_) => unreachable!(),
|
||||||
|
Vacant(view) => {
|
||||||
|
assert_eq!(*view.insert(1000), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(map.get(&10).unwrap(), &1000);
|
||||||
|
assert_eq!(map.len(), 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user