use std::hash::Hash;
use std::num::NonZeroU32;
use std::sync::{LazyLock, RwLock};
use crate::helpers::{BiTigerHashMap, TigerHashMap};
use crate::token::{Loc, Token};
use crate::tooltipped::Tooltipped;
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
struct MacroKey {
loc: Loc,
args: Vec<(&'static str, &'static str)>,
tooltipped: Tooltipped,
negated: bool,
}
impl MacroKey {
pub fn new(
mut loc: Loc,
args: &[(&'static str, Token)],
tooltipped: Tooltipped,
negated: bool,
) -> Self {
loc.link_idx = None;
let mut args: Vec<_> = args.iter().map(|(parm, arg)| (*parm, arg.as_str())).collect();
args.sort_unstable();
Self { loc, args, tooltipped, negated }
}
}
#[derive(Debug)]
pub struct MacroCache<T> {
cache: RwLock<TigerHashMap<MacroKey, T>>,
}
impl<T> MacroCache<T> {
pub fn perform<F: FnMut(&T)>(
&self,
key: &Token,
args: &[(&'static str, Token)],
tooltipped: Tooltipped,
negated: bool,
mut f: F,
) -> bool {
let key = MacroKey::new(key.loc, args, tooltipped, negated);
if let Some(x) = self.cache.read().unwrap().get(&key) {
f(x);
true
} else {
false
}
}
pub fn insert(
&self,
key: &Token,
args: &[(&'static str, Token)],
tooltipped: Tooltipped,
negated: bool,
value: T,
) {
let key = MacroKey::new(key.loc, args, tooltipped, negated);
self.cache.write().unwrap().insert(key, value);
}
}
impl<T> Default for MacroCache<T> {
fn default() -> Self {
MacroCache { cache: RwLock::new(TigerHashMap::default()) }
}
}
pub(crate) static MACRO_MAP: LazyLock<MacroMap> = LazyLock::new(MacroMap::default);
#[derive(Default)]
pub struct MacroMap(RwLock<MacroMapInner>);
pub struct MacroMapInner {
counter: NonZeroU32,
bi_map: BiTigerHashMap<NonZeroU32, Loc>,
}
impl Default for MacroMapInner {
fn default() -> Self {
Self { counter: NonZeroU32::new(1).unwrap(), bi_map: BiTigerHashMap::default() }
}
}
impl MacroMap {
pub fn get_loc(&self, index: MacroMapIndex) -> Option<Loc> {
self.0.read().unwrap().bi_map.get_by_left(&index.0).copied()
}
pub fn get_index(&self, loc: Loc) -> Option<MacroMapIndex> {
self.0.read().unwrap().bi_map.get_by_right(&loc).copied().map(MacroMapIndex)
}
pub fn insert_or_get_loc(&self, loc: Loc) -> MacroMapIndex {
let mut guard = self.0.write().unwrap();
let counter = guard.counter;
if guard.bi_map.insert_no_overwrite(counter, loc).is_err() {
return guard.bi_map.get_by_right(&loc).copied().map(MacroMapIndex).unwrap();
}
guard.counter =
guard.counter.checked_add(1).expect("internal error: 2^32 macro map entries");
MacroMapIndex(counter)
}
pub fn get_or_insert_loc(&self, loc: Loc) -> MacroMapIndex {
if let Some(index) = self.get_index(loc) {
index
} else {
self.insert_or_get_loc(loc)
}
}
pub(crate) fn clear(&self) {
let mut guard = self.0.write().unwrap();
guard.counter = NonZeroU32::new(1).unwrap();
guard.bi_map.clear();
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MacroMapIndex(NonZeroU32);