#![deny(missing_docs)]
use crate::boxedset::HashSet;
use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::sync::Mutex;
#[cfg_attr(docsrs, doc(cfg(feature = "arena")))]
pub struct Arena<T: ?Sized> {
data: Mutex<HashSet<Box<T>>>,
}
#[cfg(feature = "deepsize")]
impl<T: ?Sized + deepsize::DeepSizeOf> deepsize::DeepSizeOf for Arena<T> {
fn deep_size_of_children(&self, context: &mut deepsize::Context) -> usize {
let hashset = self.data.lock().unwrap();
(*hashset).deep_size_of_children(context)
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "arena")))]
pub struct ArenaIntern<'a, T: ?Sized> {
pointer: &'a T,
}
#[cfg(feature = "deepsize")]
impl<'a, T: ?Sized + deepsize::DeepSizeOf> deepsize::DeepSizeOf for ArenaIntern<'a, T> {
fn deep_size_of_children(&self, _context: &mut deepsize::Context) -> usize {
std::mem::size_of::<&T>()
}
}
impl<'a, T: ?Sized> Clone for ArenaIntern<'a, T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<'a, T: ?Sized> Copy for ArenaIntern<'a, T> {}
impl<T: ?Sized> Arena<T> {
#[inline]
pub fn new() -> Self {
Arena {
data: Mutex::new(HashSet::new()),
}
}
}
impl<T: Eq + Hash> Arena<T> {
pub fn intern(&self, val: T) -> ArenaIntern<T> {
let mut m = self.data.lock().unwrap();
if let Some(b) = m.get(&val) {
let p = b.as_ref() as *const T;
return ArenaIntern {
pointer: unsafe { &*p },
};
}
let b = Box::new(val);
let p = b.as_ref() as *const T;
m.insert(b);
ArenaIntern {
pointer: unsafe { &*p },
}
}
}
impl<T: Eq + Hash + ?Sized> Arena<T> {
pub fn intern_ref<'a, 'b, I>(&'a self, val: &'b I) -> ArenaIntern<'a, T>
where
T: 'a + Borrow<I>,
Box<T>: From<&'b I>,
I: Eq + std::hash::Hash + ?Sized,
{
let mut m = self.data.lock().unwrap();
if let Some(b) = m.get(val) {
let p = b.as_ref() as *const T;
return ArenaIntern {
pointer: unsafe { &*p },
};
}
let b: Box<T> = val.into();
let p = b.as_ref() as *const T;
m.insert(b);
ArenaIntern {
pointer: unsafe { &*p },
}
}
fn intern_from_owned<I>(&self, val: I) -> ArenaIntern<T>
where
Box<T>: From<I>,
I: Eq + std::hash::Hash + AsRef<T>,
{
let mut m = self.data.lock().unwrap();
if let Some(b) = m.get(val.as_ref()) {
let p = b.as_ref() as *const T;
return ArenaIntern {
pointer: unsafe { &*p },
};
}
let b: Box<T> = val.into();
let p = b.as_ref() as *const T;
m.insert(b);
ArenaIntern {
pointer: unsafe { &*p },
}
}
}
impl Arena<str> {
#[inline]
pub fn intern<'a>(&'a self, val: &str) -> ArenaIntern<'a, str> {
self.intern_ref(val)
}
#[inline]
pub fn intern_string(&self, val: String) -> ArenaIntern<str> {
self.intern_from_owned(val)
}
#[inline]
pub fn intern_box(&self, val: Box<str>) -> ArenaIntern<str> {
self.intern_from_owned(val)
}
}
impl Arena<std::ffi::CStr> {
#[inline]
pub fn intern<'a>(&'a self, val: &std::ffi::CStr) -> ArenaIntern<'a, std::ffi::CStr> {
self.intern_ref(val)
}
#[inline]
pub fn intern_cstring(&self, val: std::ffi::CString) -> ArenaIntern<std::ffi::CStr> {
self.intern_from_owned(val)
}
#[inline]
pub fn intern_box(&self, val: Box<std::ffi::CStr>) -> ArenaIntern<std::ffi::CStr> {
self.intern_from_owned(val)
}
}
impl Arena<std::ffi::OsStr> {
#[inline]
pub fn intern<'a>(&'a self, val: &std::ffi::OsStr) -> ArenaIntern<'a, std::ffi::OsStr> {
self.intern_ref(val)
}
#[inline]
pub fn intern_osstring(&self, val: std::ffi::OsString) -> ArenaIntern<std::ffi::OsStr> {
self.intern_from_owned(val)
}
#[inline]
pub fn intern_box(&self, val: Box<std::ffi::OsStr>) -> ArenaIntern<std::ffi::OsStr> {
self.intern_from_owned(val)
}
}
impl Arena<std::path::Path> {
#[inline]
pub fn intern<'a>(&'a self, val: &std::path::Path) -> ArenaIntern<'a, std::path::Path> {
self.intern_ref(val)
}
#[inline]
pub fn intern_pathbuf(&self, val: std::path::PathBuf) -> ArenaIntern<std::path::Path> {
self.intern_from_owned(val)
}
#[inline]
pub fn intern_box(&self, val: Box<std::path::Path>) -> ArenaIntern<std::path::Path> {
self.intern_from_owned(val)
}
}
impl<T: Eq + Hash + Copy> Arena<[T]> {
#[inline]
pub fn intern<'a>(&'a self, val: &[T]) -> ArenaIntern<'a, [T]> {
self.intern_ref(val)
}
#[inline]
pub fn intern_vec(&self, val: Vec<T>) -> ArenaIntern<[T]> {
self.intern_from_owned(val)
}
#[inline]
pub fn intern_box(&self, val: Box<[T]>) -> ArenaIntern<[T]> {
self.intern_from_owned(val)
}
}
impl<T: Eq + Hash + ?Sized> Arena<T> {
pub fn intern_from<'a, 'b, I>(&'a self, val: &'b I) -> ArenaIntern<'a, T>
where
T: 'a + Borrow<I> + From<&'b I>,
I: Eq + std::hash::Hash + ?Sized,
{
let mut m = self.data.lock().unwrap();
if let Some(b) = m.get(val) {
let p = b.as_ref() as *const T;
return ArenaIntern {
pointer: unsafe { &*p },
};
}
let b: Box<T> = Box::new(val.into());
let p = b.as_ref() as *const T;
m.insert(b);
ArenaIntern {
pointer: unsafe { &*p },
}
}
}
impl<T> Default for Arena<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<'a, T: ?Sized> AsRef<T> for ArenaIntern<'a, T> {
#[inline(always)]
fn as_ref(&self) -> &T {
self.pointer
}
}
impl<'a, T: ?Sized> std::ops::Deref for ArenaIntern<'a, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<'a, T: ?Sized> ArenaIntern<'a, T> {
#[inline(always)]
fn get_pointer(&self) -> *const T {
self.pointer as *const T
}
#[inline(always)]
pub fn into_ref(self) -> &'a T {
self.pointer
}
}
impl<'a, T: ?Sized> Hash for ArenaIntern<'a, T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.get_pointer().hash(state);
}
}
impl<'a, T: ?Sized> PartialEq for ArenaIntern<'a, T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.get_pointer(), other.get_pointer())
}
}
impl<'a, T: ?Sized> Eq for ArenaIntern<'a, T> {}
impl<'a, T: std::fmt::Debug + ?Sized> std::fmt::Debug for ArenaIntern<'a, T> {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.as_ref().fmt(f)
}
}
impl<'a, T: std::fmt::Display + ?Sized> std::fmt::Display for ArenaIntern<'a, T> {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.as_ref().fmt(f)
}
}
#[test]
fn eq_string() {
let arena = Arena::<&'static str>::new();
assert_eq!(arena.intern("hello"), arena.intern("hello"));
assert_ne!(arena.intern("goodbye"), arena.intern("farewell"));
}
#[test]
fn display() {
let arena = Arena::<&'static str>::new();
let world = arena.intern("world");
println!("Hello {}", world);
}
#[test]
fn debug() {
let arena = Arena::<&'static str>::new();
let world = arena.intern("world");
println!("Hello {:?}", world);
}
#[test]
fn can_clone() {
let arena = Arena::<&'static str>::new();
assert_eq!(arena.intern("hello").clone(), arena.intern("hello"));
}
#[test]
fn has_deref() {
let arena = Arena::<Option<String>>::new();
let x = arena.intern(None);
let b: &Option<String> = x.as_ref();
use std::ops::Deref;
assert_eq!(b, arena.intern(None).deref());
}
#[test]
fn unsized_str() {
let arena = Arena::<str>::new();
let x = arena.intern("hello");
let b: &str = x.as_ref();
assert_eq!("hello", b);
}
#[test]
fn ref_to_string() {
let arena = Arena::<String>::new();
let x = arena.intern_from("hello");
assert_eq!("hello", &*x);
}