hyperformula
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
200 lines (198 loc) • 6.14 kB
JavaScript
;
exports.__esModule = true;
exports.SparseStrategy = void 0;
var _Cell = require("../../Cell");
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/
/**
* Mapping from cell addresses to vertices
*
* Uses Map to store addresses, having minimal memory usage for sparse sheets but not necessarily constant set/lookup.
*/
class SparseStrategy {
constructor(width, height) {
this.width = width;
this.height = height;
/**
* Map of Maps in which actual data is stored.
*
* Key of map in first level is column number.
* Key of map in second level is row number.
*/
this.mapping = new Map();
}
/** @inheritDoc */
getCell(address) {
var _a;
return (_a = this.mapping.get(address.col)) === null || _a === void 0 ? void 0 : _a.get(address.row);
}
/** @inheritDoc */
setCell(address, newVertex) {
this.width = Math.max(this.width, address.col + 1);
this.height = Math.max(this.height, address.row + 1);
let colMapping = this.mapping.get(address.col);
if (!colMapping) {
colMapping = new Map();
this.mapping.set(address.col, colMapping);
}
colMapping.set(address.row, newVertex);
}
/** @inheritDoc */
has(address) {
var _a;
return !!((_a = this.mapping.get(address.col)) === null || _a === void 0 ? void 0 : _a.get(address.row));
}
/** @inheritDoc */
getHeight() {
return this.height;
}
/** @inheritDoc */
getWidth() {
return this.width;
}
removeCell(address) {
var _a;
(_a = this.mapping.get(address.col)) === null || _a === void 0 ? void 0 : _a.delete(address.row);
}
addRows(row, numberOfRows) {
this.mapping.forEach(rowMapping => {
const tmpMapping = new Map();
rowMapping.forEach((vertex, rowNumber) => {
if (rowNumber >= row) {
tmpMapping.set(rowNumber + numberOfRows, vertex);
rowMapping.delete(rowNumber);
}
});
tmpMapping.forEach((vertex, rowNumber) => {
rowMapping.set(rowNumber, vertex);
});
});
this.height += numberOfRows;
}
addColumns(column, numberOfColumns) {
const tmpMapping = new Map();
this.mapping.forEach((rowMapping, colNumber) => {
if (colNumber >= column) {
tmpMapping.set(colNumber + numberOfColumns, rowMapping);
this.mapping.delete(colNumber);
}
});
tmpMapping.forEach((rowMapping, colNumber) => {
this.mapping.set(colNumber, rowMapping);
});
this.width += numberOfColumns;
}
removeRows(removedRows) {
this.mapping.forEach(rowMapping => {
const tmpMapping = new Map();
rowMapping.forEach((vertex, rowNumber) => {
if (rowNumber >= removedRows.rowStart) {
rowMapping.delete(rowNumber);
if (rowNumber > removedRows.rowEnd) {
tmpMapping.set(rowNumber - removedRows.numberOfRows, vertex);
}
}
});
tmpMapping.forEach((vertex, rowNumber) => {
rowMapping.set(rowNumber, vertex);
});
});
const rightmostRowRemoved = Math.min(this.height - 1, removedRows.rowEnd);
const numberOfRowsRemoved = Math.max(0, rightmostRowRemoved - removedRows.rowStart + 1);
this.height = Math.max(0, this.height - numberOfRowsRemoved);
}
removeColumns(removedColumns) {
const tmpMapping = new Map();
this.mapping.forEach((rowMapping, colNumber) => {
if (colNumber >= removedColumns.columnStart) {
this.mapping.delete(colNumber);
if (colNumber > removedColumns.columnEnd) {
tmpMapping.set(colNumber - removedColumns.numberOfColumns, rowMapping);
}
}
});
tmpMapping.forEach((rowMapping, colNumber) => {
this.mapping.set(colNumber, rowMapping);
});
const rightmostColumnRemoved = Math.min(this.width - 1, removedColumns.columnEnd);
const numberOfColumnsRemoved = Math.max(0, rightmostColumnRemoved - removedColumns.columnStart + 1);
this.width = Math.max(0, this.width - numberOfColumnsRemoved);
}
*getEntries(sheet) {
for (const [colNumber, col] of this.mapping) {
for (const [rowNumber, value] of col) {
yield [(0, _Cell.simpleCellAddress)(sheet, colNumber, rowNumber), value];
}
}
}
*verticesFromColumn(column) {
const colMapping = this.mapping.get(column);
if (colMapping === undefined) {
return;
}
for (const [_, vertex] of colMapping) {
yield vertex;
}
}
*verticesFromRow(row) {
for (const colMapping of this.mapping.values()) {
const rowVertex = colMapping.get(row);
if (rowVertex !== undefined) {
yield rowVertex;
}
}
}
*verticesFromColumnsSpan(columnsSpan) {
for (const column of columnsSpan.columns()) {
const colMapping = this.mapping.get(column);
if (colMapping === undefined) {
continue;
}
for (const [_, vertex] of colMapping) {
yield vertex;
}
}
}
*verticesFromRowsSpan(rowsSpan) {
for (const colMapping of this.mapping.values()) {
for (const row of rowsSpan.rows()) {
const rowVertex = colMapping.get(row);
if (rowVertex !== undefined) {
yield rowVertex;
}
}
}
}
*entriesFromRowsSpan(rowsSpan) {
for (const [col, colMapping] of this.mapping.entries()) {
for (const row of rowsSpan.rows()) {
const rowVertex = colMapping.get(row);
if (rowVertex !== undefined) {
yield [(0, _Cell.simpleCellAddress)(rowsSpan.sheet, col, row), rowVertex];
}
}
}
}
*entriesFromColumnsSpan(columnsSpan) {
for (const col of columnsSpan.columns()) {
const colMapping = this.mapping.get(col);
if (colMapping !== undefined) {
for (const [row, vertex] of colMapping.entries()) {
yield [(0, _Cell.simpleCellAddress)(columnsSpan.sheet, col, row), vertex];
}
}
}
}
*vertices() {
for (const [_, col] of this.mapping) {
for (const [_, value] of col) {
if (value !== undefined) {
yield value;
}
}
}
}
}
exports.SparseStrategy = SparseStrategy;