cl-structures: Use hashbrown's hash table implementation for deduplication.
This commit is contained in:
parent
e70ffd1895
commit
be604b7b45
@ -8,3 +8,4 @@ license.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
hashbrown = { version = "0.14.3", default-features = false }
|
||||
|
@ -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<T: Symbol, H: BuildHasher = RandomState> {
|
||||
map: HashMap<T, ()>,
|
||||
arena: StringArena<T>,
|
||||
pub struct Interner<Sym: Symbol, H: BuildHasher = RandomState> {
|
||||
set: HashTable<Sym>,
|
||||
arena: StringArena<Sym>,
|
||||
hasher: H,
|
||||
}
|
||||
|
||||
impl<T: Symbol, H: BuildHasher + Default> Default for Interner<T, H> {
|
||||
impl<Sym: Symbol, H: BuildHasher + Default> Default for Interner<Sym, H> {
|
||||
fn default() -> Self {
|
||||
Self { map: Default::default(), arena: Default::default(), hasher: Default::default() }
|
||||
Self { set: Default::default(), arena: Default::default(), hasher: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Symbol, H: BuildHasher> Interner<T, H> {
|
||||
pub fn get_or_insert(&mut self, s: &str) -> T {
|
||||
let Self { map, arena, hasher } = self;
|
||||
impl<Sym: Symbol, H: BuildHasher> Interner<Sym, H> {
|
||||
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<T> {
|
||||
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<Sym> {
|
||||
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<T>,
|
||||
) -> impl Fn(&T) -> bool + 'a {
|
||||
fn is_match<'a, Sym: Symbol>(
|
||||
s: &'a str,
|
||||
arena: &'a StringArena<Sym>,
|
||||
) -> impl Fn(&Sym) -> bool + 'a {
|
||||
move |sym| match arena.get(*sym) {
|
||||
Some(sym) => sym == target,
|
||||
Some(sym) => sym == s,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user