use std::cell::{Cell, RefCell};
use std::cmp::Ordering;
use std::convert::Infallible;
use std::hash::Hasher;
use crate::refers::Shape as Part;
use super::dense::Dense;
use super::eval::{
arithmetic, binary, compare_numbers, compares, finite, Arg, Computed, Ctx, Env, Known, Library,
Reason, Strict,
};
use super::formula::{BinOp, Expr, RefExpr};
use super::graph::{Area, CellId};
use super::library::{self, Axis, Fold, Ranged, Rule};
use super::value::{ErrorKind, Value};
pub(crate) const CHUNK: usize = 256;
type Got = Result<Value, Reason>;
#[derive(Debug)]
enum Lane {
Same(Got),
Each(Vec<Got>),
Numbers(Vec<f64>),
Truths(Vec<bool>),
}
impl Lane {
#[inline]
fn with<R>(&self, k: usize, f: impl FnOnce(Result<&Value, &Reason>) -> R) -> R {
match self {
Lane::Same(got) => f(got.as_ref()),
Lane::Each(each) => f(each[k].as_ref()),
Lane::Numbers(ns) => f(Ok(&Value::Number(ns[k]))),
Lane::Truths(ts) => f(Ok(&Value::Bool(ts[k]))),
}
}
fn take_at(&mut self, k: usize, last: bool) -> Got {
match self {
Lane::Same(got) if last => std::mem::replace(got, Ok(Value::Empty)),
Lane::Same(got) => got.clone(),
Lane::Each(each) => std::mem::replace(&mut each[k], Ok(Value::Empty)),
Lane::Numbers(ns) => Ok(Value::Number(ns[k])),
Lane::Truths(ts) => Ok(Value::Bool(ts[k])),
}
}
}
enum Values {
Same(Got),
Each(Vec<Got>),
}
fn is_arithmetic(op: BinOp) -> bool {
matches!(
op,
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Pow
)
}
#[derive(Debug, Default)]
pub(crate) struct Lanes {
values: Vec<Vec<Got>>,
numbers: Vec<Vec<f64>>,
truths: Vec<Vec<bool>>,
positions: Vec<Vec<u32>>,
found: Vec<Key>,
kept: Vec<Option<Lane>>,
}
impl Lanes {
fn reserve(&mut self, (values, positions): (usize, usize)) {
while self.values.len() < values {
self.values.push(Vec::with_capacity(CHUNK));
}
while self.numbers.len() < values {
self.numbers.push(Vec::with_capacity(CHUNK));
}
while self.truths.len() < values {
self.truths.push(Vec::with_capacity(CHUNK));
}
while self.positions.len() < positions {
self.positions.push(Vec::with_capacity(CHUNK));
}
}
#[cfg(test)]
pub(crate) fn made(&self) -> (usize, usize, usize, usize, usize) {
let most = self.values.iter().map(Vec::capacity);
let most = most
.chain(self.numbers.iter().map(Vec::capacity))
.chain(self.truths.iter().map(Vec::capacity))
.chain(self.positions.iter().map(Vec::capacity))
.max();
(
self.values.len(),
self.numbers.len(),
self.truths.len(),
self.positions.len(),
most.unwrap_or(0),
)
}
}
pub(crate) fn holds(lib: &Library, e: &Expr) -> (usize, usize) {
match e {
Expr::Number(_) | Expr::Text(_) | Expr::Bool(_) | Expr::Error(_) | Expr::Empty => (0, 0),
Expr::Ref(_) | Expr::Name { .. } => (1, 0),
Expr::Neg(x) | Expr::Pos(x) | Expr::Percent(x) => holds(lib, x),
Expr::Binary(..) => {
let (mut values, mut positions) = (0, 0);
let mut left = e;
while let Expr::Binary(_, l, r) = left {
let (v, p) = holds(lib, r);
values = values.max(1 + v);
positions = positions.max(p);
left = l;
}
let (v, p) = holds(lib, left);
(values.max(v), positions.max(p))
}
Expr::Call(name, args) => {
if lib.form(name).is_some() {
let known = lib.known(name);
if known == Some(Known::Choose) && args.len() >= 2 {
let (mut values, mut positions) = holds(lib, &args[0]);
values = values.max(2);
positions = positions.max(3);
for a in &args[1..] {
let (v, p) = holds(lib, a);
values = values.max(1 + v);
positions = positions.max(3 + p);
}
return (values, positions);
}
if known != Some(Known::If) || !(2..=3).contains(&args.len()) {
return (1, 0);
}
let (mut values, mut positions) = holds(lib, &args[0]);
values = values.max(2);
for a in &args[1..] {
let (v, p) = holds(lib, a);
values = values.max(1 + v);
positions = positions.max(3 + p);
}
(values, positions)
} else if lib.strict(name).is_none() {
(0, 0)
} else if !args.iter().all(|a| is_operand(lib, a)) {
(1, 0)
} else {
let (mut values, mut positions) = (args.len() + 1, 0);
for (j, a) in args.iter().enumerate() {
let (v, p) = holds(lib, a);
values = values.max(j + v);
positions = positions.max(p);
}
(values, positions)
}
}
}
}
fn is_operand(lib: &Library, a: &Expr) -> bool {
match a {
Expr::Ref(_) => true,
Expr::Pos(x) => is_operand(lib, x),
_ => yields_value(lib, a),
}
}
fn ref_operand<'e>(lib: &Library, a: &'e Expr) -> Option<&'e RefExpr> {
match a {
Expr::Ref(r) => Some(r),
Expr::Pos(x) if !yields_value(lib, a) => ref_operand(lib, x),
_ => None,
}
}
fn yields_value(lib: &Library, e: &Expr) -> bool {
match e {
Expr::Ref(_) | Expr::Name { .. } => false,
Expr::Pos(x) => yields_value(lib, x),
Expr::Call(name, args) => match lib.known(name) {
Some(Known::If | Known::Choose) => args.iter().skip(1).all(|a| yields_value(lib, a)),
_ => lib.form(name).is_none(),
},
_ => true,
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub(crate) struct Repeats {
places: Vec<(u16, bool, u32)>,
steps: Vec<u16>,
parts: usize,
}
impl Repeats {
pub(crate) fn of(lib: &Library, e: &Expr) -> Repeats {
struct Node<'e> {
e: &'e Expr,
parent: u32,
branch: u32,
reached: bool,
size: u32,
hash: u64,
}
let mut nodes: Vec<Node> = Vec::new();
let mut stack: Vec<(&Expr, u32, u32, bool)> = vec![(e, u32::MAX, 0, true)];
let mut candidates = 0;
while let Some((x, parent, branch, reached)) = stack.pop() {
let at = nodes.len() as u32;
candidates += usize::from(reached && !literal(x));
nodes.push(Node {
e: x,
parent,
branch,
reached,
size: 1,
hash: 0,
});
match x {
Expr::Neg(y) | Expr::Pos(y) | Expr::Percent(y) => {
stack.push((y, at, branch, reached));
}
Expr::Binary(_, l, r) => {
stack.push((r, at, branch, reached));
stack.push((l, at, branch, reached));
}
Expr::Call(name, args) => {
let how = reaches(lib, name, args);
for (j, a) in args.iter().enumerate().rev() {
let (b, r) = match how {
Reaches::If if j > 0 => (at * 4 + j as u32, reached),
Reaches::If => (branch, reached),
Reaches::Operands => (branch, reached && ref_operand(lib, a).is_none()),
Reaches::None => (branch, false),
};
stack.push((a, at, b, r));
}
}
_ => {}
}
}
if candidates < 2 {
return Repeats::default();
}
for i in (1..nodes.len()).rev() {
let p = nodes[i].parent as usize;
nodes[p].size += nodes[i].size;
}
for i in (0..nodes.len()).rev() {
let mut h = crate::fx::FxHasher::default();
node_hash(nodes[i].e, &mut h);
let mut c = i + 1;
for _ in 0..arity(nodes[i].e) {
h.write_u64(nodes[c].hash);
c += nodes[c].size as usize;
}
nodes[i].hash = h.finish();
}
let mut reached: Vec<Key> = (1..nodes.len() as u32)
.filter(|&i| nodes[i as usize].reached && !literal(nodes[i as usize].e))
.map(|i| (nodes[i as usize].hash as usize, nodes[i as usize].branch, i))
.collect();
reached.sort_unstable();
let mut members: Vec<u32> = Vec::new();
let mut groups: Vec<Key> = Vec::new();
let mut taken = vec![false; reached.len()];
for a in 0..reached.len() {
if taken[a] {
continue;
}
let (hash, branch, first) = reached[a];
let start = members.len();
for (b, &(h, br, i)) in reached.iter().enumerate().skip(a) {
if (h, br) != (hash, branch) {
break;
}
if !taken[b] && same_part(nodes[first as usize].e, nodes[i as usize].e) {
taken[b] = true;
members.push(i);
}
}
match members.len() - start {
0 | 1 => members.truncate(start),
n => {
let size = nodes[first as usize].size as usize;
groups.push((usize::MAX - size, start as u32, n as u32));
}
}
}
groups.sort_unstable();
let mut hidden = vec![false; nodes.len()];
let mut kept: Vec<Key> = Vec::new();
let mut parts = 0;
for &(_, start, n) in &groups {
let at = start as usize;
let places: Vec<u32> = members[at..at + n as usize]
.iter()
.copied()
.filter(|&i| !hidden[i as usize])
.collect();
if places.len() < 2 || parts == usize::from(u16::MAX) {
continue;
}
for (k, &i) in places.iter().enumerate() {
kept.push((i as usize, parts as u32, u32::from(k + 1 == places.len())));
if k > 0 {
let end = i + nodes[i as usize].size;
for h in &mut hidden[i as usize + 1..end as usize] {
*h = true;
}
}
}
parts += 1;
}
if parts == 0 {
return Repeats::default();
}
kept.sort_unstable();
let mut out = Repeats {
parts,
..Repeats::default()
};
let mut path: Vec<u16> = Vec::new();
for (i, part, last) in kept {
let (i, part, last) = (i as u32, part as u16, last == 1);
path.clear();
let mut c = i as usize;
while nodes[c].parent != u32::MAX {
let p = nodes[c].parent as usize;
let (mut child, mut s) = (0u16, p + 1);
while s != c {
s += nodes[s].size as usize;
child += 1;
}
path.push(child);
c = p;
}
out.steps.extend(path.iter().rev());
out.places.push((part, last, out.steps.len() as u32));
}
out
}
pub(crate) fn parts(&self) -> usize {
self.parts
}
#[cfg(test)]
pub(crate) fn places(&self) -> usize {
self.places.len()
}
fn found(&self, root: &Expr, out: &mut Vec<Key>) {
out.clear();
let mut from = 0;
for &(part, last, to) in &self.places {
let path = &self.steps[from..to as usize];
from = to as usize;
let mut e = Some(root);
for &k in path {
e = match (e, usize::from(k)) {
(Some(Expr::Neg(x) | Expr::Pos(x) | Expr::Percent(x)), 0) => Some(&**x),
(Some(Expr::Binary(_, l, _)), 0) => Some(&**l),
(Some(Expr::Binary(_, _, r)), 1) => Some(&**r),
(Some(Expr::Call(_, args)), j) => args.get(j),
_ => None,
};
}
debug_assert!(e.is_some(), "a place's path leaves its parse");
if let Some(e) = e {
let at = e as *const Expr as usize;
out.push((at, u32::from(part) << 1 | u32::from(last), 0));
}
}
out.sort_unstable();
}
}
type Key = (usize, u32, u32);
enum Reaches {
If,
Operands,
None,
}
fn reaches(lib: &Library, name: &str, args: &[Expr]) -> Reaches {
if lib.form(name).is_some() {
if lib.known(name) == Some(Known::If) && (2..=3).contains(&args.len()) {
Reaches::If
} else {
Reaches::None
}
} else if lib.strict(name).is_none() || !args.iter().all(|a| is_operand(lib, a)) {
Reaches::None
} else {
Reaches::Operands
}
}
fn literal(e: &Expr) -> bool {
matches!(
e,
Expr::Number(_) | Expr::Text(_) | Expr::Bool(_) | Expr::Error(_) | Expr::Empty
)
}
fn arity(e: &Expr) -> usize {
match e {
Expr::Neg(_) | Expr::Pos(_) | Expr::Percent(_) => 1,
Expr::Binary(..) => 2,
Expr::Call(_, args) => args.len(),
_ => 0,
}
}
fn node_hash(e: &Expr, h: &mut crate::fx::FxHasher) {
use std::hash::Hash;
std::mem::discriminant(e).hash(h);
match e {
Expr::Number(v) => h.write_u64(v.to_bits()),
Expr::Text(t) => t.hash(h),
Expr::Bool(b) => b.hash(h),
Expr::Error(k) => k.hash(h),
Expr::Ref(r) => {
r.written.hash(h);
r.sheet.hash(h);
(r.top, r.left, r.bottom, r.right).hash(h);
}
Expr::Name { name, sheet } => {
name.hash(h);
sheet.hash(h);
}
Expr::Call(name, args) => {
name.hash(h);
args.len().hash(h);
}
Expr::Binary(op, ..) => std::mem::discriminant(op).hash(h),
Expr::Empty | Expr::Neg(_) | Expr::Pos(_) | Expr::Percent(_) => {}
}
}
fn same_part(a: &Expr, b: &Expr) -> bool {
let mut stack = vec![(a, b)];
while let Some(pair) = stack.pop() {
match pair {
(Expr::Number(x), Expr::Number(y)) if x.to_bits() == y.to_bits() => {}
(Expr::Text(x), Expr::Text(y)) if x == y => {}
(Expr::Bool(x), Expr::Bool(y)) if x == y => {}
(Expr::Error(x), Expr::Error(y)) if x == y => {}
(Expr::Empty, Expr::Empty) => {}
(Expr::Ref(x), Expr::Ref(y)) if x == y => {}
(Expr::Name { name, sheet }, Expr::Name { name: n, sheet: s })
if name == n && sheet == s => {}
(Expr::Call(f, xs), Expr::Call(g, ys)) if f == g && xs.len() == ys.len() => {
stack.extend(xs.iter().zip(ys));
}
(Expr::Neg(x), Expr::Neg(y))
| (Expr::Pos(x), Expr::Pos(y))
| (Expr::Percent(x), Expr::Percent(y)) => stack.push((x, y)),
(Expr::Binary(o, l, r), Expr::Binary(p, m, s)) if o == p => {
stack.push((r, s));
stack.push((l, m));
}
_ => return false,
}
}
true
}
#[derive(Clone, Copy)]
enum Sel<'s> {
All(usize),
Some(&'s [u32]),
}
impl Sel<'_> {
fn len(self) -> usize {
match self {
Sel::All(n) => n,
Sel::Some(at) => at.len(),
}
}
fn at(self, k: usize) -> usize {
match self {
Sel::All(_) => k,
Sel::Some(at) => at[k] as usize,
}
}
}
enum Operand<'e> {
Ref(&'e RefExpr),
Value(Lane),
}
const COUNTED: usize = 8;
enum Parted {
All(bool),
Answer(Lane),
Cells(Lane, Vec<u32>, Vec<u32>),
}
enum Picked {
All(usize),
Answer(Lane),
Cells(Lane, Vec<u32>, Vec<u32>),
}
struct Many<'a> {
env: &'a dyn Env,
lib: &'a Library,
cells: &'a [CellId],
anchor: CellId,
lanes: RefCell<&'a mut Lanes>,
found: Vec<Key>,
kept: RefCell<Vec<Option<Lane>>>,
computing: Cell<usize>,
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn evaluate(
env: &dyn Env,
lib: &Library,
expr: &Expr,
held: (usize, usize),
repeats: &Repeats,
anchor: CellId,
cells: &[CellId],
lanes: &mut Lanes,
out: &mut Vec<Computed>,
) {
lanes.reserve(held);
let mut found = std::mem::take(&mut lanes.found);
repeats.found(expr, &mut found);
let mut kept = std::mem::take(&mut lanes.kept);
kept.clear();
kept.resize_with(repeats.parts(), || None);
let many = Many {
env,
lib,
cells,
anchor,
lanes: RefCell::new(lanes),
found,
kept: RefCell::new(kept),
computing: Cell::new(0),
};
match many.scalars(expr, Sel::All(cells.len())) {
Lane::Same(got) => {
if let Some((_, rest)) = cells.split_last() {
for _ in rest {
out.push(computed(got.clone()));
}
out.push(computed(got));
}
}
Lane::Each(mut each) => {
out.extend(each.drain(..).map(computed));
many.give(each);
}
Lane::Numbers(numbers) => {
out.extend(numbers.iter().map(|&n| Computed::Value(Value::Number(n))));
many.give_numbers(numbers);
}
Lane::Truths(truths) => {
out.extend(truths.iter().map(|&b| Computed::Value(Value::Bool(b))));
many.give_truths(truths);
}
}
for k in 0..repeats.parts() {
let lane = many.kept.borrow_mut()[k].take();
if let Some(lane) = lane {
many.give_lane(lane);
}
}
let Many {
lanes, found, kept, ..
} = many;
let lanes = lanes.into_inner();
lanes.found = found;
lanes.kept = kept.into_inner();
}
fn computed(got: Got) -> Computed {
match got {
Ok(v) => Computed::Value(v.settled()),
Err(r) => Computed::NotComputed(r),
}
}
impl<'a> Many<'a> {
fn offset(&self, pos: usize) -> (i64, i64) {
let (_, row, col) = self.cells[pos];
(
i64::from(row) - i64::from(self.anchor.1),
i64::from(col) - i64::from(self.anchor.2),
)
}
fn ctx(&self, pos: usize) -> Ctx<'a> {
self.env.enter(self.cells[pos]);
let (d_row, d_col) = self.offset(pos);
Ctx::at(self.env, self.lib, d_row, d_col)
}
fn take(&self) -> Vec<Got> {
let kept = self.lanes.borrow_mut().values.pop();
kept.unwrap_or_else(|| Vec::with_capacity(CHUNK))
}
fn give(&self, mut lane: Vec<Got>) {
lane.clear();
self.lanes.borrow_mut().values.push(lane);
}
fn take_numbers(&self) -> Vec<f64> {
let kept = self.lanes.borrow_mut().numbers.pop();
kept.unwrap_or_else(|| Vec::with_capacity(CHUNK))
}
fn give_numbers(&self, mut lane: Vec<f64>) {
lane.clear();
self.lanes.borrow_mut().numbers.push(lane);
}
fn take_truths(&self) -> Vec<bool> {
let kept = self.lanes.borrow_mut().truths.pop();
kept.unwrap_or_else(|| Vec::with_capacity(CHUNK))
}
fn give_truths(&self, mut lane: Vec<bool>) {
lane.clear();
self.lanes.borrow_mut().truths.push(lane);
}
fn give_lane(&self, lane: Lane) {
match lane {
Lane::Same(_) => {}
Lane::Each(each) => self.give(each),
Lane::Numbers(numbers) => self.give_numbers(numbers),
Lane::Truths(truths) => self.give_truths(truths),
}
}
fn values(&self, lane: Lane) -> Values {
match lane {
Lane::Same(got) => Values::Same(got),
Lane::Each(each) => Values::Each(each),
Lane::Numbers(numbers) => {
let mut each = self.take();
each.extend(numbers.iter().map(|&n| Ok(Value::Number(n))));
self.give_numbers(numbers);
Values::Each(each)
}
Lane::Truths(truths) => {
let mut each = self.take();
each.extend(truths.iter().map(|&b| Ok(Value::Bool(b))));
self.give_truths(truths);
Values::Each(each)
}
}
}
fn valued(&self, lane: Lane) -> Lane {
match self.values(lane) {
Values::Same(got) => Lane::Same(got),
Values::Each(each) => Lane::Each(each),
}
}
fn arithmetic_in_place(&self, mut numbers: Vec<f64>, f: impl Fn(usize, f64) -> Value) -> Lane {
for k in 0..numbers.len() {
match f(k, numbers[k]) {
Value::Number(n) => numbers[k] = n,
other => {
let mut each = self.take();
each.extend(numbers[..k].iter().map(|&n| Ok(Value::Number(n))));
each.push(Ok(other));
each.extend((k + 1..numbers.len()).map(|j| Ok(f(j, numbers[j]))));
self.give_numbers(numbers);
return Lane::Each(each);
}
}
}
Lane::Numbers(numbers)
}
fn compared(&self, op: BinOp, n: usize, ordering: impl Fn(usize) -> Ordering) -> Lane {
let mut truths = self.take_truths();
truths.extend((0..n).map(|k| compares(op, ordering(k))));
Lane::Truths(truths)
}
fn push(&self, lane: &mut Lane, got: Got) {
match (&mut *lane, got) {
(Lane::Each(each), got) => each.push(got),
(Lane::Numbers(numbers), Ok(Value::Number(n))) => numbers.push(n),
(Lane::Truths(truths), Ok(Value::Bool(b))) => truths.push(b),
(_, got) => {
let made = std::mem::replace(lane, Lane::Same(Ok(Value::Empty)));
*lane = self.valued(made);
if let Lane::Each(each) = lane {
each.push(got);
}
}
}
}
fn positions(&self) -> Vec<u32> {
let kept = self.lanes.borrow_mut().positions.pop();
kept.unwrap_or_else(|| Vec::with_capacity(CHUNK))
}
fn give_positions(&self, mut at: Vec<u32>) {
at.clear();
self.lanes.borrow_mut().positions.push(at);
}
fn scalars(&self, e: &Expr, sel: Sel) -> Lane {
if self.repeated(e) {
return self.again(e, &sel);
}
match e {
Expr::Number(v) => Lane::Same(Ok(Value::Number(*v))),
Expr::Text(t) => Lane::Same(Ok(Value::Text(t.clone()))),
Expr::Bool(b) => Lane::Same(Ok(Value::Bool(*b))),
Expr::Error(k) => Lane::Same(Ok(Value::Error(*k))),
Expr::Empty => Lane::Same(Ok(Value::Empty)),
Expr::Ref(r) if matches!(r.shape, Part::Cell) && r.last_sheet.is_none() => {
self.reads(r, sel)
}
Expr::Neg(x) => self.unary(x, sel, |n| -n),
Expr::Pos(x) => self.scalars(x, sel),
Expr::Percent(x) => self.unary(x, sel, |n| n / 100.0),
Expr::Binary(..) => self.chain(e, sel),
Expr::Call(name, args) => self.call(e, name, args, sel),
Expr::Ref(_) | Expr::Name { .. } => self.each_cell(e, sel),
}
}
fn repeated(&self, e: &Expr) -> bool {
let at = e as *const Expr as usize;
!self.found.is_empty() && self.computing.replace(0) != at && self.part_at(at).is_some()
}
fn part_at(&self, at: usize) -> Option<(u16, bool)> {
let i = self.found.binary_search_by_key(&at, |&(a, _, _)| a).ok()?;
let (_, place, _) = self.found[i];
Some(((place >> 1) as u16, place & 1 == 1))
}
#[inline(never)]
fn again(&self, e: &Expr, sel: &Sel) -> Lane {
let at = e as *const Expr as usize;
let Some((part, last)) = self.part_at(at) else {
self.computing.set(at);
return self.scalars(e, *sel);
};
let k = usize::from(part);
let held = self.kept.borrow_mut()[k].take();
match held {
Some(lane) if last => lane,
Some(lane) => {
let copy = self.copied(&lane);
self.kept.borrow_mut()[k] = Some(lane);
copy
}
None => {
self.computing.set(at);
let lane = self.scalars(e, *sel);
if !last {
let copy = self.copied(&lane);
self.kept.borrow_mut()[k] = Some(copy);
}
lane
}
}
}
fn copied(&self, lane: &Lane) -> Lane {
match lane {
Lane::Same(got) => Lane::Same(got.clone()),
Lane::Each(each) => {
let mut copy = self.take();
copy.extend(each.iter().cloned());
Lane::Each(copy)
}
Lane::Numbers(numbers) => {
let mut copy = self.take_numbers();
copy.extend_from_slice(numbers);
Lane::Numbers(copy)
}
Lane::Truths(truths) => {
let mut copy = self.take_truths();
copy.extend_from_slice(truths);
Lane::Truths(copy)
}
}
}
fn reads(&self, r: &RefExpr, sel: Sel) -> Lane {
if sel.len() == 0 {
return Lane::Each(self.take());
}
let sheet = match (r.found, &r.sheet) {
(Some((first, _)), _) => usize::from(first),
(None, None) => self.cells[sel.at(0)].0,
(None, Some(name)) => match self.env.model().find_sheet(name) {
Some(s) => s,
None => return Lane::Same(Ok(Value::Error(ErrorKind::Ref))),
},
};
let dense = self.env.dense(sheet);
let at = |k: usize| -> Result<f64, Got> {
let (d_row, d_col) = self.offset(sel.at(k));
let Some((row, col, _, _)) = r.moved(d_row, d_col) else {
return Err(Ok(Value::Error(ErrorKind::Ref)));
};
match dense.and_then(|d| d.get(row, col)) {
Some(Value::Number(n)) => Ok(*n),
Some(v) if !matches!(v, Value::Empty) => Err(Ok(v.clone())),
_ => match self.env.read((sheet, row, col)) {
Ok(Value::Number(n)) => Ok(n),
got => Err(got),
},
}
};
let got = |k: usize| -> Got {
match at(k) {
Ok(n) => Ok(Value::Number(n)),
Err(other) => other,
}
};
if r.corners.row_abs1 && r.corners.col_abs1 {
return Lane::Same(got(0));
}
let mut numbers = self.take_numbers();
for k in 0..sel.len() {
match at(k) {
Ok(n) => numbers.push(n),
Err(other) => {
let mut out = self.take();
out.extend(numbers.iter().map(|&n| Ok(Value::Number(n))));
self.give_numbers(numbers);
out.push(other);
out.extend((k + 1..sel.len()).map(got));
return Lane::Each(out);
}
}
}
Lane::Numbers(numbers)
}
fn unary(&self, x: &Expr, sel: Sel, f: fn(f64) -> f64) -> Lane {
let lane = self.scalars(x, sel);
self.signed(lane, f)
}
#[inline(never)]
fn signed(&self, lane: Lane, f: fn(f64) -> f64) -> Lane {
let number = |v: &mut Value| {
*v = match v.number() {
Ok(n) => finite(f(n)),
Err(k) => Value::Error(k),
}
};
match lane {
Lane::Numbers(numbers) => self.numbers_mapped(numbers, |n| finite(f(n))),
lane => match self.values(lane) {
Values::Same(mut got) => {
if let Ok(v) = got.as_mut() {
number(v);
}
Lane::Same(got)
}
Values::Each(mut each) => {
for v in each.iter_mut().flatten() {
number(v);
}
Lane::Each(each)
}
},
}
}
fn numbers_mapped(&self, mut numbers: Vec<f64>, f: impl Fn(f64) -> Value) -> Lane {
for k in 0..numbers.len() {
match f(numbers[k]) {
Value::Number(n) => numbers[k] = n,
other => {
let mut each = self.take();
each.extend(numbers[..k].iter().map(|&n| Ok(Value::Number(n))));
each.push(Ok(other));
each.extend(numbers[k + 1..].iter().map(|&n| Ok(f(n))));
self.give_numbers(numbers);
return Lane::Each(each);
}
}
}
Lane::Numbers(numbers)
}
fn chain(&self, e: &Expr, sel: Sel) -> Lane {
const NEAR: usize = 16;
let mut near: [(BinOp, &Expr); NEAR] = [(BinOp::Add, e); NEAR];
let mut far: Vec<(BinOp, &Expr)> = Vec::new();
let mut links = 0;
let mut left = e;
while let Expr::Binary(op, l, r) = left {
if links > 0 && self.repeated(left) {
break;
}
if links < NEAR {
near[links] = (*op, r);
} else {
far.push((*op, r));
}
links += 1;
left = l;
}
let mut acc = self.scalars(left, sel);
for i in (0..links).rev() {
let (op, r) = if i < NEAR { near[i] } else { far[i - NEAR] };
let b = self.scalars(r, sel);
acc = self.combine(op, acc, b);
}
acc
}
fn combine(&self, op: BinOp, a: Lane, b: Lane) -> Lane {
let (a, b) = match (op, a, b) {
(BinOp::Concat, a, b) => (self.values(a), self.values(b)),
(op, Lane::Numbers(xs), Lane::Numbers(ys)) => {
let lane = if is_arithmetic(op) {
self.arithmetic_in_place(xs, |k, x| arithmetic(op, x, ys[k]))
} else {
let lane = self.compared(op, xs.len(), |k| compare_numbers(xs[k], ys[k]));
self.give_numbers(xs);
lane
};
self.give_numbers(ys);
return lane;
}
(op, Lane::Numbers(xs), Lane::Same(Ok(Value::Number(y)))) => {
return if is_arithmetic(op) {
self.arithmetic_in_place(xs, |_, x| arithmetic(op, x, y))
} else {
let lane = self.compared(op, xs.len(), |k| compare_numbers(xs[k], y));
self.give_numbers(xs);
lane
};
}
(op, Lane::Same(Ok(Value::Number(x))), Lane::Numbers(ys)) => {
return if is_arithmetic(op) {
self.arithmetic_in_place(ys, |_, y| arithmetic(op, x, y))
} else {
let lane = self.compared(op, ys.len(), |k| compare_numbers(x, ys[k]));
self.give_numbers(ys);
lane
};
}
(_, a, b) => (self.values(a), self.values(b)),
};
match (a, b) {
(Values::Same(x), Values::Same(y)) => Lane::Same(match (x, &y) {
(Err(r), _) => Err(r),
(Ok(_), Err(r)) => Err(r.clone()),
(Ok(x), Ok(y)) => Ok(binary(op, &x, y)),
}),
(Values::Each(mut xs), Values::Same(y)) => {
for x in xs.iter_mut() {
if let Ok(a) = x {
match &y {
Ok(b) => *a = binary(op, a, b),
Err(r) => *x = Err(r.clone()),
}
}
}
Lane::Each(xs)
}
(Values::Same(x), Values::Each(mut ys)) => {
for y in ys.iter_mut() {
match &x {
Err(r) => *y = Err(r.clone()),
Ok(a) => {
if let Ok(b) = y {
*b = binary(op, a, b);
}
}
}
}
Lane::Each(ys)
}
(Values::Each(mut xs), Values::Each(mut ys)) => {
for (x, y) in xs.iter_mut().zip(ys.iter_mut()) {
if let Ok(a) = x {
match y {
Ok(b) => *a = binary(op, a, b),
Err(r) => *x = Err(std::mem::replace(r, Reason::Cycle)),
}
}
}
self.give(ys);
Lane::Each(xs)
}
}
}
fn call(&self, e: &Expr, name: &str, args: &[Expr], sel: Sel) -> Lane {
if self.lib.form(name).is_some() {
return match self.lib.known(name) {
Some(Known::If) => self.if_(args, sel),
Some(Known::Choose) => self.choose(args, sel),
_ => self.each_cell(e, sel),
};
}
let Some(f) = self.lib.strict(name) else {
return Lane::Same(Err(Reason::Function(name.to_string())));
};
if !args.iter().all(|a| is_operand(self.lib, a)) {
return self.each_cell(e, sel);
}
match args {
[a] => {
let mut x = self.operand(a, sel);
let lane = self.apply_one(f, name, &mut x, sel);
self.drop_operand(x);
lane
}
[a, b] => {
let mut x = self.operand(a, sel);
let mut y = self.operand(b, sel);
let lane = self.apply_two(f, name, &mut x, &mut y, sel);
self.drop_operand(x);
self.drop_operand(y);
lane
}
_ => {
let mut ops: Vec<Operand> = args.iter().map(|a| self.operand(a, sel)).collect();
let lane = self.apply_many(f, name, &mut ops, sel);
for x in ops {
self.drop_operand(x);
}
lane
}
}
}
fn known_call(&self, f: Strict, name: &str, ops: &mut [Operand<'_>], sel: Sel) -> Option<Lane> {
match self.lib.known(name)? {
Known::Abs => self.of_numbers(f, 1, ops, sel, |a, _| library::abs_of(a)),
Known::Int => self.of_numbers(f, 1, ops, sel, |a, _| library::int_of(a)),
Known::Sin => self.of_numbers(f, 1, ops, sel, |a, _| library::sin_of(a)),
Known::Mod => self.of_numbers(f, 2, ops, sel, library::mod_of),
Known::Row => self.placed(Axis::Row, ops, sel),
Known::Column => self.placed(Axis::Column, ops, sel),
known => self.known(known, ops, sel),
}
}
fn operand<'e>(&self, a: &'e Expr, sel: Sel) -> Operand<'e> {
match ref_operand(self.lib, a) {
Some(r) => Operand::Ref(r),
None => Operand::Value(self.scalars(a, sel)),
}
}
fn known(&self, known: Known, ops: &mut [Operand<'_>], sel: Sel) -> Option<Lane> {
if known == Known::Not {
let [Operand::Value(lane)] = ops else {
return None;
};
let lane = std::mem::replace(lane, Lane::Same(Ok(Value::Empty)));
return Some(self.negated(lane, sel));
}
if ops.len() > COUNTED {
return None;
}
let mut kept: [Option<(usize, &Dense)>; COUNTED] = [None; COUNTED];
for (j, x) in ops.iter().enumerate() {
let Operand::Ref(r) = x else {
continue;
};
if r.last_sheet.is_some() {
return None;
}
let sheet = match (r.found, &r.sheet) {
(Some((first, _)), _) => Some(usize::from(first)),
(None, None) => Some(self.cells[0].0),
(None, Some(name)) => self.env.model().find_sheet(name),
};
if let Some(s) = sheet {
kept[j] = Some((s, self.env.dense(s)?));
}
}
let kept = &kept[..ops.len()];
let numbers = || Lane::Numbers(self.take_numbers());
let truths = || Lane::Truths(self.take_truths());
Some(match known {
Known::Sum => self.aggregate::<library::Sum>(ops, kept, sel, numbers()),
Known::Min => self.aggregate::<library::Least>(ops, kept, sel, numbers()),
Known::Max => self.aggregate::<library::Most>(ops, kept, sel, numbers()),
Known::And => self.aggregate::<library::All>(ops, kept, sel, truths()),
Known::Or => self.aggregate::<library::Some_>(ops, kept, sel, truths()),
Known::If
| Known::Choose
| Known::Not
| Known::Abs
| Known::Int
| Known::Sin
| Known::Mod
| Known::Row
| Known::Column => return None,
})
}
#[inline(never)]
fn placed(&self, axis: Axis, ops: &mut [Operand<'_>], sel: Sel) -> Option<Lane> {
match ops {
[] => {
let mut numbers = self.take_numbers();
numbers.extend((0..sel.len()).map(|k| {
let (_, row, column) = self.cells[sel.at(k)];
axis.of(row, column)
}));
Some(Lane::Numbers(numbers))
}
[Operand::Ref(r)]
if r.found.is_some() || (r.sheet.is_none() && r.last_sheet.is_none()) =>
{
let mut out = Lane::Numbers(self.take_numbers());
for k in 0..sel.len() {
let (d_row, d_col) = self.offset(sel.at(k));
let cell = r.moved(d_row, d_col).map(|(top, left, _, _)| (top, left));
self.push(&mut out, Ok(library::placed(axis, cell)));
}
Some(out)
}
_ => None,
}
}
#[inline(never)]
fn of_numbers<G: Fn(f64, f64) -> Value>(
&self,
f: Strict,
count: usize,
ops: &mut [Operand<'_>],
sel: Sel,
g: G,
) -> Option<Lane> {
if ops.len() != count {
return None;
}
let one_cell = |r: &RefExpr| matches!(r.shape, Part::Cell) && r.last_sheet.is_none();
if ops
.iter()
.any(|x| matches!(x, Operand::Ref(r) if !one_cell(r)))
{
return None;
}
let read = self.read_refs(ops, sel);
Some(self.numbers_by(f, count, ops, read, sel, g))
}
#[inline(never)]
fn read_refs(&self, ops: &[Operand<'_>], sel: Sel) -> [Option<Lane>; 2] {
let mut read: [Option<Lane>; 2] = [None, None];
for (j, x) in ops.iter().enumerate().take(2) {
if let Operand::Ref(r) = x {
read[j] = Some(self.reads(r, sel));
}
}
read
}
#[inline(never)]
fn numbers_by<G: Fn(f64, f64) -> Value>(
&self,
f: Strict,
count: usize,
ops: &mut [Operand<'_>],
read: [Option<Lane>; 2],
sel: Sel,
g: G,
) -> Lane {
let n = sel.len();
let mut out = Lane::Numbers(self.take_numbers());
for k in 0..n {
let a = number_at(operand_lane(&read[0], &ops[0]), k);
let b = match count {
2 => number_at(operand_lane(&read[1], &ops[1]), k),
_ => Some(0.0),
};
let got = match (a, b) {
(Some(a), Some(b)) => Ok(g(a, b)),
_ => self.alone(f, ops, k, k + 1 == n, sel),
};
self.push(&mut out, got);
}
for lane in read.into_iter().flatten() {
self.give_lane(lane);
}
out
}
fn alone(&self, f: Strict, ops: &mut [Operand<'_>], k: usize, last: bool, sel: Sel) -> Got {
let ctx = self.ctx(sel.at(k));
match ops {
[x] => match take_arg(x, k, last, &ctx) {
Ok(a) => f(&ctx, std::slice::from_ref(&a)),
Err(r) => Err(r),
},
[x, y] => match take_arg(x, k, last, &ctx) {
Err(r) => Err(r),
Ok(a) => match take_arg(y, k, last, &ctx) {
Err(r) => Err(r),
Ok(b) => f(&ctx, &[a, b]),
},
},
_ => {
let mut args = Vec::with_capacity(ops.len());
for x in ops.iter_mut() {
args.push(take_arg(x, k, last, &ctx)?);
}
f(&ctx, &args)
}
}
}
fn choose(&self, args: &[Expr], sel: Sel) -> Lane {
if args.len() < 2 {
return Lane::Same(Ok(Value::Error(ErrorKind::Value)));
}
let index = self.scalars(&args[0], sel);
let (mut out, order, starts) = match self.picked(index, args.len() - 1, sel) {
Picked::All(j) => return self.scalars(&args[j], sel),
Picked::Answer(lane) => return lane,
Picked::Cells(out, order, starts) => (out, order, starts),
};
for j in 1..args.len() {
let (from, to) = (starts[j] as usize, starts[j + 1] as usize);
if from < to {
self.fill_value(&mut out, &args[j], sel, &order[from..to]);
}
}
self.give_positions(order);
self.give_positions(starts);
out
}
#[inline(never)]
fn picked(&self, index: Lane, count: usize, sel: Sel) -> Picked {
if let Lane::Same(got) = &index {
return match got {
Err(r) => Picked::Answer(Lane::Same(Err(r.clone()))),
Ok(v) => match library::chosen(v, count) {
Ok(j) => Picked::All(j),
Err(e) => Picked::Answer(Lane::Same(Ok(Value::Error(e)))),
},
};
}
let n = sel.len();
let mut labels = self.positions();
let mut out = Lane::Numbers(self.take_numbers());
for k in 0..n {
let chose = index.with(k, |g| match g {
Err(r) => Err(Err(r.clone())),
Ok(v) => library::chosen(v, count).map_err(|e| Ok(Value::Error(e))),
});
match chose {
Ok(j) => {
labels.push(j as u32);
self.push(&mut out, Ok(Value::Number(0.0)));
}
Err(answer) => {
labels.push(0);
self.push(&mut out, answer);
}
}
}
self.give_lane(index);
let mut starts = self.positions();
starts.resize(count + 2, 0);
for &j in labels.iter() {
starts[j as usize] += 1;
}
for j in 1..starts.len() {
starts[j] += starts[j - 1];
}
let mut order = self.positions();
order.resize(n, 0);
for k in (0..n).rev() {
let j = labels[k] as usize;
starts[j] -= 1;
order[starts[j] as usize] = k as u32;
}
self.give_positions(labels);
Picked::Cells(out, order, starts)
}
fn fill_value(&self, out: &mut Lane, value: &Expr, sel: Sel, ks: &[u32]) {
let lane = if ks.len() == sel.len() {
self.scalars(value, sel)
} else {
let mut at = self.positions();
at.extend(ks.iter().map(|&k| sel.at(k as usize) as u32));
let lane = self.scalars(value, Sel::Some(&at));
self.give_positions(at);
lane
};
self.place(out, lane, sel, ks);
}
fn negated(&self, lane: Lane, sel: Sel) -> Lane {
match lane {
Lane::Same(got) => Lane::Same(got.map(|v| library::negated(&v))),
Lane::Each(mut each) => {
for v in each.iter_mut().flatten() {
*v = library::negated(v);
}
Lane::Each(each)
}
typed => {
let mut out = Lane::Truths(self.take_truths());
for k in 0..sel.len() {
let got = typed.with(k, |g| g.map(library::negated).map_err(Reason::clone));
self.push(&mut out, got);
}
self.give_lane(typed);
out
}
}
}
#[inline(never)]
fn aggregate<F: Fold>(
&self,
ops: &[Operand<'_>],
kept: &[Option<(usize, &Dense)>],
sel: Sel,
mut out: Lane,
) -> Lane {
for k in 0..sel.len() {
let got = self.fold_at::<F>(ops, kept, sel.at(k), k);
self.push(&mut out, got);
}
out
}
fn fold_at<F: Fold>(
&self,
ops: &[Operand<'_>],
kept: &[Option<(usize, &Dense)>],
pos: usize,
k: usize,
) -> Got {
for x in ops {
if let Operand::Value(lane) = x {
if let Some(r) = lane.with(k, |g| g.err().cloned()) {
return Err(r);
}
}
}
let (d_row, d_col) = self.offset(pos);
let mut fold = F::default();
for (x, kept) in ops.iter().zip(kept) {
let r = match x {
Operand::Value(lane) => {
match lane.with(k, |g| g.ok().map(F::Rule::given)) {
Some(Ok(item)) => fold.add(item),
Some(Err(e)) => return Ok(Value::Error(e)),
None => {}
}
continue;
}
Operand::Ref(r) => r,
};
let area = kept.and_then(|(sheet, array)| {
let (top, left, bottom, right) = r.moved(d_row, d_col)?;
let area = Area {
sheet,
top,
left,
bottom,
right,
};
Some((area, array))
});
let Some((area, array)) = area else {
match F::Rule::given(&Value::Error(ErrorKind::Ref)) {
Ok(item) => fold.add(item),
Err(e) => return Ok(Value::Error(e)),
}
continue;
};
let mut err: Option<ErrorKind> = None;
let walked = array.each_ref::<Infallible, _>(&area, |v| {
match F::Rule::ranged(v) {
Ranged::Counts(item) => fold.add(item),
Ranged::Error(e) => {
err.get_or_insert(e);
}
Ranged::Skipped => {}
}
Ok(())
});
let Ok(()) = walked;
if let Some(e) = err {
return Ok(Value::Error(e));
}
}
Ok(fold.answer())
}
fn drop_operand(&self, x: Operand<'_>) {
if let Operand::Value(lane) = x {
self.give_lane(lane);
}
}
#[inline(never)]
fn apply_one(&self, f: Strict, name: &str, x: &mut Operand<'_>, sel: Sel) -> Lane {
if let Some(lane) = self.known_call(f, name, std::slice::from_mut(x), sel) {
return lane;
}
let (mut out, n) = (Lane::Numbers(self.take_numbers()), sel.len());
for k in 0..n {
let ctx = self.ctx(sel.at(k));
let got = match take_arg(x, k, k + 1 == n, &ctx) {
Ok(a) => f(&ctx, std::slice::from_ref(&a)),
Err(r) => Err(r),
};
self.push(&mut out, got);
}
out
}
#[inline(never)]
fn apply_two<'e>(
&self,
f: Strict,
name: &str,
x: &mut Operand<'e>,
y: &mut Operand<'e>,
sel: Sel,
) -> Lane {
let held = || Operand::Value(Lane::Same(Ok(Value::Empty)));
let mut pair = [std::mem::replace(x, held()), std::mem::replace(y, held())];
let known = self.known_call(f, name, &mut pair, sel);
let [a, b] = pair;
(*x, *y) = (a, b);
if let Some(lane) = known {
return lane;
}
let (mut out, n) = (Lane::Numbers(self.take_numbers()), sel.len());
for k in 0..n {
let ctx = self.ctx(sel.at(k));
let got = match take_arg(x, k, k + 1 == n, &ctx) {
Err(r) => Err(r),
Ok(a) => match take_arg(y, k, k + 1 == n, &ctx) {
Err(r) => Err(r),
Ok(b) => f(&ctx, &[a, b]),
},
};
self.push(&mut out, got);
}
out
}
#[inline(never)]
fn apply_many(&self, f: Strict, name: &str, ops: &mut [Operand<'_>], sel: Sel) -> Lane {
if let Some(lane) = self.known_call(f, name, ops, sel) {
return lane;
}
let (mut out, n) = (Lane::Numbers(self.take_numbers()), sel.len());
let mut args = Vec::with_capacity(ops.len());
for k in 0..n {
let ctx = self.ctx(sel.at(k));
args.clear();
let mut stopped = None;
for x in ops.iter_mut() {
match take_arg(x, k, k + 1 == n, &ctx) {
Ok(a) => args.push(a),
Err(r) => {
stopped = Some(r);
break;
}
}
}
let got = match stopped {
Some(r) => Err(r),
None => f(&ctx, &args),
};
self.push(&mut out, got);
}
out
}
fn if_(&self, args: &[Expr], sel: Sel) -> Lane {
if args.len() < 2 || args.len() > 3 {
return Lane::Same(Ok(Value::Error(ErrorKind::Value)));
}
let conditions = self.scalars(&args[0], sel);
let (mut out, yes, no) = match self.parted(conditions, sel) {
Parted::All(taken) => return self.branch(args, taken, sel),
Parted::Answer(lane) => return lane,
Parted::Cells(out, yes, no) => (out, yes, no),
};
self.fill(&mut out, args, true, sel, &yes);
self.fill(&mut out, args, false, sel, &no);
self.give_positions(yes);
self.give_positions(no);
out
}
#[inline(never)]
fn parted(&self, conditions: Lane, sel: Sel) -> Parted {
let (mut yes, mut no) = match conditions {
Lane::Same(Err(r)) => return Parted::Answer(Lane::Same(Err(r))),
Lane::Same(Ok(v)) => {
return match v.truth() {
Ok(taken) => Parted::All(taken),
Err(k) => Parted::Answer(Lane::Same(Ok(Value::Error(k)))),
}
}
_ => (self.positions(), self.positions()),
};
let out = match conditions {
Lane::Each(mut out) => {
for (k, got) in out.iter_mut().enumerate() {
if let Ok(v) = got {
match v.truth() {
Ok(true) => yes.push(k as u32),
Ok(false) => no.push(k as u32),
Err(kind) => *v = Value::Error(kind),
}
}
}
Lane::Each(out)
}
typed => {
let mut out = Lane::Numbers(self.take_numbers());
for k in 0..sel.len() {
match typed.with(k, |g| g.map(Value::truth).map_err(Reason::clone)) {
Ok(Ok(taken)) => {
if taken { &mut yes } else { &mut no }.push(k as u32);
self.push(&mut out, Ok(Value::Number(0.0)));
}
Ok(Err(kind)) => self.push(&mut out, Ok(Value::Error(kind))),
Err(r) => self.push(&mut out, Err(r)),
}
}
self.give_lane(typed);
out
}
};
Parted::Cells(out, yes, no)
}
fn fill(&self, out: &mut Lane, args: &[Expr], taken: bool, sel: Sel, ks: &[u32]) {
if ks.is_empty() {
return;
}
let lane = if ks.len() == sel.len() {
self.branch(args, taken, sel)
} else {
let mut at = self.positions();
at.extend(ks.iter().map(|&k| sel.at(k as usize) as u32));
let lane = self.branch(args, taken, Sel::Some(&at));
self.give_positions(at);
lane
};
self.place(out, lane, sel, ks);
}
#[inline(never)]
fn place(&self, out: &mut Lane, lane: Lane, sel: Sel, ks: &[u32]) {
if let Lane::Numbers(numbers) = out {
match &lane {
Lane::Same(Ok(Value::Number(n))) => {
for &k in ks {
numbers[k as usize] = *n;
}
return;
}
Lane::Numbers(answers) => {
for (j, &k) in ks.iter().enumerate() {
numbers[k as usize] = answers[j];
}
self.give_lane(lane);
return;
}
_ => {}
}
}
let made = std::mem::replace(out, Lane::Same(Ok(Value::Empty)));
let mut each = match self.values(made) {
Values::Each(each) => each,
Values::Same(got) => {
let mut each = self.take();
each.resize(sel.len(), got);
each
}
};
match lane {
Lane::Same(got) => {
if let Some((&last, rest)) = ks.split_last() {
for &k in rest {
each[k as usize] = got.clone();
}
each[last as usize] = got;
}
}
mut lane => {
for (j, &k) in ks.iter().enumerate() {
each[k as usize] = lane.take_at(j, false);
}
self.give_lane(lane);
}
}
*out = Lane::Each(each);
}
fn branch(&self, args: &[Expr], taken: bool, sel: Sel) -> Lane {
match (taken, args.get(1), args.get(2)) {
(true, Some(Expr::Empty), _) | (false, _, Some(Expr::Empty)) => {
Lane::Same(Ok(Value::Number(0.0)))
}
(true, Some(then), _) => self.scalars(then, sel),
(false, _, Some(otherwise)) => self.scalars(otherwise, sel),
(false, _, None) => Lane::Same(Ok(Value::Bool(false))),
(true, None, _) => Lane::Same(Ok(Value::Error(ErrorKind::Value))),
}
}
#[inline(never)]
fn each_cell(&self, e: &Expr, sel: Sel) -> Lane {
let mut out = self.take();
for k in 0..sel.len() {
out.push(self.ctx(sel.at(k)).scalar(e));
}
Lane::Each(out)
}
}
fn take_arg<'e>(
x: &mut Operand<'e>,
k: usize,
last: bool,
ctx: &Ctx<'_>,
) -> Result<Arg<'e>, Reason> {
match x {
Operand::Ref(r) => ctx.reference(r),
Operand::Value(lane) => lane.take_at(k, last).map(Arg::Scalar),
}
}
fn operand_lane<'l>(read: &'l Option<Lane>, op: &'l Operand<'_>) -> Option<&'l Lane> {
match (read, op) {
(Some(lane), _) => Some(lane),
(None, Operand::Value(lane)) => Some(lane),
(None, Operand::Ref(_)) => None,
}
}
fn number_at(lane: Option<&Lane>, k: usize) -> Option<f64> {
match lane? {
Lane::Numbers(ns) => Some(ns[k]),
Lane::Same(Ok(Value::Number(n))) => Some(*n),
Lane::Each(each) => match &each[k] {
Ok(Value::Number(n)) => Some(*n),
_ => None,
},
Lane::Same(_) | Lane::Truths(_) => None,
}
}