use super::Register;
use crate::{core::UntypedVal, engine::TranslationError, Error};
use core::{iter::Rev, slice::Iter as SliceIter};
use std::{
collections::{btree_map, BTreeMap},
vec::Vec,
};
#[derive(Debug, Default)]
pub struct FuncLocalConsts {
const2idx: BTreeMap<UntypedVal, Register>,
idx2const: Vec<UntypedVal>,
next_idx: i16,
}
impl FuncLocalConsts {
pub fn reset(&mut self) {
self.const2idx.clear();
self.idx2const.clear();
self.next_idx = Self::first_index();
}
fn first_index() -> i16 {
-1
}
fn last_index() -> i16 {
i16::MIN
}
pub fn len_consts(&self) -> u16 {
self.next_idx.abs_diff(Self::first_index())
}
pub fn alloc(&mut self, value: UntypedVal) -> Result<Register, 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 = Register::from_i16(self.next_idx);
self.next_idx -= 1;
entry.insert(register);
self.idx2const.push(value);
Ok(register)
}
}
}
pub fn get(&self, register: Register) -> Option<UntypedVal> {
if !register.is_const() {
return None;
}
let index = register.to_i16().wrapping_add(1).unsigned_abs() as usize;
self.idx2const.get(index).copied()
}
pub fn iter(&self) -> FuncLocalConstsIter {
FuncLocalConstsIter::new(self)
}
}
pub struct FuncLocalConstsIter<'a> {
iter: Rev<SliceIter<'a, UntypedVal>>,
}
impl<'a> FuncLocalConstsIter<'a> {
pub fn new(consts: &'a FuncLocalConsts) -> Self {
Self {
iter: consts.idx2const.as_slice().iter().rev(),
}
}
}
impl<'a> Iterator for FuncLocalConstsIter<'a> {
type Item = UntypedVal;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().copied()
}
}
impl<'a> DoubleEndedIterator for FuncLocalConstsIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().copied()
}
}
impl<'a> ExactSizeIterator for FuncLocalConstsIter<'a> {
fn len(&self) -> usize {
self.iter.len()
}
}