use crate::arena::{ContextStack, DataValue};
use crate::operators::array::{IterArgKind, ResolvedInput, resolve_iter_input};
use crate::operators::meta::Extremum;
use crate::{CompiledNode, Engine, Result};
use bumpalo::Bump;
impl Extremum {
#[inline(always)]
fn init(self) -> f64 {
match self {
Extremum::Max => f64::NEG_INFINITY,
Extremum::Min => f64::INFINITY,
}
}
#[inline(always)]
fn beats(self, candidate: f64, best: f64) -> bool {
match self {
Extremum::Max => candidate > best,
Extremum::Min => candidate < best,
}
}
}
#[inline]
pub(crate) fn extremum<'a>(
args: &'a [CompiledNode],
iter_arg_kind: IterArgKind,
ctx: &mut ContextStack<'a>,
engine: &Engine,
arena: &'a Bump,
op: Extremum,
) -> Result<&'a DataValue<'a>> {
if args.len() > 1 {
return extremum_variadic(args, ctx, engine, arena, op);
}
if super::helpers::is_literal_array(&args[0]) {
return Err(crate::Error::invalid_args());
}
let src = match resolve_iter_input(&args[0], iter_arg_kind, ctx, engine, arena)? {
ResolvedInput::Iterable(s) => s,
ResolvedInput::Empty => return Err(crate::Error::invalid_args()),
ResolvedInput::Bridge(av) => {
debug_assert!(!matches!(av, DataValue::Array(_) | DataValue::Null));
if !matches!(av, DataValue::Number(_)) {
return Err(crate::Error::invalid_args());
}
return Ok(av);
}
};
if src.is_empty() {
return Err(crate::Error::invalid_args());
}
let mut best_f = op.init();
let mut best_idx: Option<usize> = None;
let len = src.len();
for i in 0..len {
match src.get(i) {
DataValue::Number(n) => {
let f = n.as_f64();
if op.beats(f, best_f) {
best_f = f;
best_idx = Some(i);
}
}
_ => return Err(crate::Error::invalid_args()),
}
}
match best_idx {
Some(i) => Ok(src.get(i)),
None => Ok(crate::arena::singletons::singleton_null()),
}
}
#[inline]
fn extremum_variadic<'a>(
args: &'a [CompiledNode],
ctx: &mut ContextStack<'a>,
engine: &Engine,
arena: &'a Bump,
op: Extremum,
) -> Result<&'a DataValue<'a>> {
let mut best_f = op.init();
let mut best_av: Option<&'a DataValue<'a>> = None;
for arg in args {
let av = engine.dispatch_node(arg, ctx, arena)?;
let f = match av {
DataValue::Number(n) => n.as_f64(),
_ => return Err(crate::Error::invalid_args()),
};
if op.beats(f, best_f) {
best_f = f;
best_av = Some(av);
}
}
match best_av {
Some(av) => Ok(av),
None => Ok(crate::arena::singletons::singleton_null()),
}
}