use bumpalo::Bump;
use exp_rs::{
EvalContext,
engine::parse_expression,
eval::iterative::{EvalEngine, eval_with_engine},
expression::Expression,
};
use std::rc::Rc;
#[test]
fn test_arena_zero_allocations() {
let arena = Bump::with_capacity(64 * 1024);
let expr1 = parse_expression("x * 2 + y", &arena).unwrap();
let expr2 = parse_expression("sin(x) + cos(y)", &arena).unwrap();
let initial_bytes = arena.allocated_bytes();
println!("Arena bytes after parsing: {}", initial_bytes);
let mut ctx = EvalContext::new();
ctx.set_parameter("x", 1.0).unwrap();
ctx.set_parameter("y", 2.0).unwrap();
let ctx = Rc::new(ctx);
let mut engine = EvalEngine::new(&arena);
let mut ctx_first = (*ctx).clone();
ctx_first.set_parameter("x", 0.0).unwrap();
let ctx_rc_first = Rc::new(ctx_first);
let _result1 = eval_with_engine(&expr1, Some(ctx_rc_first.clone()), &mut engine).unwrap();
let _result2 = eval_with_engine(&expr2, Some(ctx_rc_first), &mut engine).unwrap();
let bytes_after_first_eval = arena.allocated_bytes();
println!(
"Arena bytes after first evaluation: {}",
bytes_after_first_eval
);
for i in 1..1000 {
let mut ctx_clone = (*ctx).clone();
ctx_clone.set_parameter("x", i as f64).unwrap();
let ctx_rc = Rc::new(ctx_clone);
let result1 = eval_with_engine(&expr1, Some(ctx_rc.clone()), &mut engine).unwrap();
let _result2 = eval_with_engine(&expr2, Some(ctx_rc), &mut engine).unwrap();
assert_eq!(result1, (i as f64) * 2.0 + 2.0);
assert_eq!(
arena.allocated_bytes(),
bytes_after_first_eval,
"Arena grew during evaluation #{} (beyond initial evaluator setup)",
i
);
}
println!("✓ No additional arena growth beyond evaluator setup during 1000 evaluations!");
}
#[test]
fn test_batch_builder_arena() {
let arena = Bump::with_capacity(64 * 1024);
let mut builder = Expression::new(&arena);
builder.add_parameter("x", 0.0).unwrap();
builder.add_parameter("y", 0.0).unwrap();
let idx1 = builder.add_expression("x * 2 + y").unwrap();
let idx2 = builder.add_expression("x + y * 3").unwrap();
let initial_bytes = arena.allocated_bytes();
println!("Arena bytes after setup: {}", initial_bytes);
let ctx = Rc::new(EvalContext::new());
for i in 0..1000 {
builder.set_param_by_name("x", i as f64).unwrap();
builder.set_param_by_name("y", (i * 2) as f64).unwrap();
builder.eval(&ctx).unwrap();
assert_eq!(
builder.get_result(idx1).unwrap(),
(i as f64) * 2.0 + (i * 2) as f64
);
assert_eq!(
builder.get_result(idx2).unwrap(),
(i as f64) + (i * 2) as f64 * 3.0
);
assert_eq!(
arena.allocated_bytes(),
initial_bytes,
"Arena grew during batch evaluation #{}",
i
);
}
println!("✓ Zero arena allocations during 1000 batch evaluations!");
}