use super::Reset;
use crate::{core::UntypedVal, engine::TranslationError, ir::Slot, Error};
use alloc::{
collections::{btree_map, BTreeMap},
vec::Vec,
};
use core::{iter::Rev, slice::Iter as SliceIter};
#[derive(Debug, Default)]
pub struct ConstRegistry {
const2idx: BTreeMap<UntypedVal, Slot>,
idx2const: Vec<UntypedVal>,
next_idx: i16,
}
impl Reset for ConstRegistry {
fn reset(&mut self) {
self.const2idx.clear();
self.idx2const.clear();
self.next_idx = Self::first_index();
}
}
impl ConstRegistry {
fn first_index() -> i16 {
-1
}
fn last_index() -> i16 {
i16::MIN
}
pub fn alloc(&mut self, value: UntypedVal) -> Result<Slot, Error> {
if self.next_idx == Self::last_index() {
return Err(Error::from(TranslationError::TooManyFuncLocalConstValues));
}
match self.const2idx.entry(value) {
btree_map::Entry::Occupied(entry) => Ok(*entry.get()),
btree_map::Entry::Vacant(entry) => {
let register = Slot::from(self.next_idx);
self.next_idx -= 1;
entry.insert(register);
self.idx2const.push(value);
Ok(register)
}
}
}
pub fn iter(&self) -> ConstRegistryIter<'_> {
ConstRegistryIter::new(self)
}
}
pub struct ConstRegistryIter<'a> {
iter: Rev<SliceIter<'a, UntypedVal>>,
}
impl<'a> ConstRegistryIter<'a> {
pub fn new(consts: &'a ConstRegistry) -> Self {
Self {
iter: consts.idx2const.as_slice().iter().rev(),
}
}
}
impl Iterator for ConstRegistryIter<'_> {
type Item = UntypedVal;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().copied()
}
}
impl DoubleEndedIterator for ConstRegistryIter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().copied()
}
}
impl ExactSizeIterator for ConstRegistryIter<'_> {
fn len(&self) -> usize {
self.iter.len()
}
}