|
13 | 13 |
|
14 | 14 | #![allow(missing_docs)]
|
15 | 15 |
|
| 16 | +pub use self::Entry::*; |
| 17 | + |
16 | 18 | use core::prelude::*;
|
17 | 19 |
|
18 | 20 | use core::cmp::Ordering;
|
@@ -66,6 +68,32 @@ pub struct VecMap<V> {
|
66 | 68 | v: Vec<Option<V>>,
|
67 | 69 | }
|
68 | 70 |
|
| 71 | +/// A view into a single entry in a map, which may either be vacant or occupied. |
| 72 | +#[unstable(feature = "collections", |
| 73 | + reason = "precise API still under development")] |
| 74 | +pub enum Entry<'a, V:'a> { |
| 75 | + /// A vacant Entry |
| 76 | + Vacant(VacantEntry<'a, V>), |
| 77 | + /// An occupied Entry |
| 78 | + Occupied(OccupiedEntry<'a, V>), |
| 79 | +} |
| 80 | + |
| 81 | +/// A vacant Entry. |
| 82 | +#[unstable(feature = "collections", |
| 83 | + reason = "precise API still under development")] |
| 84 | +pub struct VacantEntry<'a, V:'a> { |
| 85 | + map: &'a mut VecMap<V>, |
| 86 | + index: usize, |
| 87 | +} |
| 88 | + |
| 89 | +/// An occupied Entry. |
| 90 | +#[unstable(feature = "collections", |
| 91 | + reason = "precise API still under development")] |
| 92 | +pub struct OccupiedEntry<'a, V:'a> { |
| 93 | + map: &'a mut VecMap<V>, |
| 94 | + index: usize, |
| 95 | +} |
| 96 | + |
69 | 97 | #[stable(feature = "rust1", since = "1.0.0")]
|
70 | 98 | impl<V> Default for VecMap<V> {
|
71 | 99 | #[stable(feature = "rust1", since = "1.0.0")]
|
@@ -485,6 +513,119 @@ impl<V> VecMap<V> {
|
485 | 513 | let result = &mut self.v[*key];
|
486 | 514 | result.take()
|
487 | 515 | }
|
| 516 | + |
| 517 | + /// Gets the given key's corresponding entry in the map for in-place manipulation. |
| 518 | + /// |
| 519 | + /// # Examples |
| 520 | + /// |
| 521 | + /// ``` |
| 522 | + /// use std::collections::VecMap; |
| 523 | + /// use std::collections::vec_map::Entry; |
| 524 | + /// |
| 525 | + /// let mut count: VecMap<u32> = VecMap::new(); |
| 526 | + /// |
| 527 | + /// // count the number of occurrences of numbers in the vec |
| 528 | + /// for x in vec![1, 2, 1, 2, 3, 4, 1, 2, 4].iter() { |
| 529 | + /// match count.entry(*x) { |
| 530 | + /// Entry::Vacant(view) => { |
| 531 | + /// view.insert(1); |
| 532 | + /// }, |
| 533 | + /// Entry::Occupied(mut view) => { |
| 534 | + /// let v = view.get_mut(); |
| 535 | + /// *v += 1; |
| 536 | + /// }, |
| 537 | + /// } |
| 538 | + /// } |
| 539 | + /// |
| 540 | + /// assert_eq!(count[1], 3); |
| 541 | + /// ``` |
| 542 | + #[unstable(feature = "collections", |
| 543 | + reason = "precise API still under development")] |
| 544 | + pub fn entry(&mut self, key: usize) -> Entry<V> { |
| 545 | + // FIXME(Gankro): this is basically the dumbest implementation of |
| 546 | + // entry possible, because weird non-lexical borrows issues make it |
| 547 | + // completely insane to do any other way. That said, Entry is a border-line |
| 548 | + // useless construct on VecMap, so it's hardly a big loss. |
| 549 | + if self.contains_key(&key) { |
| 550 | + Occupied(OccupiedEntry { |
| 551 | + map: self, |
| 552 | + index: key, |
| 553 | + }) |
| 554 | + } else { |
| 555 | + Vacant(VacantEntry { |
| 556 | + map: self, |
| 557 | + index: key, |
| 558 | + }) |
| 559 | + } |
| 560 | + } |
| 561 | +} |
| 562 | + |
| 563 | + |
| 564 | +impl<'a, V> Entry<'a, V> { |
| 565 | + #[unstable(feature = "collections", |
| 566 | + reason = "matches collection reform v2 specification, waiting for dust to settle")] |
| 567 | + /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant |
| 568 | + pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, V>> { |
| 569 | + match self { |
| 570 | + Occupied(entry) => Ok(entry.into_mut()), |
| 571 | + Vacant(entry) => Err(entry), |
| 572 | + } |
| 573 | + } |
| 574 | +} |
| 575 | + |
| 576 | +impl<'a, V> VacantEntry<'a, V> { |
| 577 | + /// Sets the value of the entry with the VacantEntry's key, |
| 578 | + /// and returns a mutable reference to it. |
| 579 | + #[unstable(feature = "collections", |
| 580 | + reason = "matches collection reform v2 specification, waiting for dust to settle")] |
| 581 | + pub fn insert(self, value: V) -> &'a mut V { |
| 582 | + let index = self.index; |
| 583 | + self.map.insert(index, value); |
| 584 | + &mut self.map[index] |
| 585 | + } |
| 586 | +} |
| 587 | + |
| 588 | +impl<'a, V> OccupiedEntry<'a, V> { |
| 589 | + /// Gets a reference to the value in the entry. |
| 590 | + #[unstable(feature = "collections", |
| 591 | + reason = "matches collection reform v2 specification, waiting for dust to settle")] |
| 592 | + pub fn get(&self) -> &V { |
| 593 | + let index = self.index; |
| 594 | + &self.map[index] |
| 595 | + } |
| 596 | + |
| 597 | + /// Gets a mutable reference to the value in the entry. |
| 598 | + #[unstable(feature = "collections", |
| 599 | + reason = "matches collection reform v2 specification, waiting for dust to settle")] |
| 600 | + pub fn get_mut(&mut self) -> &mut V { |
| 601 | + let index = self.index; |
| 602 | + &mut self.map[index] |
| 603 | + } |
| 604 | + |
| 605 | + /// Converts the entry into a mutable reference to its value. |
| 606 | + #[unstable(feature = "collections", |
| 607 | + reason = "matches collection reform v2 specification, waiting for dust to settle")] |
| 608 | + pub fn into_mut(self) -> &'a mut V { |
| 609 | + let index = self.index; |
| 610 | + &mut self.map[index] |
| 611 | + } |
| 612 | + |
| 613 | + /// Sets the value of the entry with the OccupiedEntry's key, |
| 614 | + /// and returns the entry's old value. |
| 615 | + #[unstable(feature = "collections", |
| 616 | + reason = "matches collection reform v2 specification, waiting for dust to settle")] |
| 617 | + pub fn insert(&mut self, value: V) -> V { |
| 618 | + let index = self.index; |
| 619 | + self.map.insert(index, value).unwrap() |
| 620 | + } |
| 621 | + |
| 622 | + /// Takes the value of the entry out of the map, and returns it. |
| 623 | + #[unstable(feature = "collections", |
| 624 | + reason = "matches collection reform v2 specification, waiting for dust to settle")] |
| 625 | + pub fn remove(self) -> V { |
| 626 | + let index = self.index; |
| 627 | + self.map.remove(&index).unwrap() |
| 628 | + } |
488 | 629 | }
|
489 | 630 |
|
490 | 631 | #[stable(feature = "rust1", since = "1.0.0")]
|
@@ -783,7 +924,7 @@ mod test_map {
|
783 | 924 | use prelude::*;
|
784 | 925 | use core::hash::{hash, SipHasher};
|
785 | 926 |
|
786 |
| - use super::VecMap; |
| 927 | + use super::{VecMap, Occupied, Vacant}; |
787 | 928 |
|
788 | 929 | #[test]
|
789 | 930 | fn test_get_mut() {
|
@@ -1135,6 +1276,57 @@ mod test_map {
|
1135 | 1276 |
|
1136 | 1277 | map[4];
|
1137 | 1278 | }
|
| 1279 | + |
| 1280 | + #[test] |
| 1281 | + fn test_entry(){ |
| 1282 | + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; |
| 1283 | + |
| 1284 | + let mut map: VecMap<i32> = xs.iter().map(|&x| x).collect(); |
| 1285 | + |
| 1286 | + // Existing key (insert) |
| 1287 | + match map.entry(1) { |
| 1288 | + Vacant(_) => unreachable!(), |
| 1289 | + Occupied(mut view) => { |
| 1290 | + assert_eq!(view.get(), &10); |
| 1291 | + assert_eq!(view.insert(100), 10); |
| 1292 | + } |
| 1293 | + } |
| 1294 | + assert_eq!(map.get(&1).unwrap(), &100); |
| 1295 | + assert_eq!(map.len(), 6); |
| 1296 | + |
| 1297 | + |
| 1298 | + // Existing key (update) |
| 1299 | + match map.entry(2) { |
| 1300 | + Vacant(_) => unreachable!(), |
| 1301 | + Occupied(mut view) => { |
| 1302 | + let v = view.get_mut(); |
| 1303 | + *v *= 10; |
| 1304 | + } |
| 1305 | + } |
| 1306 | + assert_eq!(map.get(&2).unwrap(), &200); |
| 1307 | + assert_eq!(map.len(), 6); |
| 1308 | + |
| 1309 | + // Existing key (take) |
| 1310 | + match map.entry(3) { |
| 1311 | + Vacant(_) => unreachable!(), |
| 1312 | + Occupied(view) => { |
| 1313 | + assert_eq!(view.remove(), 30); |
| 1314 | + } |
| 1315 | + } |
| 1316 | + assert_eq!(map.get(&3), None); |
| 1317 | + assert_eq!(map.len(), 5); |
| 1318 | + |
| 1319 | + |
| 1320 | + // Inexistent key (insert) |
| 1321 | + match map.entry(10) { |
| 1322 | + Occupied(_) => unreachable!(), |
| 1323 | + Vacant(view) => { |
| 1324 | + assert_eq!(*view.insert(1000), 1000); |
| 1325 | + } |
| 1326 | + } |
| 1327 | + assert_eq!(map.get(&10).unwrap(), &1000); |
| 1328 | + assert_eq!(map.len(), 6); |
| 1329 | + } |
1138 | 1330 | }
|
1139 | 1331 |
|
1140 | 1332 | #[cfg(test)]
|
|
0 commit comments