fix string interning

This commit is contained in:
nora 2021-12-31 17:00:51 +01:00
parent d1179ff2ea
commit 9ed7998401
2 changed files with 34 additions and 5 deletions

View file

@ -74,10 +74,29 @@ enum HeapObjectKind {
#[derive(Debug)]
pub struct RtAlloc {
symbols: HashSet<NonNull<str>>,
symbols: HashSet<NonNullStrWrapper>,
objects: LinkedList<HeapObject>,
}
#[derive(Debug)]
struct NonNullStrWrapper(NonNull<str>);
impl Hash for NonNullStrWrapper {
fn hash<H: Hasher>(&self, state: &mut H) {
// SAFETY: Assume the ptr is valid, same rules as `Gc<T>`
unsafe { self.0.as_ref().hash(state) }
}
}
impl PartialEq for NonNullStrWrapper {
fn eq(&self, other: &Self) -> bool {
// SAFETY: Assume the ptr is valid, same rules as `Gc<T>`
unsafe { self.0.as_ref().eq(other.0.as_ref()) }
}
}
impl Eq for NonNullStrWrapper {}
impl RtAlloc {
/// # Safety
/// Promise to not forget to mark any roots and to not deref `Gc<T>` after you've dropped me 🥺
@ -119,10 +138,12 @@ impl RtAlloc {
pub fn intern_string(&mut self, str: &str) -> Symbol {
let original_nonnull = NonNull::from(str);
if let Some(interned) = self.symbols.get(&original_nonnull) {
Symbol::new(Gc { ptr: *interned })
if let Some(interned) = self.symbols.get(&NonNullStrWrapper(original_nonnull)) {
Symbol::new(Gc { ptr: interned.0 })
} else {
Symbol::new(self.alloc_str(str))
let allocated = self.alloc_str(str);
self.symbols.insert(NonNullStrWrapper(allocated.ptr));
Symbol::new(allocated)
}
}
}