use crate::arena::{ContextStack, DataValue, IterGuard, bvec};
use crate::operators::comparison::slice_contains_strict;
use crate::{CompiledNode, Engine, Result};
use bumpalo::Bump;
use super::input::{Items, IterSrc};
#[inline]
pub(crate) fn evaluate_distinct<'a>(
items: Items<'a>,
args: &'a [CompiledNode],
ctx: &mut ContextStack<'a>,
engine: &Engine,
arena: &'a Bump,
) -> Result<&'a DataValue<'a>> {
let Items::Array(src) = items else {
return Err(crate::Error::invalid_args());
};
if args.len() < 2 {
return distinct_by_value(&src, ctx, engine, arena);
}
distinct_by_key(&src, &args[1], ctx, engine, arena)
}
#[inline]
fn distinct_by_value<'a>(
src: &IterSrc<'a>,
ctx: &mut ContextStack<'a>,
engine: &Engine,
arena: &'a Bump,
) -> Result<&'a DataValue<'a>> {
let len = src.len();
let mut kept = bvec::<DataValue<'a>>(arena, len);
for i in 0..len {
let item = src.get(i);
if !slice_contains_strict(&kept, item, engine, ctx)? {
kept.push(*item);
}
}
Ok(arena.alloc(DataValue::Array(kept.into_bump_slice())))
}
#[inline]
fn distinct_by_key<'a>(
src: &IterSrc<'a>,
key_expr: &'a CompiledNode,
ctx: &mut ContextStack<'a>,
engine: &Engine,
arena: &'a Bump,
) -> Result<&'a DataValue<'a>> {
let len = src.len();
let mut seen_keys = bvec::<DataValue<'a>>(arena, len);
let mut kept = bvec::<DataValue<'a>>(arena, len);
let mut guard = IterGuard::new(ctx);
for i in 0..len {
let item = src.get(i);
guard.step_indexed(item, i);
let key = engine.dispatch_node(key_expr, guard.stack(), arena)?;
if !slice_contains_strict(&seen_keys, key, engine, guard.stack())? {
seen_keys.push(*key);
kept.push(*item);
}
}
drop(guard);
Ok(arena.alloc(DataValue::Array(kept.into_bump_slice())))
}