diff --git a/crates/fayalite/src/intern.rs b/crates/fayalite/src/intern.rs index 97dafe1..29337d7 100644 --- a/crates/fayalite/src/intern.rs +++ b/crates/fayalite/src/intern.rs @@ -16,9 +16,10 @@ use std::{ marker::PhantomData, ops::Deref, path::{Path, PathBuf}, - sync::{Mutex, RwLock}, + sync::RwLock, }; +mod interner; mod type_map; pub trait LazyInternedTrait: Send + Sync + Any { @@ -593,78 +594,6 @@ impl From> for Cow<'_, } } -struct InternerState { - table: HashTable<&'static T>, - hasher: DefaultBuildHasher, -} - -pub(crate) struct Interner { - state: Mutex>, -} - -impl Interner { - fn get() -> &'static Interner { - static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new(); - thread_local! { - static TYPE_ID_MAP_CACHE: TypeIdMap = const { TypeIdMap::new() }; - } - TYPE_ID_MAP_CACHE.with(|cache| { - cache.get_or_insert_with(|| { - TYPE_ID_MAP.get_or_insert_with(|| Box::leak(Default::default())) - }) - }) - } -} - -impl Default for Interner { - fn default() -> Self { - Self { - state: Mutex::new(InternerState { - table: HashTable::new(), - hasher: Default::default(), - }), - } - } -} - -impl Interner { - fn intern) -> &'static T>( - &self, - alloc: F, - value: Cow<'_, T>, - ) -> Interned { - let mut state = self.state.lock().unwrap(); - let InternerState { table, hasher } = &mut *state; - let inner = *table - .entry( - hasher.hash_one(&*value), - |k| **k == *value, - |k| hasher.hash_one(&**k), - ) - .or_insert_with(|| alloc(value)) - .get(); - Interned { inner } - } -} - -impl Interner { - fn intern_sized(&self, value: Cow<'_, T>) -> Interned { - self.intern(|value| Box::leak(Box::new(value.into_owned())), value) - } -} - -impl Interner<[T]> { - fn intern_slice(&self, value: Cow<'_, [T]>) -> Interned<[T]> { - self.intern(|value| value.into_owned().leak(), value) - } -} - -impl Interner { - fn intern_bit_slice(&self, value: Cow<'_, BitSlice>) -> Interned { - self.intern(|value| value.into_owned().leak(), value) - } -} - pub struct Interned { inner: &'static T, } @@ -984,7 +913,7 @@ impl Intern for T { where Self: ToOwned, { - Interner::get().intern_sized(this) + interner::Interner::get().intern_sized(this) } } @@ -1004,7 +933,7 @@ impl Intern for [T] { where Self: ToOwned, { - Interner::get().intern_slice(this) + interner::Interner::get().intern_slice(this) } } @@ -1024,7 +953,7 @@ impl Intern for BitSlice { where Self: ToOwned, { - Interner::get().intern_bit_slice(this) + interner::Interner::get().intern_bit_slice(this) } } diff --git a/crates/fayalite/src/intern/interner.rs b/crates/fayalite/src/intern/interner.rs new file mode 100644 index 0000000..45899af --- /dev/null +++ b/crates/fayalite/src/intern/interner.rs @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::{ + intern::{Interned, type_map::TypeIdMap}, + util::DefaultBuildHasher, +}; +use bitvec::slice::BitSlice; +use hashbrown::HashTable; +use std::{ + borrow::Cow, + hash::{BuildHasher, Hash}, + sync::Mutex, +}; + +struct InternerState { + table: HashTable<&'static T>, + hasher: DefaultBuildHasher, +} + +pub(crate) struct Interner { + state: Mutex>, +} + +impl Interner { + pub(crate) fn get() -> &'static Interner { + static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new(); + thread_local! { + static TYPE_ID_MAP_CACHE: TypeIdMap = const { TypeIdMap::new() }; + } + TYPE_ID_MAP_CACHE.with(|cache| { + cache.get_or_insert_with(|| { + TYPE_ID_MAP.get_or_insert_with(|| Box::leak(Default::default())) + }) + }) + } +} + +impl Default for Interner { + fn default() -> Self { + Self { + state: Mutex::new(InternerState { + table: HashTable::new(), + hasher: Default::default(), + }), + } + } +} + +impl Interner { + fn intern) -> &'static T>( + &self, + alloc: F, + value: Cow<'_, T>, + ) -> Interned { + let mut state = self.state.lock().unwrap(); + let InternerState { table, hasher } = &mut *state; + let inner = *table + .entry( + hasher.hash_one(&*value), + |k| **k == *value, + |k| hasher.hash_one(&**k), + ) + .or_insert_with(|| alloc(value)) + .get(); + Interned { inner } + } +} + +impl Interner { + pub(crate) fn intern_sized(&self, value: Cow<'_, T>) -> Interned { + self.intern(|value| Box::leak(Box::new(value.into_owned())), value) + } +} + +impl Interner<[T]> { + pub(crate) fn intern_slice(&self, value: Cow<'_, [T]>) -> Interned<[T]> { + self.intern(|value| value.into_owned().leak(), value) + } +} + +impl Interner { + pub(crate) fn intern_bit_slice(&self, value: Cow<'_, BitSlice>) -> Interned { + self.intern(|value| value.into_owned().leak(), value) + } +}