use crate::typing::{ArgsRef, Record, Type, TypeRef};
use crate::{Attrs, ExprKey, ExprPtr, ExprRef, Field, RecRef, StrRef, Value, VecRef};
use rustc_hash::{FxBuildHasher, FxHashMap};
use serde::Serialize;
use std::collections::hash_map::Entry;
use std::hash::BuildHasher;
use std::ops::Range;
use unicase::Ascii;
#[derive(Default, Serialize)]
pub(crate) struct StringArena {
#[serde(skip_serializing)]
hasher: FxBuildHasher,
cache: FxHashMap<u64, StrRef>,
slots: Vec<String>,
}
impl StringArena {
pub fn alloc(&mut self, value: &str) -> StrRef {
match self.cache.entry(self.hasher.hash_one(value)) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let key = StrRef(self.slots.len());
entry.insert(key);
self.slots.push(value.to_owned());
key
}
}
}
pub fn str_ref(&self, value: &str) -> Option<StrRef> {
self.cache.get(&self.hasher.hash_one(value)).copied()
}
pub fn alloc_no_case(&mut self, value: &str) -> StrRef {
match self.cache.entry(self.hasher.hash_one(Ascii::new(value))) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let key = StrRef(self.slots.len());
entry.insert(key);
self.slots.push(value.to_owned());
key
}
}
}
pub fn get(&self, key: StrRef) -> &str {
&self.slots[key.0]
}
}
#[derive(Debug, Clone, Copy, Serialize)]
pub struct Expr {
pub attrs: Attrs,
pub value: Value,
}
#[derive(Default, Serialize)]
pub(crate) struct ExprArena {
#[serde(skip_serializing)]
hasher: FxBuildHasher,
exprs: Vec<Expr>,
vecs: Vec<Vec<ExprRef>>,
recs: Vec<Vec<Field>>,
}
impl ExprArena {
pub fn alloc(&mut self, attrs: Attrs, value: Value) -> ExprRef {
let key = ExprKey(self.hasher.hash_one(value));
let ptr = ExprPtr(self.exprs.len());
self.exprs.push(Expr { attrs, value });
ExprRef { key, ptr }
}
pub fn get(&self, node_ref: ExprRef) -> Expr {
self.exprs[node_ref.ptr.0]
}
pub fn alloc_vec(&mut self, values: Vec<ExprRef>) -> VecRef {
let key = VecRef(self.vecs.len());
self.vecs.push(values);
key
}
pub fn alloc_rec(&mut self, values: Vec<Field>) -> RecRef {
let key = RecRef(self.recs.len());
self.recs.push(values);
key
}
pub fn vec(&self, ptr: VecRef) -> &[ExprRef] {
&self.vecs[ptr.0]
}
pub fn vec_get(&self, ptr: VecRef, idx: usize) -> ExprRef {
self.vecs[ptr.0][idx]
}
pub fn vec_idxes(&self, ptr: VecRef) -> Range<usize> {
0..self.vec(ptr).len()
}
pub fn rec(&self, ptr: RecRef) -> &[Field] {
self.recs[ptr.0].as_slice()
}
pub fn rec_get(&self, ptr: RecRef, idx: usize) -> Field {
self.recs[ptr.0][idx]
}
pub fn rec_idxes(&self, ptr: RecRef) -> Range<usize> {
0..self.rec(ptr).len()
}
}
#[derive(Default, Serialize)]
pub(crate) struct TypeArena {
#[serde(skip_serializing)]
args_hasher: FxBuildHasher,
type_offset: usize,
rec_offset: usize,
dedup_types: FxHashMap<Type, TypeRef>,
dedup_args: FxHashMap<u64, ArgsRef>,
types: Vec<Type>,
pub(crate) records: Vec<FxHashMap<StrRef, Type>>,
pub(crate) args: Vec<Vec<Type>>,
}
impl TypeArena {
pub fn freeze(&mut self) {
self.rec_offset = self.records.len();
self.type_offset = self.types.len();
}
pub fn free_space(&mut self) {
for tpe in self.types.drain(self.type_offset..) {
self.dedup_types.remove(&tpe);
}
for _ in self.records.drain(self.rec_offset..) {}
}
pub fn register_type(&mut self, tpe: Type) -> TypeRef {
match self.dedup_types.entry(tpe) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let key = TypeRef(self.types.len());
self.types.push(tpe);
entry.insert(key);
key
}
}
}
pub fn alloc_type(&mut self, tpe: Type) -> Type {
if let Type::Record(rec) = tpe {
let key = Record {
id: self.records.len(),
open: rec.open,
};
self.records.push(self.records[rec.id].clone());
return Type::Record(key);
}
tpe
}
pub fn alloc_array_of(&mut self, tpe: Type) -> Type {
Type::Array(self.register_type(tpe))
}
pub fn alloc_record(&mut self, record: FxHashMap<StrRef, Type>) -> Record {
let key = Record {
id: self.records.len(),
open: false,
};
self.records.push(record);
key
}
pub fn alloc_open_record(&mut self, record: FxHashMap<StrRef, Type>) -> Record {
let key = Record {
id: self.records.len(),
open: true,
};
self.records.push(record);
key
}
pub fn alloc_args(&mut self, args: &[Type]) -> ArgsRef {
let hash = self.args_hasher.hash_one(args);
match self.dedup_args.entry(hash) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let key = ArgsRef(self.args.len());
entry.insert(key);
self.args.push(args.to_vec());
key
}
}
}
pub fn get_type(&self, key: TypeRef) -> Type {
self.types[key.0]
}
pub fn get_record(&self, key: Record) -> &FxHashMap<StrRef, Type> {
&self.records[key.id]
}
pub fn get_args(&self, key: ArgsRef) -> &[Type] {
self.args[key.0].as_slice()
}
pub fn args_idxes(&self, key: ArgsRef) -> impl Iterator<Item = usize> + use<> {
0..self.get_args(key).len()
}
pub fn args_get(&self, key: ArgsRef, idx: usize) -> Type {
self.get_args(key)[idx]
}
pub fn record_get(&self, record: Record, field: StrRef) -> Option<Type> {
self.records[record.id].get(&field).copied()
}
pub fn records_have_same_keys(&self, rec_a: Record, rec_b: Record) -> bool {
let rec_a = self.get_record(rec_a);
let rec_b = self.get_record(rec_b);
if rec_a.is_empty() && rec_b.is_empty() {
return true;
}
if rec_a.len() != rec_b.len() {
return false;
}
for bk in rec_b.keys() {
if !rec_a.contains_key(bk) {
return false;
}
}
true
}
pub fn instantiate_open_record(&mut self) -> Record {
self.alloc_open_record(FxHashMap::default())
}
pub fn record_set(&mut self, record: Record, field: StrRef, value: Type) {
self.records[record.id].insert(field, value);
}
pub fn record_len(&self, record: Record) -> usize {
self.records[record.id].len()
}
}
#[derive(Default, Serialize)]
pub struct Arena {
pub(crate) exprs: ExprArena,
pub(crate) strings: StringArena,
pub(crate) types: TypeArena,
}
impl Arena {
pub fn freeze(&mut self) {
self.types.freeze();
}
pub fn free_space(&mut self) {
self.types.free_space();
}
pub fn get_str(&self, key: StrRef) -> &str {
self.strings.get(key)
}
pub fn str_ref(&self, key: &str) -> Option<StrRef> {
self.strings.str_ref(key)
}
pub fn get_expr(&self, key: ExprRef) -> Expr {
self.exprs.get(key)
}
pub fn get_type(&self, key: TypeRef) -> Type {
self.types.get_type(key)
}
pub fn get_vec(&self, key: VecRef) -> &[ExprRef] {
self.exprs.vec(key)
}
pub fn get_rec(&self, key: RecRef) -> &[Field] {
self.exprs.rec(key)
}
pub fn get_type_rec(&self, key: Record) -> &FxHashMap<StrRef, Type> {
self.types.get_record(key)
}
pub fn get_args(&self, key: ArgsRef) -> &[Type] {
self.types.get_args(key)
}
}