Skip to content

Commit 78787e6

Browse files
OccupiedEntry.replace_* (#11)
This is directly taken from `hashbrown`
1 parent 13509e4 commit 78787e6

File tree

2 files changed

+119
-1
lines changed

2 files changed

+119
-1
lines changed

src/map.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,6 @@ impl<K: Debug, V: Debug, S> Debug for Entry<'_, K, V, S> {
12421242
///
12431243
/// [`Entry`]: enum.Entry.html
12441244
pub struct OccupiedEntry<'a, K, V, S> {
1245-
#[allow(dead_code)] // remove when replace_ methods are implemented
12461245
key: Option<K>,
12471246
elem: Bucket<(K, V)>,
12481247
table: &'a mut HashMap<K, V, S>,
@@ -1863,6 +1862,67 @@ impl<'a, K, V, S> OccupiedEntry<'a, K, V, S> {
18631862
// restarting the iterator, though that would come at a performance penalty...
18641863
//
18651864
// when implemented, remove the #[allow(dead_code)] on OccupiedEntry::key
1865+
1866+
/// Replaces the entry, returning the old key and value. The new key in the hash map will be
1867+
/// the key used to create this entry.
1868+
///
1869+
/// # Examples
1870+
///
1871+
/// ```
1872+
/// use griddle::hash_map::{Entry, HashMap};
1873+
/// use std::rc::Rc;
1874+
///
1875+
/// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
1876+
/// map.insert(Rc::new("Stringthing".to_string()), 15);
1877+
///
1878+
/// let my_key = Rc::new("Stringthing".to_string());
1879+
///
1880+
/// if let Entry::Occupied(entry) = map.entry(my_key.clone()) {
1881+
/// // Also replace the key with a handle to our other key.
1882+
/// let (old_key, old_value): (Rc<String>, u32) = entry.replace_entry(16);
1883+
/// }
1884+
///
1885+
/// assert_eq!(map[&my_key], 16);
1886+
/// ```
1887+
#[cfg_attr(feature = "inline-more", inline)]
1888+
pub fn replace_entry(self, value: V) -> (K, V) {
1889+
let entry = unsafe { self.elem.as_mut() };
1890+
1891+
let old_key = mem::replace(&mut entry.0, self.key.unwrap());
1892+
let old_value = mem::replace(&mut entry.1, value);
1893+
1894+
(old_key, old_value)
1895+
}
1896+
1897+
/// Replaces the key in the hash map with the key used to create this entry.
1898+
///
1899+
/// # Examples
1900+
///
1901+
/// ```
1902+
/// use griddle::hash_map::{Entry, HashMap};
1903+
/// use std::rc::Rc;
1904+
///
1905+
/// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
1906+
/// let mut known_strings: Vec<Rc<String>> = Vec::new();
1907+
///
1908+
/// // Initialise known strings, run program, etc.
1909+
///
1910+
/// reclaim_memory(&mut map, &known_strings);
1911+
///
1912+
/// fn reclaim_memory(map: &mut HashMap<Rc<String>, u32>, known_strings: &[Rc<String>] ) {
1913+
/// for s in known_strings {
1914+
/// if let Entry::Occupied(entry) = map.entry(s.clone()) {
1915+
/// // Replaces the entry's key with our version of it in `known_strings`.
1916+
/// entry.replace_key();
1917+
/// }
1918+
/// }
1919+
/// }
1920+
/// ```
1921+
#[cfg_attr(feature = "inline-more", inline)]
1922+
pub fn replace_key(self) -> K {
1923+
let entry = unsafe { self.elem.as_mut() };
1924+
mem::replace(&mut entry.0, self.key.unwrap())
1925+
}
18661926
}
18671927

18681928
impl<'a, K, V, S> VacantEntry<'a, K, V, S> {

src/set.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,32 @@ where
720720
self.map.insert(value, ()).is_none()
721721
}
722722

723+
/// Adds a value to the set, replacing the existing value, if any, that is equal to the given
724+
/// one. Returns the replaced value.
725+
///
726+
/// # Examples
727+
///
728+
/// ```
729+
/// use griddle::HashSet;
730+
///
731+
/// let mut set = HashSet::new();
732+
/// set.insert(Vec::<i32>::new());
733+
///
734+
/// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0);
735+
/// set.replace(Vec::with_capacity(10));
736+
/// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10);
737+
/// ```
738+
#[cfg_attr(feature = "inline-more", inline)]
739+
pub fn replace(&mut self, value: T) -> Option<T> {
740+
match self.map.entry(value) {
741+
map::Entry::Occupied(occupied) => Some(occupied.replace_key()),
742+
map::Entry::Vacant(vacant) => {
743+
vacant.insert(());
744+
None
745+
}
746+
}
747+
}
748+
723749
/// Removes a value from the set. Returns whether the value was
724750
/// present in the set.
725751
///
@@ -1681,6 +1707,38 @@ mod test_set {
16811707
assert_eq!(format!("{:?}", empty), "{}");
16821708
}
16831709

1710+
#[test]
1711+
fn test_replace() {
1712+
use core::hash;
1713+
1714+
#[derive(Debug)]
1715+
struct Foo(&'static str, i32);
1716+
1717+
impl PartialEq for Foo {
1718+
fn eq(&self, other: &Self) -> bool {
1719+
self.0 == other.0
1720+
}
1721+
}
1722+
1723+
impl Eq for Foo {}
1724+
1725+
impl hash::Hash for Foo {
1726+
fn hash<H: hash::Hasher>(&self, h: &mut H) {
1727+
self.0.hash(h);
1728+
}
1729+
}
1730+
1731+
let mut s = HashSet::new();
1732+
assert_eq!(s.replace(Foo("a", 1)), None);
1733+
assert_eq!(s.len(), 1);
1734+
assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1)));
1735+
assert_eq!(s.len(), 1);
1736+
1737+
let mut it = s.iter();
1738+
assert_eq!(it.next(), Some(&Foo("a", 2)));
1739+
assert_eq!(it.next(), None);
1740+
}
1741+
16841742
#[test]
16851743
fn test_extend_ref() {
16861744
let mut a = HashSet::new();

0 commit comments

Comments
 (0)