cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

Read ranges through lookup.cells in the aggregates

Dami committed b6ca379
Formulas read other cells through lookup, now a reader with two
methods: cell for one cell and cells for a whole range, row by row.
each, which SUM, AVERAGE, COUNT, MIN, MAX, their decimal twins, the
AND/OR family and the functions collecting numbers or text go through,
reads ranges with cells, so the range is one call to the reader: the
seam where column blocks, prefix sums or cached aggregates can serve it
later. The sheet name is resolved once per range. lookup is a concrete
type so the callback stays on the stack; fan-in and running-total
recalculation times and allocations are unchanged (within 1%).
commit
b6ca379d9bc67600481c1928f3dce24e80dc9f67
parent
6b40936f4c473559e9214ad4892c0ba134cd37c4
author
Dami <dami.etoile@gmail.com>
6 files changed, +70 -35
Minternal/sheet/args.go2+-
Minternal/sheet/eval.go14++++---
Minternal/sheet/explain.go4+-
Minternal/sheet/functions.go15++++---
Minternal/sheet/functions_jev.go4+-
Minternal/sheet/recalc.go66++++++++++++++++++++++--------
M internal/sheet/args.go +1 -1
M internal/sheet/eval.go +8 -6
M internal/sheet/explain.go +2 -2
M internal/sheet/functions.go +8 -7
M internal/sheet/functions_jev.go +2 -2
M internal/sheet/recalc.go +49 -17
@@ -229,24 +229,56 @@ func (w *Workbook) crossReads(u, l loc) bool {
229229 return false230230 }231231 232-// lookupOn resolves references in a formula on s with get: references233-// without a sheet read s, others the sheet they name (#REF! when no sheet234-// has that name). The last sheet name is remembered, so a range on235-// another sheet resolves its name once.236-func (w *Workbook) lookupOn(s *Sheet, get func(*Sheet, Addr) Value) lookup {237- var lastName string238- var last *Sheet239- return func(sheet string, a Addr) Value {240- if sheet == "" {241- return get(s, a)242- }243- if sheet != lastName || last == nil {244- lastName, last = sheet, w.byKey[formula.SheetKey(sheet)]245- }246- if last == nil {247- return ErrRef232+// reader resolves the references of formulas on s with read: references233+// without a sheet ("") read s, others the sheet they name, with cells on234+// a sheet no sheet has the name of reading as #REF!. The last sheet name235+// is remembered, so a range on another sheet resolves its name once.236+type reader struct {237+ w *Workbook238+ s *Sheet239+ read func(*Sheet, Addr) Value240+ lastName string241+ last *Sheet242+}243+244+func (w *Workbook) lookupOn(s *Sheet, read func(*Sheet, Addr) Value) lookup {245+ return &reader{w: w, s: s, read: read}246+}247+248+// sheet is the sheet a reference written with the name sheet points at.249+func (rd *reader) sheet(sheet string) *Sheet {250+ if sheet == "" {251+ return rd.s252+ }253+ if sheet != rd.lastName || rd.last == nil {254+ rd.lastName, rd.last = sheet, rd.w.byKey[formula.SheetKey(sheet)]255+ }256+ return rd.last257+}258+259+// cell returns the current value of a cell.260+func (rd *reader) cell(sheet string, a Addr) Value {261+ t := rd.sheet(sheet)262+ if t == nil {263+ return ErrRef264+ }265+ return rd.read(t, a)266+}267+268+// cells calls fn with the value of every cell of r, row by row, until fn269+// returns false.270+func (rd *reader) cells(sheet string, r Rect, fn func(Value) bool) {271+ t := rd.sheet(sheet)272+ for row := r.From.Row; row <= r.To.Row; row++ {273+ for col := r.From.Col; col <= r.To.Col; col++ {274+ v := ErrRef275+ if t != nil {276+ v = rd.read(t, Addr{Col: col, Row: row})277+ }278+ if !fn(v) {279+ return280+ }248281 }249- return get(last, a)250282 }251283 }252284