diff --git a/compiler/cl-structures/Cargo.toml b/compiler/cl-structures/Cargo.toml index b8e7ea9..f12136c 100644 --- a/compiler/cl-structures/Cargo.toml +++ b/compiler/cl-structures/Cargo.toml @@ -8,3 +8,4 @@ license.workspace = true publish.workspace = true [dependencies] +hashbrown = { version = "0.14.3", default-features = false } diff --git a/compiler/cl-structures/src/arena/intern.rs b/compiler/cl-structures/src/arena/intern.rs index 9caef1e..71b0ee0 100644 --- a/compiler/cl-structures/src/arena/intern.rs +++ b/compiler/cl-structures/src/arena/intern.rs @@ -1,55 +1,49 @@ //! A string interner with deduplication use super::{symbol::Symbol, StringArena}; -use std::{ - collections::{hash_map::RawEntryMut, HashMap}, - hash::{BuildHasher, RandomState}, -}; +use hashbrown::hash_table::HashTable; +use std::hash::{BuildHasher, RandomState}; #[derive(Debug)] -pub struct Interner { - map: HashMap, - arena: StringArena, +pub struct Interner { + set: HashTable, + arena: StringArena, hasher: H, } -impl Default for Interner { +impl Default for Interner { fn default() -> Self { - Self { map: Default::default(), arena: Default::default(), hasher: Default::default() } + Self { set: Default::default(), arena: Default::default(), hasher: Default::default() } } } -impl Interner { - pub fn get_or_insert(&mut self, s: &str) -> T { - let Self { map, arena, hasher } = self; +impl Interner { + pub fn get_or_insert(&mut self, s: &str) -> Sym { + let Self { set: map, arena, hasher } = self; let hash = hasher.hash_one(s); - match map.raw_entry_mut().from_hash(hash, is_match(s, arena)) { - RawEntryMut::Occupied(entry) => *entry.into_key(), - RawEntryMut::Vacant(entry) => { - let tok = arena.push_string(s); - *(entry.insert_hashed_nocheck(hash, tok, ()).0) - } - } + *map.entry(hash, is_match(s, arena), |t| { + hasher.hash_one(arena.get(*t).unwrap()) + }) + .or_insert_with(|| arena.push_string(s)) + .get() } - pub fn get(&self, s: &str) -> Option { - let Self { map, arena, hasher } = self; - map.raw_entry() - .from_hash(hasher.hash_one(s), is_match(s, arena)) - .map(|entry| *entry.0) + pub fn get(&self, s: &str) -> Option { + let Self { set: map, arena, hasher } = self; + map.find(hasher.hash_one(s), is_match(s, arena)).copied() } - pub fn get_str(&self, sym: T) -> Option<&str> { + pub fn get_str(&self, sym: Sym) -> Option<&str> { self.arena.get(sym) } } -fn is_match<'a, T: Symbol>( - target: &'a str, - arena: &'a StringArena, -) -> impl Fn(&T) -> bool + 'a { +fn is_match<'a, Sym: Symbol>( + s: &'a str, + arena: &'a StringArena, +) -> impl Fn(&Sym) -> bool + 'a { move |sym| match arena.get(*sym) { - Some(sym) => sym == target, + Some(sym) => sym == s, None => false, } } diff --git a/compiler/cl-structures/src/lib.rs b/compiler/cl-structures/src/lib.rs index 8c73740..f992597 100644 --- a/compiler/cl-structures/src/lib.rs +++ b/compiler/cl-structures/src/lib.rs @@ -2,13 +2,7 @@ //! - [Span](struct@span::Span): Stores a start and end [Loc](struct@span::Loc) //! - [Loc](struct@span::Loc): Stores the index in a stream #![warn(clippy::all)] -#![feature( - inline_const, - dropck_eyepatch, - decl_macro, - get_many_mut, - hash_raw_entry -)] +#![feature(inline_const, dropck_eyepatch, decl_macro, get_many_mut)] #![deny(unsafe_op_in_unsafe_fn)] pub mod arena;