#![deny(warnings)]
#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
use std::borrow::*;
use std::cell::*;
use std::collections::hash_map::*;
use std::collections::*;
use std::hash::*;
use std::mem::*;
use std::rc::*;
pub struct TransientMap<K, V, S = RandomState> {
map: HashMap<Rc<K>, TransientMapValue<V>, S>,
tracker: RefCell<TransientUsageTracker<K>>,
}
impl<K, V> TransientMap<K, V, RandomState> {
pub fn new() -> Self {
Default::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_and_hasher(capacity, Default::default())
}
}
impl<K, V, S> TransientMap<K, V, S> {
pub fn set_all_used(&mut self) {
self.tracker.get_mut().first_used = 0;
}
pub fn set_all_unused(&mut self) {
let tracker = self.tracker.get_mut();
tracker.first_used = tracker.item_usage.len();
}
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
Self {
map: HashMap::with_capacity_and_hasher(capacity, hasher),
tracker: RefCell::new(TransientUsageTracker {
first_used: 0,
item_usage: VecDeque::new(),
usage_offset: 0,
}),
}
}
pub fn capacity(&self) -> usize {
self.map.capacity()
}
pub fn keys(&self) -> impl Iterator<Item = &K> {
self.iter().map(|(k, _)| k)
}
pub fn keys_silent(&self) -> impl Iterator<Item = &K> {
self.map.keys().map(|k| &**k)
}
pub fn into_keys(self) -> impl Iterator<Item = K> {
self.map.into_keys().map(|k| {
Rc::try_unwrap(k)
.ok()
.expect("Another reference to the key still existed.")
})
}
pub fn values(&self) -> impl Iterator<Item = &V> {
self.map.values().map(|v| {
Self::promote_item(v, &mut self.tracker.borrow_mut());
&v.value
})
}
pub fn values_silent(&self) -> impl Iterator<Item = &V> {
self.map.values().map(|v| &v.value)
}
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
self.iter_mut().map(|(_, v)| v)
}
pub fn into_values(self) -> impl Iterator<Item = V> {
self.map.into_values().map(|v| v.value)
}
pub fn iter(&self) -> impl '_ + Iterator<Item = (&K, &V)> {
self.map.iter().map(|(k, v)| {
Self::promote_item(v, &mut self.tracker.borrow_mut());
(&**k, &v.value)
})
}
pub fn iter_silent(&self) -> impl '_ + Iterator<Item = (&K, &V)> {
self.map.iter().map(|(k, v)| (&**k, &v.value))
}
pub fn iter_mut(&mut self) -> impl '_ + Iterator<Item = (&K, &mut V)> {
self.map.iter_mut().map(|(k, v)| {
Self::promote_item(v, self.tracker.get_mut());
(&**k, &mut v.value)
})
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn drain(&mut self) -> impl '_ + Iterator<Item = (K, V)> {
let tracker = self.tracker.get_mut();
tracker.first_used = 0;
tracker.usage_offset = 0;
tracker.item_usage.clear();
self.map.drain().map(|(k, v)| {
(
Rc::try_unwrap(k)
.ok()
.expect("Another reference was still out to the stored key."),
v.value,
)
})
}
pub fn clear(&mut self) {
self.map.clear();
let tracker = self.tracker.get_mut();
tracker.first_used = 0;
tracker.usage_offset = 0;
tracker.item_usage.clear();
}
pub fn hasher(&self) -> &S {
self.map.hasher()
}
fn demote_item(value: &TransientMapValue<V>, tracker: &mut TransientUsageTracker<K>) {
let idx = value.index.get();
if tracker.first_used <= idx.wrapping_add(tracker.usage_offset) {
Self::swap_items(
value.index.get(),
tracker.first_used.wrapping_sub(tracker.usage_offset),
tracker,
);
tracker.first_used += 1;
}
}
fn promote_item(value: &TransientMapValue<V>, tracker: &mut TransientUsageTracker<K>) {
let idx = value.index.get();
if idx.wrapping_add(tracker.usage_offset) < tracker.first_used {
Self::swap_items(
value.index.get(),
(tracker.first_used - 1).wrapping_sub(tracker.usage_offset),
tracker,
);
tracker.first_used -= 1;
}
}
fn remove_item(value: &TransientMapValue<V>, tracker: &mut TransientUsageTracker<K>) -> Rc<K> {
let idx = value.index.get();
if idx.wrapping_add(tracker.usage_offset) < tracker.first_used {
Self::swap_items(idx, 0usize.wrapping_sub(tracker.usage_offset), tracker);
tracker.usage_offset = tracker.usage_offset.wrapping_sub(1);
tracker.first_used -= 1;
tracker.item_usage.pop_front()
} else {
Self::swap_items(
idx,
(tracker.item_usage.len() - 1).wrapping_sub(tracker.usage_offset),
tracker,
);
tracker.item_usage.pop_back()
}
.expect("The item usage deque was empty.")
.key
}
fn swap_items(a: usize, b: usize, tracker: &mut TransientUsageTracker<K>) {
let a_idx = a.wrapping_add(tracker.usage_offset);
let b_idx = b.wrapping_add(tracker.usage_offset);
tracker.item_usage[a_idx].index.set(b);
tracker.item_usage[b_idx].index.set(a);
tracker.item_usage.swap(a_idx, b_idx);
}
}
impl<K, V, S> TransientMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher,
{
pub fn drain_unused(&mut self) -> impl '_ + Iterator<Item = (K, V)> {
let tracker = self.tracker.get_mut();
let begin_used = tracker.first_used;
tracker.first_used = tracker.item_usage.len() - begin_used;
tracker.usage_offset = tracker.usage_offset.wrapping_sub(begin_used);
Drain {
map: &mut self.map,
iterator: tracker.item_usage.drain(..begin_used),
}
}
pub fn drain_used(&mut self) -> impl '_ + Iterator<Item = (K, V)> {
let first = self.tracker.get_mut().first_used;
Drain {
map: &mut self.map,
iterator: self.tracker.get_mut().item_usage.drain(first..),
}
}
pub fn reserve(&mut self, additional: usize) {
self.map.reserve(additional);
self.tracker.get_mut().item_usage.reserve(additional);
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
for (k, v) in &mut self.map {
if f(&**k, &mut v.value) {
Self::promote_item(v, self.tracker.get_mut());
} else {
Self::demote_item(v, self.tracker.get_mut());
}
}
drop(self.drain_unused());
}
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.map.try_reserve(additional)?;
self.tracker.get_mut().item_usage.try_reserve(additional)?;
Ok(())
}
pub fn shrink_to_fit(&mut self) {
self.map.shrink_to_fit();
self.tracker.get_mut().item_usage.shrink_to_fit();
}
pub fn shrink_to(&mut self, min_capacity: usize) {
self.map.shrink_to(min_capacity);
self.tracker.get_mut().item_usage.shrink_to(min_capacity);
}
pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
match self.map.entry(Rc::new(key)) {
hash_map::Entry::Vacant(e) => Entry::Vacant(VacantEntry {
inner: e,
tracker: self.tracker.get_mut(),
}),
hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
inner: e,
tracker: self.tracker.get_mut(),
}),
}
}
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
self.get_key_value(k).map(|(_, v)| v)
}
pub fn get_silent<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
self.get_key_value_silent(k).map(|(_, v)| v)
}
pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
self.map.get_key_value(k).map(|(k, h)| {
Self::promote_item(h, &mut self.tracker.borrow_mut());
(&**k, &h.value)
})
}
pub fn get_key_value_silent<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
self.map.get_key_value(k).map(|(k, h)| (&**k, &h.value))
}
pub fn contains_key_silent<Q: ?Sized>(&self, k: &Q) -> bool
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
self.map.contains_key(k)
}
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
self.map.get_mut(k).map(|value| {
Self::promote_item(value, self.tracker.get_mut());
&mut value.value
})
}
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
let initial_position = self.tracker.get_mut().item_usage.len();
self.insert_with_mover(
k,
v,
initial_position,
0,
Self::promote_item,
VecDeque::push_back,
)
}
pub fn insert_unused(&mut self, k: K, v: V) -> Option<V> {
self.insert_with_mover(k, v, 0, 1, Self::demote_item, VecDeque::push_front)
}
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
self.remove_entry(k).map(|(_, v)| v)
}
pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
where
Rc<K>: Borrow<Q>,
Q: Hash + Eq,
{
if let Some(prev) = self.map.remove(k) {
let key = Self::remove_item(&prev, self.tracker.get_mut());
Some((
Rc::try_unwrap(key)
.ok()
.expect("Another reference was still out to the stored key."),
prev.value,
))
} else {
None
}
}
fn insert_with_mover(
&mut self,
k: K,
v: V,
initial_position: usize,
usage_increment: usize,
mover: impl Fn(&TransientMapValue<V>, &mut TransientUsageTracker<K>),
pusher: impl Fn(&mut VecDeque<TransientMapItemUsage<K>>, TransientMapItemUsage<K>),
) -> Option<V> {
let tracker = self.tracker.get_mut();
let new_offset = tracker.usage_offset.wrapping_add(usage_increment);
let usage = TransientMapItemUsage {
key: Rc::new(k),
index: Rc::new(Cell::new(initial_position.wrapping_sub(new_offset))),
};
let value = TransientMapValue {
value: v,
index: usage.index.clone(),
};
if let Some(prev) = self.map.insert(usage.key.clone(), value) {
mover(&prev, tracker);
usage.index.set(prev.index.get());
tracker.item_usage[prev.index.get().wrapping_add(tracker.usage_offset)] = usage;
Some(prev.value)
} else {
tracker.usage_offset = new_offset;
tracker.first_used += usage_increment;
pusher(&mut tracker.item_usage, usage);
None
}
}
}
impl<K, V, S> Clone for TransientMap<K, V, S>
where
K: Clone,
V: Clone,
S: Clone,
{
fn clone(&self) -> Self {
let tracker = self.tracker.borrow();
Self {
map: self.map.clone(),
tracker: RefCell::new(TransientUsageTracker {
first_used: tracker.first_used,
item_usage: tracker.item_usage.clone(),
usage_offset: tracker.usage_offset,
}),
}
}
}
impl<K, V, S> Default for TransientMap<K, V, S>
where
S: Default,
{
fn default() -> Self {
Self {
map: HashMap::default(),
tracker: RefCell::new(TransientUsageTracker {
first_used: 0,
item_usage: VecDeque::new(),
usage_offset: 0,
}),
}
}
}
impl<K, V, S> PartialEq for TransientMap<K, V, S>
where
K: Eq + Hash,
V: PartialEq,
S: BuildHasher,
{
fn eq(&self, other: &Self) -> bool {
self.map == other.map
}
}
impl<K, V, S> Eq for TransientMap<K, V, S>
where
K: Eq + Hash,
V: Eq,
S: BuildHasher,
{
}
impl<K, V, S> std::fmt::Debug for TransientMap<K, V, S>
where
K: std::fmt::Debug,
V: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.map, f)
}
}
unsafe impl<K, V, S> Send for TransientMap<K, V, S>
where
K: Send,
V: Send,
S: Send,
{
}
struct Drain<'a, K, V, S, I: Iterator<Item = TransientMapItemUsage<K>>>
where
K: Eq + Hash,
S: BuildHasher,
{
map: &'a mut HashMap<Rc<K>, TransientMapValue<V>, S>,
iterator: I,
}
impl<'a, K, V, S, I: Iterator<Item = TransientMapItemUsage<K>>> Iterator for Drain<'a, K, V, S, I>
where
K: Eq + Hash,
S: BuildHasher,
{
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
let pair = self.iterator.next()?;
let value = self
.map
.remove(&pair.key)
.expect("Could not remove item from map.")
.value;
Some((
Rc::try_unwrap(pair.key)
.ok()
.expect("Another copy of key still existed."),
value,
))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iterator.size_hint()
}
}
impl<'a, K, V, S, I: Iterator<Item = TransientMapItemUsage<K>>> Drop for Drain<'a, K, V, S, I>
where
K: Eq + Hash,
S: BuildHasher,
{
fn drop(&mut self) {
for pair in &mut self.iterator {
self.map.remove(&pair.key);
}
}
}
impl<K, V, S> IntoIterator for TransientMap<K, V, S> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
iterator: self.map.into_iter(),
}
}
}
impl<'a, K, V, S> IntoIterator for &'a TransientMap<K, V, S> {
type Item = (&'a K, &'a V);
type IntoIter = Box<dyn 'a + Iterator<Item = (&'a K, &'a V)>>;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.iter())
}
}
impl<'a, K, V, S> IntoIterator for &'a mut TransientMap<K, V, S> {
type Item = (&'a K, &'a mut V);
type IntoIter = Box<dyn 'a + Iterator<Item = (&'a K, &'a mut V)>>;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.iter_mut())
}
}
pub struct IntoIter<K, V> {
iterator: hash_map::IntoIter<Rc<K>, TransientMapValue<V>>,
}
impl<K, V> Iterator for IntoIter<K, V> {
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.iterator.next().map(|(k, v)| {
(
Rc::try_unwrap(k)
.ok()
.expect("Another reference to the key was still held."),
v.value,
)
})
}
}
pub enum Entry<'a, K: 'a, V: 'a> {
Occupied(OccupiedEntry<'a, K, V>),
Vacant(VacantEntry<'a, K, V>),
}
pub struct VacantEntry<'a, K: 'a, V: 'a> {
inner: hash_map::VacantEntry<'a, Rc<K>, TransientMapValue<V>>,
tracker: &'a mut TransientUsageTracker<K>,
}
impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
pub fn insert(self, value: V) -> &'a mut V {
let usage = TransientMapItemUsage {
key: self.inner.key().clone(),
index: Rc::new(Cell::new(
self.tracker
.item_usage
.len()
.wrapping_sub(self.tracker.usage_offset),
)),
};
let value = TransientMapValue {
value,
index: usage.index.clone(),
};
self.tracker.item_usage.push_back(usage);
&mut self.inner.insert(value).value
}
pub fn insert_unused(self, value: V) -> &'a mut V {
let new_offset = self.tracker.usage_offset.wrapping_add(1);
let usage = TransientMapItemUsage {
key: self.inner.key().clone(),
index: Rc::new(Cell::new(0usize.wrapping_sub(new_offset))),
};
let value = TransientMapValue {
value,
index: usage.index.clone(),
};
self.tracker.usage_offset = new_offset;
self.tracker.first_used += 1;
self.tracker.item_usage.push_front(usage);
&mut self.inner.insert(value).value
}
pub fn key_silent(&self) -> &K {
self.inner.key()
}
pub fn into_key(self) -> K {
Rc::try_unwrap(self.inner.into_key())
.ok()
.expect("Another reference was still out to the stored key.")
}
}
unsafe impl<'a, K, V> Send for VacantEntry<'a, K, V>
where
K: Send,
V: Send,
{
}
unsafe impl<'a, K, V> Sync for VacantEntry<'a, K, V>
where
K: Sync,
V: Sync,
{
}
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
inner: hash_map::OccupiedEntry<'a, Rc<K>, TransientMapValue<V>>,
tracker: &'a mut TransientUsageTracker<K>,
}
impl<'a, K: 'a, V: 'a> OccupiedEntry<'a, K, V> {
pub fn get_silent(&self) -> &V {
&self.inner.get().value
}
pub fn get_mut(&mut self) -> &mut V {
let res = self.inner.get_mut();
TransientMap::<_, _, ()>::promote_item(res, self.tracker);
&mut res.value
}
pub fn insert(&mut self, value: V) -> V {
replace(self.get_mut(), value)
}
pub fn insert_unused(&mut self, value: V) -> V {
let res = self.inner.get_mut();
TransientMap::<_, _, ()>::demote_item(res, self.tracker);
replace(&mut res.value, value)
}
pub fn into_mut(self) -> &'a mut V {
let res = self.inner.into_mut();
TransientMap::<_, _, ()>::promote_item(res, self.tracker);
&mut res.value
}
pub fn key_silent(&self) -> &K {
self.inner.key()
}
pub fn remove(self) -> V {
self.remove_entry().1
}
pub fn remove_entry(self) -> (K, V) {
let (key, v) = self.inner.remove_entry();
TransientMap::<_, _, ()>::remove_item(&v, self.tracker);
(
Rc::try_unwrap(key)
.ok()
.expect("Another reference was still out to the stored key."),
v.value,
)
}
}
unsafe impl<'a, K, V> Send for OccupiedEntry<'a, K, V>
where
K: Send,
V: Send,
{
}
unsafe impl<'a, K, V> Sync for OccupiedEntry<'a, K, V>
where
K: Sync,
V: Sync,
{
}
struct TransientUsageTracker<K> {
pub first_used: usize,
pub item_usage: VecDeque<TransientMapItemUsage<K>>,
pub usage_offset: usize,
}
#[derive(Clone)]
struct TransientMapItemUsage<K> {
pub key: Rc<K>,
pub index: Rc<Cell<usize>>,
}
#[derive(Clone)]
struct TransientMapValue<V> {
pub value: V,
pub index: Rc<Cell<usize>>,
}
impl<V: PartialEq> PartialEq for TransientMapValue<V> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<V: Eq> Eq for TransientMapValue<V> {}
impl<V: std::fmt::Debug> std::fmt::Debug for TransientMapValue<V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.value, f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_drain_len() {
let mut map = TransientMap::new();
map.insert(1, "a");
map.insert(2, "b");
map.insert(3, "c");
drop(map.drain_unused());
map.get_mut(&1);
map.get_silent(&2);
let mut res = map.drain_unused().collect::<Vec<_>>();
res.sort_by(|a, b| a.0.cmp(&b.0));
assert_eq!(vec!((2, "b"), (3, "c")), res);
assert_eq!(1, map.len());
}
#[test]
pub fn test_drain_mark_used() {
let mut map = TransientMap::new();
map.insert(1, "a");
map.insert(2, "b");
map.insert(3, "c");
drop(map.drain_unused());
map.get_mut(&1);
map.get_silent(&2);
map.set_all_used();
drop(map.drain_unused());
assert_eq!(3, map.len());
}
#[test]
pub fn test_drain_mark_unused() {
let mut map = TransientMap::new();
map.insert(1, "a");
map.insert(2, "b");
map.insert(3, "c");
map.set_all_unused();
drop(map.drain_unused());
assert_eq!(0, map.len());
}
#[test]
pub fn test_insert_overwrite() {
let mut map = TransientMap::new();
map.insert(1, "a");
drop(map.drain_unused());
assert_eq!(Some("a"), map.insert(1, "b"));
drop(map.drain_unused());
assert_eq!(1, map.len());
}
#[test]
pub fn test_insert_no_overwrite() {
let mut map = TransientMap::new();
map.insert(1, "a");
drop(map.drain_unused());
drop(map.drain_unused());
assert_eq!(0, map.len());
}
#[test]
pub fn test_insert_unused() {
let mut map = TransientMap::new();
map.insert(1, "a");
map.insert_unused(2, "b");
assert_eq!(vec!((2, "b")), map.drain_unused().collect::<Vec<_>>());
}
#[test]
pub fn test_add_remove_drop() {
let mut map = TransientMap::new();
map.insert_unused(1, "a");
map.insert_unused(2, "b");
assert_eq!(Some("b"), map.remove(&2));
map.insert(3, "c");
map.insert(4, "d");
assert_eq!(vec!((1, "a")), map.drain_unused().collect::<Vec<_>>());
let mut res = map.drain_unused().collect::<Vec<_>>();
res.sort_by(|a, b| a.0.cmp(&b.0));
assert_eq!(vec!((3, "c"), (4, "d")), res);
assert_eq!(0, map.len());
}
}