Use Entry API.

This commit is contained in:
Stephen Chung 2022-09-14 12:11:27 +08:00
parent b9478e601c
commit b256b3ecc7

View File

@ -1,6 +1,6 @@
use crate::func::{hashing::get_hasher, StraightHashMap}; use crate::func::{hashing::get_hasher, StraightHashMap};
use crate::ImmutableString; use crate::ImmutableString;
use std::collections::hash_map::Entry;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{ use std::{
@ -71,7 +71,7 @@ impl StringsInterner<'_> {
#[must_use] #[must_use]
pub fn get_with_mapper<S: AsRef<str>>( pub fn get_with_mapper<S: AsRef<str>>(
&mut self, &mut self,
mapper: fn(S) -> ImmutableString, mapper: impl Fn(S) -> ImmutableString,
text: S, text: S,
) -> ImmutableString { ) -> ImmutableString {
let key = text.as_ref(); let key = text.as_ref();
@ -84,19 +84,20 @@ impl StringsInterner<'_> {
key.hash(hasher); key.hash(hasher);
let key = hasher.finish(); let key = hasher.finish();
if !self.strings.is_empty() && self.strings.contains_key(&key) { let result = match self.strings.entry(key) {
return self.strings.get(&key).unwrap().clone(); Entry::Occupied(e) => return e.get().clone(),
} Entry::Vacant(e) => {
let value = mapper(text);
let value = mapper(text); if value.strong_count() > 1 {
return value;
}
if value.strong_count() > 1 { e.insert(value).clone()
return value; }
} };
self.strings.insert(key, value.clone()); // If the interner is over capacity, remove the longest entry that has the lowest count
// If the interner is over capacity, remove the longest entry
if self.strings.len() > self.capacity { if self.strings.len() > self.capacity {
// Leave some buffer to grow when shrinking the cache. // Leave some buffer to grow when shrinking the cache.
// We leave at least two entries, one for the empty string, and one for the string // We leave at least two entries, one for the empty string, and one for the string
@ -108,19 +109,24 @@ impl StringsInterner<'_> {
}; };
while self.strings.len() > max { while self.strings.len() > max {
let (_, n) = self.strings.iter().fold((0, 0), |(x, n), (&k, v)| { let (_, _, n) =
if k != key && v.len() > x { self.strings
(v.len(), k) .iter()
} else { .fold((0, usize::MAX, 0), |(x, c, n), (&k, v)| {
(x, n) if k != key
} && (v.strong_count() < c || (v.strong_count() == c && v.len() > x))
}); {
(v.len(), v.strong_count(), k)
} else {
(x, c, n)
}
});
self.strings.remove(&n); self.strings.remove(&n);
} }
} }
value result
} }
/// Number of strings interned. /// Number of strings interned.