use std::hash::Hash;
use indexmap::IndexMap;
use parking_lot::Mutex;
pub struct DeduplicatingContainer<'a, T: Eq + Hash + ?Sized> {
items: Mutex<IndexMap<&'a T, *mut T>>,
}
impl<'a, T: Eq + Hash + ?Sized> DeduplicatingContainer<'a, T> {
#[must_use]
pub fn new() -> Self {
DeduplicatingContainer {
items: Mutex::new(IndexMap::new()),
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
items: Mutex::new(IndexMap::with_capacity(capacity)),
}
}
pub fn count(&self) -> usize {
self.items.lock().len()
}
}
impl<'a, T: Eq + Hash> DeduplicatingContainer<'a, T> {
pub fn put(&self, item: T) -> &T {
unsafe {
let mut items = self.items.lock();
if let Some(existing) = items.get(&item) {
&**existing
} else {
let item_ref = Box::into_raw(Box::new(item));
items.insert(&*item_ref, item_ref);
&*item_ref
}
}
}
}
impl<'a, T: Eq + Hash + ?Sized> DeduplicatingContainer<'a, T> {
pub fn put_boxed(&self, item: Box<T>) -> &T {
unsafe {
let mut items = self.items.lock();
if let Some(existing) = items.get(&*item) {
&**existing
} else {
let item_ref = Box::into_raw(item);
items.insert(&*item_ref, item_ref);
&*item_ref
}
}
}
}
impl<'a, T: Eq + Hash + ?Sized> Default for DeduplicatingContainer<'a, T> {
fn default() -> Self {
Self::new()
}
}
impl<'a, T: Eq + Hash + ?Sized> Drop for DeduplicatingContainer<'a, T> {
fn drop(&mut self) {
for &p in self.items.lock().values().rev() {
unsafe {
let _ = Box::from_raw(p);
}
}
}
}
unsafe impl<'a, T: Eq + Hash + Send + ?Sized> Send for DeduplicatingContainer<'a, T> {}
unsafe impl<'a, T: Eq + Hash + Send + Sync + ?Sized> Sync for DeduplicatingContainer<'a, T> {}