@odoo/o-spreadsheet 17.2.0-alpha.8 → 17.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.0-alpha.8
7
- * @date 2024-03-15T11:01:01.388Z
8
- * @hash 11cf381
6
+ * @version 17.3.0-alpha.0
7
+ * @date 2024-03-20T13:42:32.042Z
8
+ * @hash 073e154
9
9
  */
10
10
 
11
11
  (function (exports, owl) {
@@ -641,21 +641,6 @@
641
641
  }
642
642
  return true;
643
643
  }
644
- class JetSet extends Set {
645
- addMany(iterable) {
646
- for (const element of iterable) {
647
- super.add(element);
648
- }
649
- return this;
650
- }
651
- deleteMany(iterable) {
652
- let wasDeleted = false;
653
- for (const element of iterable) {
654
- wasDeleted ||= super.delete(element);
655
- }
656
- return wasDeleted;
657
- }
658
- }
659
644
  /**
660
645
  * Creates a version of the function that's memoized on the value of its first
661
646
  * argument, if any.
@@ -4101,14 +4086,6 @@
4101
4086
  }
4102
4087
  return positions;
4103
4088
  }
4104
- function forEachPositionsInZone(zone, callback) {
4105
- const { left, right, top, bottom } = zone;
4106
- for (let col = left; col <= right; col++) {
4107
- for (let row = top; row <= bottom; row++) {
4108
- callback(col, row);
4109
- }
4110
- }
4111
- }
4112
4089
  /**
4113
4090
  * This function returns a zone with coordinates modified according to the change
4114
4091
  * applied to the zone. It may be possible to change the zone by resizing or moving
@@ -10054,6 +10031,9 @@ stores.inject(MyMetaStore, storeInstance);
10054
10031
  result.default = true;
10055
10032
  result.defaultValue = defaultValue;
10056
10033
  }
10034
+ if (types.some((t) => t.startsWith("RANGE"))) {
10035
+ result.acceptMatrix = true;
10036
+ }
10057
10037
  return result;
10058
10038
  }
10059
10039
  /**
@@ -18624,11 +18604,27 @@ stores.inject(MyMetaStore, storeInstance);
18624
18604
  }
18625
18605
  const descr = addMetaInfoFromArg(addDescr);
18626
18606
  validateArguments(descr.args);
18627
- this.mapping[name] = addErrorHandling(addResultHandling(descr.compute), name);
18607
+ this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr)), name);
18628
18608
  super.add(name, descr);
18629
18609
  return this;
18630
18610
  }
18631
18611
  }
18612
+ function addInputHandling(descr) {
18613
+ function computeWithInputHandling(...args) {
18614
+ for (let i = 0; i < args.length; i++) {
18615
+ const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
18616
+ const arg = args[i];
18617
+ if (isMatrix(arg) && !argDefinition.acceptMatrix) {
18618
+ if (arg.length !== 1 || arg[0].length !== 1) {
18619
+ throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be a single value or a single cell reference, not a range.", argDefinition.name));
18620
+ }
18621
+ args[i] = arg[0][0];
18622
+ }
18623
+ }
18624
+ return descr.compute.apply(this, args);
18625
+ }
18626
+ return computeWithInputHandling;
18627
+ }
18632
18628
  function addErrorHandling(compute, functionName) {
18633
18629
  return function (...args) {
18634
18630
  try {
@@ -45850,6 +45846,41 @@ stores.inject(MyMetaStore, storeInstance);
45850
45846
  }
45851
45847
  }
45852
45848
 
45849
+ class PositionMap {
45850
+ map = {};
45851
+ set({ sheetId, col, row }, value) {
45852
+ const map = this.map;
45853
+ if (!map[sheetId]) {
45854
+ map[sheetId] = {};
45855
+ }
45856
+ if (!map[sheetId][col]) {
45857
+ map[sheetId][col] = {};
45858
+ }
45859
+ map[sheetId][col][row] = value;
45860
+ }
45861
+ get({ sheetId, col, row }) {
45862
+ return this.map[sheetId]?.[col]?.[row];
45863
+ }
45864
+ has({ sheetId, col, row }) {
45865
+ return this.map[sheetId]?.[col]?.[row] !== undefined;
45866
+ }
45867
+ delete({ sheetId, col, row }) {
45868
+ delete this.map[sheetId]?.[col]?.[row];
45869
+ }
45870
+ keys() {
45871
+ const map = this.map;
45872
+ const keys = [];
45873
+ for (const sheetId in map) {
45874
+ for (const col in map[sheetId]) {
45875
+ for (const row in map[sheetId][col]) {
45876
+ keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
45877
+ }
45878
+ }
45879
+ }
45880
+ return keys;
45881
+ }
45882
+ }
45883
+
45853
45884
  function quickselect(arr, k, left, right, compare) {
45854
45885
  quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare);
45855
45886
  }
@@ -46576,26 +46607,26 @@ stores.inject(MyMetaStore, storeInstance);
46576
46607
  * It uses an R-Tree data structure to efficiently find dependent cells.
46577
46608
  */
46578
46609
  class FormulaDependencyGraph {
46579
- encoder;
46580
- dependencies = new Map();
46610
+ createEmptyPositionSet;
46611
+ dependencies = new PositionMap();
46581
46612
  rTree;
46582
- constructor(encoder, data = []) {
46583
- this.encoder = encoder;
46613
+ constructor(createEmptyPositionSet, data = []) {
46614
+ this.createEmptyPositionSet = createEmptyPositionSet;
46584
46615
  this.rTree = new SpreadsheetRTree(data);
46585
46616
  }
46586
- removeAllDependencies(formulaPositionId) {
46587
- const ranges = this.dependencies.get(formulaPositionId);
46617
+ removeAllDependencies(formulaPosition) {
46618
+ const ranges = this.dependencies.get(formulaPosition);
46588
46619
  if (!ranges) {
46589
46620
  return;
46590
46621
  }
46591
46622
  for (const range of ranges) {
46592
46623
  this.rTree.remove(range);
46593
46624
  }
46594
- this.dependencies.delete(formulaPositionId);
46625
+ this.dependencies.delete(formulaPosition);
46595
46626
  }
46596
- addDependencies(formulaPositionId, dependencies) {
46627
+ addDependencies(formulaPosition, dependencies) {
46597
46628
  const rTreeItems = dependencies.map(({ sheetId, zone }) => ({
46598
- data: formulaPositionId,
46629
+ data: formulaPosition,
46599
46630
  boundingBox: {
46600
46631
  zone,
46601
46632
  sheetId,
@@ -46604,12 +46635,12 @@ stores.inject(MyMetaStore, storeInstance);
46604
46635
  for (const item of rTreeItems) {
46605
46636
  this.rTree.insert(item);
46606
46637
  }
46607
- const existingDependencies = this.dependencies.get(formulaPositionId);
46638
+ const existingDependencies = this.dependencies.get(formulaPosition);
46608
46639
  if (existingDependencies) {
46609
46640
  existingDependencies.push(...rTreeItems);
46610
46641
  }
46611
46642
  else {
46612
- this.dependencies.set(formulaPositionId, rTreeItems);
46643
+ this.dependencies.set(formulaPosition, rTreeItems);
46613
46644
  }
46614
46645
  }
46615
46646
  /**
@@ -46618,23 +46649,194 @@ stores.inject(MyMetaStore, storeInstance);
46618
46649
  * This is called a topological ordering (excluding cycles)
46619
46650
  */
46620
46651
  getCellsDependingOn(ranges) {
46621
- const visited = new JetSet();
46652
+ const visited = this.createEmptyPositionSet();
46622
46653
  const queue = Array.from(ranges).reverse();
46623
46654
  while (queue.length > 0) {
46624
46655
  const range = queue.pop();
46625
- visited.addMany(this.encoder.encodeBoundingBox(range));
46626
- const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
46627
- for (const positionId of impactedPositionIds) {
46628
- if (!visited.has(positionId)) {
46629
- queue.push(this.encoder.decodeToBoundingBox(positionId));
46656
+ visited.addMany(positions(range.zone).map((position) => ({ sheetId: range.sheetId, ...position })));
46657
+ const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
46658
+ for (const position of impactedPositions) {
46659
+ if (!visited.has(position)) {
46660
+ queue.push({ sheetId: position.sheetId, zone: positionToZone(position) });
46630
46661
  }
46631
46662
  }
46632
46663
  }
46633
- visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
46664
+ visited.deleteMany(ranges.flatMap((r) => positions(r.zone).map((position) => ({ sheetId: r.sheetId, ...position }))));
46634
46665
  return visited;
46635
46666
  }
46636
46667
  }
46637
46668
 
46669
+ /**
46670
+ * Implements a fixed-sized grid or 2D matrix of bits.
46671
+ * based on https://github.com/zandaqo/structurae
46672
+ *
46673
+ * The grid is implemented as a 1D array of 32-bit integers, where each bit represents a cell in the grid.
46674
+ * It follows row-major order, with each row stored consecutively in 32-bit blocks.
46675
+ * Pads the number of columns to the next power of 2 to allow quick lookups with bitwise operations.
46676
+ *
46677
+ * Key terminology:
46678
+ * - bucket: Index of an item in the Uint32Array, a 32-bit integer.
46679
+ * - bitPosition: The position of a bit within the bucket 32-bit integer.
46680
+ */
46681
+ class BinaryGrid extends Uint32Array {
46682
+ columnOffset = 0;
46683
+ cols = 0;
46684
+ rows = 0;
46685
+ /**
46686
+ * Creates a binary grid of specified dimensions.
46687
+ */
46688
+ static create(rows, columns) {
46689
+ const columnOffset = log2Ceil(columns);
46690
+ const length = (rows << columnOffset) >> 5;
46691
+ const grid = new this(length + 1);
46692
+ grid.columnOffset = columnOffset;
46693
+ grid.cols = columns;
46694
+ grid.rows = rows;
46695
+ return grid;
46696
+ }
46697
+ /**
46698
+ * Returns the bit at given coordinates.
46699
+ */
46700
+ getValue(position) {
46701
+ const [bucket, bitPosition] = this.getCoordinates(position);
46702
+ return ((this[bucket] >> bitPosition) & 1);
46703
+ }
46704
+ /**
46705
+ * Sets the bit at given coordinates.
46706
+ */
46707
+ setValue(position, value) {
46708
+ const [bucket, bitPosition] = this.getCoordinates(position);
46709
+ const currentValue = (this[bucket] >> bitPosition) & 1;
46710
+ const hasBeenInserted = currentValue === 0 && value === 1;
46711
+ this[bucket] = (this[bucket] & ~(1 << bitPosition)) | (value << bitPosition);
46712
+ return hasBeenInserted;
46713
+ // Let's breakdown of the above line:
46714
+ // with an example with a 4-bit integer (instead of 32-bit).
46715
+ //
46716
+ // Let's say we want to set the bit at position 2 to 1 and the existing
46717
+ // bit sequence this[bucket] is 1001. The final bit sequence should be 1101.
46718
+ //
46719
+ // First, we clear the bit at position 2 by AND-ing this[bucket] with a
46720
+ // mask having all 1s except a 0 at the bit position (~ (1 << bitPosition)).
46721
+ // 1 << bitPosition is 0100 (shifting 0001 to the left by 2)
46722
+ // Inverting the bits with ~ gives the final mask ~(1 << bitPosition): 1011
46723
+ //
46724
+ // Then, we shift the value by the bit position (value << bitPosition: 0100)
46725
+ // and OR the result with the previous step's result:
46726
+ // (1001 & 1011) | 0100 = 1101
46727
+ }
46728
+ isEmpty() {
46729
+ return !this.some((bucket) => bucket !== 0);
46730
+ }
46731
+ fillAllPositions() {
46732
+ const thirtyTwoOnes = -1 >>> 0; // same as 2 ** 32 - 1, a 32-bit number with all bits set to 1
46733
+ this.fill(thirtyTwoOnes);
46734
+ }
46735
+ clear() {
46736
+ this.fill(0);
46737
+ }
46738
+ getCoordinates(position) {
46739
+ const { row, col } = position;
46740
+ const index = (row << this.columnOffset) + col;
46741
+ const bucket = index >> 5;
46742
+ return [bucket, index - (bucket << 5)];
46743
+ }
46744
+ }
46745
+ function log2Ceil(value) {
46746
+ // A faster version of Math.ceil(Math.log2(value)).
46747
+ if (value === 0) {
46748
+ return -Infinity;
46749
+ }
46750
+ else if (value < 0) {
46751
+ return NaN;
46752
+ }
46753
+ // --value handles the case where value is a power of 2
46754
+ return 32 - Math.clz32(--value);
46755
+ }
46756
+
46757
+ class PositionSet {
46758
+ sheets = {};
46759
+ /**
46760
+ * List of positions in the order they were inserted.
46761
+ */
46762
+ insertions = [];
46763
+ maxSize = 0;
46764
+ constructor(sheetSizes) {
46765
+ for (const sheetId in sheetSizes) {
46766
+ const cols = sheetSizes[sheetId].cols;
46767
+ const rows = sheetSizes[sheetId].rows;
46768
+ this.maxSize += cols * rows;
46769
+ this.sheets[sheetId] = BinaryGrid.create(rows, cols);
46770
+ }
46771
+ }
46772
+ add(position) {
46773
+ const hasBeenInserted = this.sheets[position.sheetId].setValue(position, 1);
46774
+ if (hasBeenInserted) {
46775
+ this.insertions.push(position);
46776
+ }
46777
+ }
46778
+ addMany(positions) {
46779
+ for (const position of positions) {
46780
+ this.add(position);
46781
+ }
46782
+ }
46783
+ delete(position) {
46784
+ this.sheets[position.sheetId].setValue(position, 0);
46785
+ }
46786
+ deleteMany(positions) {
46787
+ for (const position of positions) {
46788
+ this.delete(position);
46789
+ }
46790
+ }
46791
+ has(position) {
46792
+ return this.sheets[position.sheetId].getValue(position) === 1;
46793
+ }
46794
+ clear() {
46795
+ const insertions = this.insertions;
46796
+ this.insertions = [];
46797
+ for (const sheetId in this.sheets) {
46798
+ this.sheets[sheetId].clear();
46799
+ }
46800
+ return insertions;
46801
+ }
46802
+ isEmpty() {
46803
+ if (this.insertions.length === 0) {
46804
+ return true;
46805
+ }
46806
+ for (const sheetId in this.sheets) {
46807
+ if (!this.sheets[sheetId].isEmpty()) {
46808
+ return false;
46809
+ }
46810
+ }
46811
+ return true;
46812
+ }
46813
+ fillAllPositions() {
46814
+ this.insertions = new Array(this.maxSize);
46815
+ let index = 0;
46816
+ for (const sheetId in this.sheets) {
46817
+ const grid = this.sheets[sheetId];
46818
+ grid.fillAllPositions();
46819
+ for (let i = 0; i < grid.rows; i++) {
46820
+ for (let j = 0; j < grid.cols; j++) {
46821
+ this.insertions[index++] = { sheetId, row: i, col: j };
46822
+ }
46823
+ }
46824
+ }
46825
+ }
46826
+ /**
46827
+ * Iterate over the positions in the order of insertion.
46828
+ * Note that the same position may be yielded multiple times if the value was added
46829
+ * to the set then removed and then added again.
46830
+ */
46831
+ *[Symbol.iterator]() {
46832
+ for (const position of this.insertions) {
46833
+ if (this.sheets[position.sheetId].getValue(position) === 1) {
46834
+ yield position;
46835
+ }
46836
+ }
46837
+ }
46838
+ }
46839
+
46638
46840
  /**
46639
46841
  * Contains, for each cell, the array
46640
46842
  * formulas that could potentially spread on it
@@ -46648,6 +46850,7 @@ stores.inject(MyMetaStore, storeInstance);
46648
46850
  *
46649
46851
  */
46650
46852
  class SpreadingRelation {
46853
+ createEmptyPositionSet;
46651
46854
  /**
46652
46855
  * Internal structure:
46653
46856
  * For something like
@@ -46676,39 +46879,42 @@ stores.inject(MyMetaStore, storeInstance);
46676
46879
  * - (B1) --> (B2, B3, B4) meaning B1 spreads on B2, B3 and B4
46677
46880
  *
46678
46881
  */
46679
- resultsToArrayFormulas = new Map();
46680
- arrayFormulasToResults = new Map();
46681
- getFormulaPositionsSpreadingOn(resultPositionId) {
46682
- return this.resultsToArrayFormulas.get(resultPositionId) || EMPTY_ARRAY;
46882
+ resultsToArrayFormulas = new PositionMap();
46883
+ arrayFormulasToResults = new PositionMap();
46884
+ constructor(createEmptyPositionSet) {
46885
+ this.createEmptyPositionSet = createEmptyPositionSet;
46886
+ }
46887
+ getFormulaPositionsSpreadingOn(resultPosition) {
46888
+ return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
46683
46889
  }
46684
- getArrayResultPositionIds(formulasPositionId) {
46685
- return this.arrayFormulasToResults.get(formulasPositionId) || EMPTY_ARRAY;
46890
+ getArrayResultPositions(formulasPosition) {
46891
+ return this.arrayFormulasToResults.get(formulasPosition) || EMPTY_ARRAY;
46686
46892
  }
46687
46893
  /**
46688
46894
  * Remove a node, also remove it from other nodes adjacency list
46689
46895
  */
46690
- removeNode(positionId) {
46691
- this.resultsToArrayFormulas.delete(positionId);
46692
- this.arrayFormulasToResults.delete(positionId);
46896
+ removeNode(position) {
46897
+ this.resultsToArrayFormulas.delete(position);
46898
+ this.arrayFormulasToResults.delete(position);
46693
46899
  }
46694
46900
  /**
46695
46901
  * Create a spreading relation between two cells
46696
46902
  */
46697
- addRelation({ arrayFormulaPositionId, resultPositionId, }) {
46698
- if (!this.resultsToArrayFormulas.has(resultPositionId)) {
46699
- this.resultsToArrayFormulas.set(resultPositionId, new Set());
46903
+ addRelation({ arrayFormulaPosition, resultPosition, }) {
46904
+ if (!this.resultsToArrayFormulas.has(resultPosition)) {
46905
+ this.resultsToArrayFormulas.set(resultPosition, this.createEmptyPositionSet());
46700
46906
  }
46701
- this.resultsToArrayFormulas.get(resultPositionId)?.add(arrayFormulaPositionId);
46702
- if (!this.arrayFormulasToResults.has(arrayFormulaPositionId)) {
46703
- this.arrayFormulasToResults.set(arrayFormulaPositionId, new Set());
46907
+ this.resultsToArrayFormulas.get(resultPosition)?.add(arrayFormulaPosition);
46908
+ if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
46909
+ this.arrayFormulasToResults.set(arrayFormulaPosition, this.createEmptyPositionSet());
46704
46910
  }
46705
- this.arrayFormulasToResults.get(arrayFormulaPositionId)?.add(resultPositionId);
46911
+ this.arrayFormulasToResults.get(arrayFormulaPosition)?.add(resultPosition);
46706
46912
  }
46707
- hasArrayFormulaResult(positionId) {
46708
- return this.resultsToArrayFormulas.has(positionId);
46913
+ hasArrayFormulaResult(position) {
46914
+ return this.resultsToArrayFormulas.has(position);
46709
46915
  }
46710
- isArrayFormula(positionId) {
46711
- return this.arrayFormulasToResults.has(positionId);
46916
+ isArrayFormula(position) {
46917
+ return this.arrayFormulasToResults.has(position);
46712
46918
  }
46713
46919
  }
46714
46920
  const EMPTY_ARRAY = [];
@@ -46720,50 +46926,41 @@ stores.inject(MyMetaStore, storeInstance);
46720
46926
  context;
46721
46927
  getters;
46722
46928
  compilationParams;
46723
- encoder = new PositionBitsEncoder();
46724
- evaluatedCells = new Map();
46725
- formulaDependencies = lazy(new FormulaDependencyGraph(this.encoder));
46726
- blockedArrayFormulas = new Set();
46727
- spreadingRelations = new SpreadingRelation();
46929
+ evaluatedCells = new PositionMap();
46930
+ formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
46931
+ blockedArrayFormulas = new PositionSet({});
46932
+ spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
46728
46933
  constructor(context, getters) {
46729
46934
  this.context = context;
46730
46935
  this.getters = getters;
46731
46936
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
46732
46937
  }
46733
46938
  getEvaluatedCell(position) {
46734
- return this.evaluatedCells.get(this.encoder.encode(position)) || EMPTY_CELL;
46939
+ return this.evaluatedCells.get(position) || EMPTY_CELL;
46735
46940
  }
46736
46941
  getSpreadPositionsOf(position) {
46737
- const positionId = this.encoder.encode(position);
46738
- if (!this.spreadingRelations.isArrayFormula(positionId)) {
46942
+ if (!this.spreadingRelations.isArrayFormula(position)) {
46739
46943
  return [];
46740
46944
  }
46741
- return Array.from(this.spreadingRelations.getArrayResultPositionIds(positionId)).map((positionId) => this.encoder.decode(positionId));
46742
- }
46743
- getArrayFormulaSpreadingOn(position) {
46744
- const positionId = this.encoder.encode(position);
46745
- const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
46746
- return formulaPosition !== undefined ? this.encoder.decode(formulaPosition) : undefined;
46945
+ return Array.from(this.spreadingRelations.getArrayResultPositions(position));
46747
46946
  }
46748
46947
  getEvaluatedPositions() {
46749
- return [...this.evaluatedCells.keys()].map((p) => this.encoder.decode(p));
46948
+ return this.evaluatedCells.keys();
46750
46949
  }
46751
- getArrayFormulaSpreadingOnId(positionId) {
46752
- if (!this.spreadingRelations.hasArrayFormulaResult(positionId)) {
46950
+ getArrayFormulaSpreadingOn(position) {
46951
+ if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
46753
46952
  return undefined;
46754
46953
  }
46755
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
46756
- return Array.from(arrayFormulas).find((positionId) => !this.blockedArrayFormulas.has(positionId));
46954
+ const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
46955
+ return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
46757
46956
  }
46758
46957
  updateDependencies(position) {
46759
- const positionId = this.encoder.encode(position);
46760
- this.formulaDependencies().removeAllDependencies(positionId);
46761
- const dependencies = this.getDirectDependencies(positionId);
46762
- this.formulaDependencies().addDependencies(positionId, dependencies);
46958
+ this.formulaDependencies().removeAllDependencies(position);
46959
+ const dependencies = this.getDirectDependencies(position);
46960
+ this.formulaDependencies().addDependencies(position, dependencies);
46763
46961
  }
46764
46962
  addDependencies(position, dependencies) {
46765
- const positionId = this.encoder.encode(position);
46766
- this.formulaDependencies().addDependencies(positionId, dependencies);
46963
+ this.formulaDependencies().addDependencies(position, dependencies);
46767
46964
  }
46768
46965
  updateCompilationParameters() {
46769
46966
  // rebuild the compilation parameters (with a clean cache)
@@ -46771,47 +46968,57 @@ stores.inject(MyMetaStore, storeInstance);
46771
46968
  this.compilationParams.evalContext.updateDependencies = this.updateDependencies.bind(this);
46772
46969
  this.compilationParams.evalContext.addDependencies = this.addDependencies.bind(this);
46773
46970
  }
46971
+ createEmptyPositionSet() {
46972
+ const sheetSizes = {};
46973
+ for (const sheetId of this.getters.getSheetIds()) {
46974
+ sheetSizes[sheetId] = {
46975
+ rows: this.getters.getNumberRows(sheetId),
46976
+ cols: this.getters.getNumberCols(sheetId),
46977
+ };
46978
+ }
46979
+ return new PositionSet(sheetSizes);
46980
+ }
46774
46981
  evaluateCells(positions) {
46775
- const cells = positions.map((p) => this.encoder.encode(p));
46776
- const cellsToCompute = new JetSet(cells);
46777
- const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
46778
- cellsToCompute.addMany(this.getCellsDependingOn(cells));
46779
- cellsToCompute.addMany(arrayFormulasPositionIds);
46780
- cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
46982
+ const cellsToCompute = this.createEmptyPositionSet();
46983
+ cellsToCompute.addMany(positions);
46984
+ const arrayFormulasPositions = this.getArrayFormulasImpactedByChangesOf(positions);
46985
+ cellsToCompute.addMany(this.getCellsDependingOn(positions));
46986
+ cellsToCompute.addMany(arrayFormulasPositions);
46987
+ cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositions));
46781
46988
  this.evaluate(cellsToCompute);
46782
46989
  }
46783
- getArrayFormulasImpactedByChangesOf(positionIds) {
46784
- const impactedPositionIds = new JetSet();
46785
- for (const positionId of positionIds) {
46786
- const content = this.getCell(positionId)?.content;
46787
- const arrayFormulaPositionId = this.getArrayFormulaSpreadingOnId(positionId);
46788
- if (arrayFormulaPositionId !== undefined) {
46990
+ getArrayFormulasImpactedByChangesOf(positions) {
46991
+ const impactedPositions = this.createEmptyPositionSet();
46992
+ for (const position of positions) {
46993
+ const content = this.getters.getCell(position)?.content;
46994
+ const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
46995
+ if (arrayFormulaPosition !== undefined) {
46789
46996
  // take into account new collisions.
46790
- impactedPositionIds.add(arrayFormulaPositionId);
46997
+ impactedPositions.add(arrayFormulaPosition);
46791
46998
  }
46792
46999
  if (!content) {
46793
47000
  // The previous content could have blocked some array formulas
46794
- impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
47001
+ impactedPositions.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(position));
46795
47002
  }
46796
47003
  }
46797
- return impactedPositionIds;
47004
+ return impactedPositions;
46798
47005
  }
46799
47006
  buildDependencyGraph() {
46800
- this.blockedArrayFormulas = new Set();
46801
- this.spreadingRelations = new SpreadingRelation();
47007
+ this.blockedArrayFormulas = this.createEmptyPositionSet();
47008
+ this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
46802
47009
  this.formulaDependencies = lazy(() => {
46803
- const dependencies = [...this.getAllCells()].flatMap((positionId) => this.getDirectDependencies(positionId).map((range) => ({
46804
- data: positionId,
47010
+ const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position).map((range) => ({
47011
+ data: position,
46805
47012
  boundingBox: {
46806
47013
  zone: range.zone,
46807
47014
  sheetId: range.sheetId,
46808
47015
  },
46809
47016
  })));
46810
- return new FormulaDependencyGraph(this.encoder, dependencies);
47017
+ return new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this), dependencies);
46811
47018
  });
46812
47019
  }
46813
47020
  evaluateAllCells() {
46814
- this.evaluatedCells = new Map();
47021
+ this.evaluatedCells = new PositionMap();
46815
47022
  this.evaluate(this.getAllCells());
46816
47023
  }
46817
47024
  evaluateFormula(sheetId, formulaString) {
@@ -46828,57 +47035,50 @@ stores.inject(MyMetaStore, storeInstance);
46828
47035
  return result.value;
46829
47036
  }
46830
47037
  getAllCells() {
46831
- const positionIds = new JetSet();
46832
- for (const sheetId of this.getters.getSheetIds()) {
46833
- const cellIds = this.getters.getCells(sheetId);
46834
- for (const cellId in cellIds) {
46835
- positionIds.add(this.encoder.encode(this.getters.getCellPosition(cellId)));
46836
- }
46837
- }
46838
- return positionIds;
47038
+ const positions = this.createEmptyPositionSet();
47039
+ positions.fillAllPositions();
47040
+ return positions;
46839
47041
  }
46840
- getArrayFormulasBlockedByOrSpreadingOn(positionId) {
46841
- if (!this.spreadingRelations.hasArrayFormulaResult(positionId)) {
47042
+ getArrayFormulasBlockedByOrSpreadingOn(position) {
47043
+ if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
46842
47044
  return [];
46843
47045
  }
46844
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
46845
- const cells = new JetSet(arrayFormulas);
46846
- cells.addMany(this.getCellsDependingOn(arrayFormulas));
46847
- return cells;
47046
+ const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
47047
+ const positions = this.createEmptyPositionSet();
47048
+ positions.addMany(arrayFormulas);
47049
+ positions.addMany(this.getCellsDependingOn(arrayFormulas));
47050
+ return positions;
46848
47051
  }
46849
- nextPositionsToUpdate = new JetSet();
47052
+ nextPositionsToUpdate = new PositionSet({});
46850
47053
  cellsBeingComputed = new Set();
46851
- evaluate(cells) {
47054
+ evaluate(positions) {
46852
47055
  this.cellsBeingComputed = new Set();
46853
- this.nextPositionsToUpdate = cells;
47056
+ this.nextPositionsToUpdate = positions;
46854
47057
  let currentIteration = 0;
46855
- while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
47058
+ while (!this.nextPositionsToUpdate.isEmpty() && currentIteration++ < MAX_ITERATION) {
46856
47059
  this.updateCompilationParameters();
46857
- const positionIds = Array.from(this.nextPositionsToUpdate);
46858
- this.nextPositionsToUpdate.clear();
46859
- for (let i = 0; i < positionIds.length; ++i) {
46860
- const cell = positionIds[i];
46861
- this.evaluatedCells.delete(cell);
47060
+ const positions = this.nextPositionsToUpdate.clear();
47061
+ for (let i = 0; i < positions.length; ++i) {
47062
+ this.evaluatedCells.delete(positions[i]);
46862
47063
  }
46863
- for (let i = 0; i < positionIds.length; ++i) {
46864
- const cell = positionIds[i];
46865
- this.setEvaluatedCell(cell, this.computeCell(cell));
47064
+ for (let i = 0; i < positions.length; ++i) {
47065
+ const position = positions[i];
47066
+ const evaluatedCell = this.computeCell(position);
47067
+ if (evaluatedCell !== EMPTY_CELL) {
47068
+ this.evaluatedCells.set(position, evaluatedCell);
47069
+ }
46866
47070
  }
46867
47071
  }
46868
47072
  }
46869
- setEvaluatedCell(positionId, evaluatedCell) {
46870
- this.evaluatedCells.set(positionId, evaluatedCell);
46871
- }
46872
- computeCell(positionId) {
46873
- const evaluation = this.evaluatedCells.get(positionId);
47073
+ computeCell(position) {
47074
+ const evaluation = this.evaluatedCells.get(position);
46874
47075
  if (evaluation) {
46875
47076
  return evaluation; // already computed
46876
47077
  }
46877
- if (!this.blockedArrayFormulas.has(positionId)) {
46878
- this.invalidateSpreading(positionId);
47078
+ if (!this.blockedArrayFormulas.has(position)) {
47079
+ this.invalidateSpreading(position);
46879
47080
  }
46880
- const cellPosition = this.encoder.decode(positionId);
46881
- const cell = this.getters.getCell(cellPosition);
47081
+ const cell = this.getters.getCell(position);
46882
47082
  if (cell === undefined) {
46883
47083
  return EMPTY_CELL;
46884
47084
  }
@@ -46890,7 +47090,7 @@ stores.inject(MyMetaStore, storeInstance);
46890
47090
  }
46891
47091
  this.cellsBeingComputed.add(cellId);
46892
47092
  return cell.isFormula
46893
- ? this.computeFormulaCell(cellPosition.sheetId, cell)
47093
+ ? this.computeFormulaCell(position.sheetId, cell)
46894
47094
  : evaluateLiteral(cell.content, localeFormat);
46895
47095
  }
46896
47096
  catch (e) {
@@ -46903,10 +47103,9 @@ stores.inject(MyMetaStore, storeInstance);
46903
47103
  }
46904
47104
  }
46905
47105
  computeAndSave(position) {
46906
- const positionId = this.encoder.encode(position);
46907
- const evaluatedCell = this.computeCell(positionId);
46908
- if (!this.evaluatedCells.has(positionId)) {
46909
- this.setEvaluatedCell(positionId, evaluatedCell);
47106
+ const evaluatedCell = this.computeCell(position);
47107
+ if (!this.evaluatedCells.has(position)) {
47108
+ this.evaluatedCells.set(position, evaluatedCell);
46910
47109
  }
46911
47110
  return evaluatedCell;
46912
47111
  }
@@ -46944,24 +47143,23 @@ stores.inject(MyMetaStore, storeInstance);
46944
47143
  throw new EvaluationError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
46945
47144
  }
46946
47145
  updateSpreadRelation({ sheetId, col, row, }) {
46947
- const arrayFormulaPositionId = this.encoder.encode({ sheetId, col, row });
47146
+ const arrayFormulaPosition = { sheetId, col, row };
46948
47147
  return (i, j) => {
46949
47148
  const position = { sheetId, col: i + col, row: j + row };
46950
- const resultPositionId = this.encoder.encode(position);
46951
- this.spreadingRelations.addRelation({ resultPositionId, arrayFormulaPositionId });
47149
+ this.spreadingRelations.addRelation({ resultPosition: position, arrayFormulaPosition });
46952
47150
  };
46953
47151
  }
46954
- checkCollision({ sheetId, col, row }) {
46955
- const formulaPositionId = this.encoder.encode({ sheetId, col, row });
47152
+ checkCollision(formulaPosition) {
47153
+ const { sheetId, col, row } = formulaPosition;
46956
47154
  return (i, j) => {
46957
47155
  const position = { sheetId: sheetId, col: i + col, row: j + row };
46958
47156
  const rawCell = this.getters.getCell(position);
46959
47157
  if (rawCell?.content ||
46960
47158
  this.getters.getEvaluatedCell(position).type !== CellValueType.empty) {
46961
- this.blockedArrayFormulas.add(formulaPositionId);
47159
+ this.blockedArrayFormulas.add(formulaPosition);
46962
47160
  throw new EvaluationError(_t("Array result was not expanded because it would overwrite data in %s.", toXC(position.col, position.row)));
46963
47161
  }
46964
- this.blockedArrayFormulas.delete(formulaPositionId);
47162
+ this.blockedArrayFormulas.delete(formulaPosition);
46965
47163
  };
46966
47164
  }
46967
47165
  spreadValues({ sheetId, col, row }, matrixResult) {
@@ -46969,19 +47167,18 @@ stores.inject(MyMetaStore, storeInstance);
46969
47167
  const position = { sheetId, col: i + col, row: j + row };
46970
47168
  const cell = this.getters.getCell(position);
46971
47169
  const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
46972
- const positionId = this.encoder.encode(position);
46973
- this.setEvaluatedCell(positionId, evaluatedCell);
47170
+ this.evaluatedCells.set(position, evaluatedCell);
46974
47171
  // check if formula dependencies present in the spread zone
46975
47172
  // if so, they need to be recomputed
46976
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
47173
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([position]));
46977
47174
  };
46978
47175
  }
46979
- invalidateSpreading(positionId) {
46980
- if (!this.spreadingRelations.isArrayFormula(positionId)) {
47176
+ invalidateSpreading(position) {
47177
+ if (!this.spreadingRelations.isArrayFormula(position)) {
46981
47178
  return;
46982
47179
  }
46983
- for (const child of this.spreadingRelations.getArrayResultPositionIds(positionId)) {
46984
- const content = this.getCell(child)?.content;
47180
+ for (const child of this.spreadingRelations.getArrayResultPositions(position)) {
47181
+ const content = this.getters.getCell(child)?.content;
46985
47182
  if (content) {
46986
47183
  // there's no point at re-evaluating overlapping array formulas,
46987
47184
  // there's still a collision
@@ -46991,28 +47188,25 @@ stores.inject(MyMetaStore, storeInstance);
46991
47188
  this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
46992
47189
  this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
46993
47190
  }
46994
- this.spreadingRelations.removeNode(positionId);
47191
+ this.spreadingRelations.removeNode(position);
46995
47192
  }
46996
47193
  // ----------------------------------------------------------
46997
47194
  // COMMON FUNCTIONALITY
46998
47195
  // ----------------------------------------------------------
46999
- getDirectDependencies(positionId) {
47000
- const cell = this.getCell(positionId);
47196
+ getDirectDependencies(position) {
47197
+ const cell = this.getters.getCell(position);
47001
47198
  if (!cell?.isFormula) {
47002
47199
  return [];
47003
47200
  }
47004
47201
  return cell.compiledFormula.dependencies;
47005
47202
  }
47006
- getCellsDependingOn(positionIds) {
47203
+ getCellsDependingOn(positions) {
47007
47204
  const ranges = [];
47008
- for (const positionId of positionIds) {
47009
- ranges.push(this.encoder.decodeToBoundingBox(positionId));
47205
+ for (const position of positions) {
47206
+ ranges.push({ sheetId: position.sheetId, zone: positionToZone(position) });
47010
47207
  }
47011
47208
  return this.formulaDependencies().getCellsDependingOn(ranges);
47012
47209
  }
47013
- getCell(positionId) {
47014
- return this.getters.getCell(this.encoder.decode(positionId));
47015
- }
47016
47210
  }
47017
47211
  function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
47018
47212
  for (let i = 0; i < nbColumns; ++i) {
@@ -47038,85 +47232,6 @@ stores.inject(MyMetaStore, storeInstance);
47038
47232
  }
47039
47233
  return fPayload;
47040
47234
  }
47041
- /**
47042
- * Encode (and decode) cell positions { sheetId, col, row }
47043
- * to a single integer.
47044
- *
47045
- * `col` and `row` values are encoded on 21 bits each (max 2^21 = 2_097_152),
47046
- * An incremental integer id is assigned to each different sheet id, starting at 0.
47047
- *
47048
- * e.g.
47049
- * Given { col: 10, row: 4, sheetId: "abcde" }
47050
- * we have:
47051
- * - row "4" encoded on 21 bits: 000000000000000000100
47052
- * - col "10" encoded on 21 bits: 000000000000000001010
47053
- * - sheetId: let's say it's the 4th sheetId met, encoded to: 11
47054
- *
47055
- * The final encoded value is found by concatenating the 3 bit sequences:
47056
- *
47057
- * sheetId: 11
47058
- * col: 000000000000000001010
47059
- * row: 000000000000000000100
47060
- * => 11000000000000000001010000000000000000000100
47061
- *
47062
- * this binary sequence is the integer 13194160504836
47063
- */
47064
- class PositionBitsEncoder {
47065
- sheetMapping = {};
47066
- inverseSheetMapping = new Map();
47067
- constructor() {
47068
- try {
47069
- // @ts-ignore
47070
- o_spreadsheet.__DEBUG__ = o_spreadsheet.__DEBUG__ || {};
47071
- // @ts-ignore
47072
- o_spreadsheet.__DEBUG__.decodePosition = this.decode.bind(this);
47073
- // @ts-ignore
47074
- o_spreadsheet.__DEBUG__.encodePosition = this.encode.bind(this);
47075
- }
47076
- catch (error) { }
47077
- }
47078
- /**
47079
- * Encode a cell position to a single integer.
47080
- */
47081
- encode({ sheetId, col, row }) {
47082
- return (this.encodeSheet(sheetId) << 42n) | (BigInt(col) << 21n) | BigInt(row);
47083
- }
47084
- encodeBoundingBox({ sheetId, zone }) {
47085
- const positions = [];
47086
- forEachPositionsInZone(zone, (col, row) => {
47087
- positions.push(this.encode({ sheetId, col, row }));
47088
- });
47089
- return positions;
47090
- }
47091
- decode(id) {
47092
- // keep only the last 21 bits by AND-ing the bit sequence with 21 ones
47093
- const row = Number(id & 2097151n);
47094
- const col = Number((id >> 21n) & 2097151n);
47095
- const sheetId = this.decodeSheet(id >> 42n);
47096
- return { sheetId, col, row };
47097
- }
47098
- decodeToBoundingBox(id) {
47099
- const { sheetId, col, row } = this.decode(id);
47100
- return { sheetId, zone: { left: col, top: row, right: col, bottom: row } };
47101
- }
47102
- encodeSheet(sheetId) {
47103
- const sheetKey = this.sheetMapping[sheetId];
47104
- if (sheetKey === undefined) {
47105
- const newSheetKey = BigInt(Object.keys(this.sheetMapping).length);
47106
- this.sheetMapping[sheetId] = newSheetKey;
47107
- this.inverseSheetMapping.set(newSheetKey, sheetId);
47108
- return newSheetKey;
47109
- }
47110
- return sheetKey;
47111
- }
47112
- decodeSheet(sheetKey) {
47113
- const sheetId = this.inverseSheetMapping.get(sheetKey);
47114
- if (sheetId === undefined) {
47115
- throw new Error("Sheet id not found");
47116
- }
47117
- return sheetId;
47118
- }
47119
- }
47120
47235
  function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId, cellId) {
47121
47236
  compilationParams.evalContext.__originCellXC = lazy(() => {
47122
47237
  if (!cellId) {
@@ -47263,6 +47378,10 @@ stores.inject(MyMetaStore, storeInstance);
47263
47378
  this.evaluator.updateDependencies(cmd);
47264
47379
  }
47265
47380
  break;
47381
+ case "DUPLICATE_SHEET":
47382
+ case "CREATE_SHEET":
47383
+ this.shouldRebuildDependenciesGraph = true;
47384
+ break;
47266
47385
  case "EVALUATE_CELLS":
47267
47386
  this.evaluator.evaluateAllCells();
47268
47387
  break;
@@ -60047,9 +60166,9 @@ stores.inject(MyMetaStore, storeInstance);
60047
60166
  exports.tokenize = tokenize;
60048
60167
 
60049
60168
 
60050
- __info__.version = "17.2.0-alpha.8";
60051
- __info__.date = "2024-03-15T11:01:01.388Z";
60052
- __info__.hash = "11cf381";
60169
+ __info__.version = "17.3.0-alpha.0";
60170
+ __info__.date = "2024-03-20T13:42:32.042Z";
60171
+ __info__.hash = "073e154";
60053
60172
 
60054
60173
 
60055
60174
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);