use cairo_lang_semantic::TypeId;
use cairo_lang_utils::casts::IntoOrPanic;
use crate::db::LoweringGroup;
use crate::{FlatBlockEnd, FlatLowered, Statement, VarUsage, VariableId};
pub trait InlineWeight {
fn calling_weight(&self, lowered: &FlatLowered) -> isize;
fn statement_weight(&self, statement: &Statement) -> isize;
fn block_end_weight(&self, block_end: &FlatBlockEnd) -> isize;
fn lowered_weight(&self, lowered: &FlatLowered) -> isize {
self.calling_weight(lowered)
+ lowered
.blocks
.iter()
.map(|(_, block)| {
block
.statements
.iter()
.map(|statement| self.statement_weight(statement))
.sum::<isize>()
+ self.block_end_weight(&block.end)
})
.sum::<isize>()
}
}
pub struct SimpleInlineWeight;
impl InlineWeight for SimpleInlineWeight {
fn calling_weight(&self, _lowered: &FlatLowered) -> isize {
0
}
fn statement_weight(&self, _statement: &Statement) -> isize {
1
}
fn block_end_weight(&self, _block_end: &FlatBlockEnd) -> isize {
1
}
}
pub struct ApproxCasmInlineWeight<'a> {
db: &'a dyn LoweringGroup,
lowered: &'a FlatLowered,
}
impl<'a> ApproxCasmInlineWeight<'a> {
pub fn new(db: &'a dyn LoweringGroup, lowered: &'a FlatLowered) -> Self {
Self { db, lowered }
}
fn tys_total_size(&self, tys: impl IntoIterator<Item = TypeId>) -> usize {
tys.into_iter().map(|ty| self.db.type_size(ty)).sum()
}
fn vars_size<'b, I: IntoIterator<Item = &'b VariableId>>(&self, vars: I) -> usize {
self.tys_total_size(vars.into_iter().map(|v| self.lowered.variables[*v].ty))
}
fn inputs_size<'b, I: IntoIterator<Item = &'b VarUsage>>(&self, vars: I) -> usize {
self.vars_size(vars.into_iter().map(|v| &v.var_id))
}
}
impl InlineWeight for ApproxCasmInlineWeight<'_> {
fn calling_weight(&self, _lowered: &FlatLowered) -> isize {
0
}
fn statement_weight(&self, statement: &Statement) -> isize {
match statement {
Statement::Call(statement_call) => self.inputs_size(&statement_call.inputs),
_ => 0,
}
.into_or_panic()
}
fn block_end_weight(&self, block_end: &FlatBlockEnd) -> isize {
match block_end {
FlatBlockEnd::Return(..) => 0,
FlatBlockEnd::Goto(_, r) => self.vars_size(r.keys()),
FlatBlockEnd::Match { info } => info.arms().len() + self.inputs_size(info.inputs()),
FlatBlockEnd::Panic(_) | FlatBlockEnd::NotSet => unreachable!(),
}
.into_or_panic()
}
}