From f243adf0b08c98a29c111124c37d107abed1c6a0 Mon Sep 17 00:00:00 2001 From: DR-Univer Date: Thu, 24 Oct 2024 12:36:41 +0800 Subject: [PATCH] refactor(formula): tree id string to number --- packages/core/src/shared/r-tree.ts | 30 ++-- .../src/engine/ast-node/base-ast-node.ts | 2 +- .../src/engine/ast-node/node-type.ts | 26 ++-- .../src/engine/dependency/dependency-tree.ts | 17 +-- .../engine/dependency/formula-dependency.ts | 20 +-- .../services/dependency-manager.service.ts | 140 +++++++++++++----- 6 files changed, 146 insertions(+), 89 deletions(-) diff --git a/packages/core/src/shared/r-tree.ts b/packages/core/src/shared/r-tree.ts index 4e60587d59e..357d1dbe659 100644 --- a/packages/core/src/shared/r-tree.ts +++ b/packages/core/src/shared/r-tree.ts @@ -19,18 +19,20 @@ import type { IUnitRange } from '../sheets/typedef'; import KDBush from 'kdbush'; import RBush from 'rbush'; +type StringOrNumber = string | number; + export interface IRTreeItem extends IUnitRange { - id: string; + id: StringOrNumber; } interface IRBushItem extends BBox { - id: string; + id: StringOrNumber; } interface IRdTreeItem { x: number; y: number; - ids: Set; + ids: Set; } export interface IRTreeData { @@ -43,7 +45,7 @@ export class RTree { private _tree: Map>> = new Map(); // unitId -> subUnitId -> row -> column -> ids - private _oneCellCache = new Map>>>>(); + private _oneCellCache = new Map>>>>(); private _kdTree: Map> = new Map(); @@ -68,7 +70,7 @@ export class RTree { return this._tree.get(unitId)!.get(subUnitId)!; } - private _getOneCellCache(unitId: string, subUnitId: string, row: number, column: number): Set { + private _getOneCellCache(unitId: string, subUnitId: string, row: number, column: number): Set { if (!this._oneCellCache.has(unitId)) { this._oneCellCache.set(unitId, new Map()); } @@ -85,7 +87,7 @@ export class RTree { return this._oneCellCache.get(unitId)!.get(subUnitId)!.get(row)!.get(column)!; } - private _removeOneCellCache(unitId: string, subUnitId: string, row: number, column: number, id: string) { + private _removeOneCellCache(unitId: string, subUnitId: string, row: number, column: number, id: StringOrNumber) { const unitCache = this._oneCellCache.get(unitId); if (!unitCache) return; @@ -101,11 +103,11 @@ export class RTree { cellCache.delete(id); } - private _insertOneCellCache(unitId: string, subUnitId: string, row: number, column: number, id: string) { + private _insertOneCellCache(unitId: string, subUnitId: string, row: number, column: number, id: StringOrNumber) { this._getOneCellCache(unitId, subUnitId, row, column).add(id); } - private _getRdTreeItems(map: Map>>) { + private _getRdTreeItems(map: Map>>) { const items: IRdTreeItem[] = []; for (const [y, innerMap] of map) { @@ -121,7 +123,7 @@ export class RTree { return items; } - private _searchByOneCellCache(search: IUnitRange): string[] { + private _searchByOneCellCache(search: IUnitRange): StringOrNumber[] { const { unitId, sheetId: subUnitId, range } = search; const { startRow, startColumn, endRow, endColumn } = range; const searchObject = this._kdTree.get(unitId)?.get(subUnitId); @@ -133,7 +135,7 @@ export class RTree { const indexes = tree.range(startColumn, startRow, endColumn, endRow); - const result: string[] = []; + const result: StringOrNumber[] = []; for (const index of indexes) { const item = items[index]; @@ -221,10 +223,10 @@ export class RTree { } } - search(search: IUnitRange): string[] { + search(search: IUnitRange): StringOrNumber[] { const { unitId, sheetId: subUnitId, range } = search; - const results: string[] = []; + const results: StringOrNumber[] = []; if (this._enableOneCellCache && this._enableOneCellCache) { const oneCellResults = this._searchByOneCellCache(search); @@ -252,8 +254,8 @@ export class RTree { return results; } - bulkSearch(searchList: IUnitRange[]): Set { - const result = new Set(); + bulkSearch(searchList: IUnitRange[]): Set { + const result = new Set(); for (const search of searchList) { const items = this.search(search); for (const item of items) { diff --git a/packages/engine-formula/src/engine/ast-node/base-ast-node.ts b/packages/engine-formula/src/engine/ast-node/base-ast-node.ts index fb0fb676d68..acf0d330894 100644 --- a/packages/engine-formula/src/engine/ast-node/base-ast-node.ts +++ b/packages/engine-formula/src/engine/ast-node/base-ast-node.ts @@ -26,7 +26,7 @@ import { NodeType } from './node-type'; interface IAstNodeNodeJson { token: string; children?: IAstNodeNodeJson[]; - nodeType: string; + nodeType: number; } export type LambdaPrivacyVarType = Map>; diff --git a/packages/engine-formula/src/engine/ast-node/node-type.ts b/packages/engine-formula/src/engine/ast-node/node-type.ts index 3103ab65b9e..0e02ba6e1b0 100644 --- a/packages/engine-formula/src/engine/ast-node/node-type.ts +++ b/packages/engine-formula/src/engine/ast-node/node-type.ts @@ -15,19 +15,19 @@ */ export enum NodeType { - REFERENCE = 'ReferenceNode', - VALUE = 'ValueNode', - OPERATOR = 'OperatorNode', - FUNCTION = 'FunctionNode', - LAMBDA = 'LambdaNode', - LAMBDA_PARAMETER = 'LambdaNodeParameter', - ERROR = 'ErrorNode', - BASE = 'Base', - ROOT = 'Root', - UNION = 'UnionNode', - PREFIX = 'PrefixNode', - SUFFIX = 'SuffixNode', - NULL = 'NullNode', + REFERENCE = 1, + VALUE = 2, + OPERATOR = 3, + FUNCTION = 4, + LAMBDA = 5, + LAMBDA_PARAMETER = 6, + ERROR = 7, + BASE = 8, + ROOT = 9, + UNION = 10, + PREFIX = 11, + SUFFIX = 12, + NULL = 13, } export const NODE_ORDER_MAP = new Map([ diff --git a/packages/engine-formula/src/engine/dependency/dependency-tree.ts b/packages/engine-formula/src/engine/dependency/dependency-tree.ts index c0c97bd9d9d..1428b387d76 100644 --- a/packages/engine-formula/src/engine/dependency/dependency-tree.ts +++ b/packages/engine-formula/src/engine/dependency/dependency-tree.ts @@ -26,7 +26,6 @@ import type { IFormulaDirtyData } from '../../services/current-data.service'; import type { IAllRuntimeData } from '../../services/runtime.service'; import type { IExecuteAstNodeData } from '../utils/ast-node-tool'; -import { generateRandomId } from '@univerjs/core'; export enum FDtreeStateType { DEFAULT, @@ -44,13 +43,13 @@ export enum FDtreeStateType { * is used to determine the order of formula calculations. */ export class FormulaDependencyTree { - treeId: string = ''; + treeId: number = -1; nodeData: Nullable; - children: Set = new Set(); + children: Set = new Set(); - parents: Set = new Set(); + parents: Set = new Set(); formula: string = ''; @@ -74,12 +73,8 @@ export class FormulaDependencyTree { isCache: boolean = false; - constructor(treeId?: string) { - if (treeId != null) { - this.treeId = treeId; - } else { - this.treeId = generateRandomId(8); - } + constructor(treeId: number) { + this.treeId = treeId; } toJson() { @@ -227,7 +222,7 @@ export class FormulaDependencyTree { this.rangeList.push(...ranges); } - hasChildren(treeId: string) { + hasChildren(treeId: number) { return this.children.has(treeId); } diff --git a/packages/engine-formula/src/engine/dependency/formula-dependency.ts b/packages/engine-formula/src/engine/dependency/formula-dependency.ts index 2beecb0e920..459580838b8 100644 --- a/packages/engine-formula/src/engine/dependency/formula-dependency.ts +++ b/packages/engine-formula/src/engine/dependency/formula-dependency.ts @@ -51,9 +51,9 @@ interface IFeatureFormulaParam { featureId: string; } -function generateRandomDependencyTreeId(dependencyManagerService: IDependencyManagerService): string { +function generateRandomDependencyTreeId(dependencyManagerService: IDependencyManagerService): number { const idNum = dependencyManagerService.getLastTreeId() || 0; - return idNum.toString(); + return idNum; } export class FormulaDependencyGenerator extends Disposable { @@ -132,9 +132,9 @@ export class FormulaDependencyGenerator extends Disposable { } private _isCyclicUtil( - treeId: string, - visited: Set, - recursionStack: Set + treeId: number, + visited: Set, + recursionStack: Set ) { const node = this._dependencyManagerService.getTreeById(treeId); if (node == null) { @@ -160,8 +160,8 @@ export class FormulaDependencyGenerator extends Disposable { } private _checkIsCycleDependency(treeList: FormulaDependencyTree[]) { - const visited = new Set(); - const recursionStack = new Set(); + const visited = new Set(); + const recursionStack = new Set(); // Call the recursive helper function to detect cycle in different // DFS trees @@ -727,7 +727,7 @@ export class FormulaDependencyGenerator extends Disposable { featureTree = this._getFeatureFormulaTree(featureId, params); newTreeList.push(featureTree); } - featureTree.parents = new Set(); + featureTree.parents = new Set(); intersectTrees.forEach((tree) => { if (tree.hasChildren(featureTree!.treeId)) { return; @@ -748,7 +748,7 @@ export class FormulaDependencyGenerator extends Disposable { const featureMap = this._featureCalculationManagerService.getReferenceExecutorMap(); newTreeList.forEach((tree) => { - const newChildren = new Set(); + const newChildren = new Set(); for (const childTreeId of tree.children) { const child = this._dependencyManagerService.getTreeById(childTreeId); if (!child) { @@ -762,7 +762,7 @@ export class FormulaDependencyGenerator extends Disposable { } tree.children = newChildren; - const newParents = new Set(); + const newParents = new Set(); for (const parentTreeId of tree.parents) { const parent = this._dependencyManagerService.getTreeById(parentTreeId); if (!parent) { diff --git a/packages/engine-formula/src/services/dependency-manager.service.ts b/packages/engine-formula/src/services/dependency-manager.service.ts index a5411ca919d..036edea9b2a 100644 --- a/packages/engine-formula/src/services/dependency-manager.service.ts +++ b/packages/engine-formula/src/services/dependency-manager.service.ts @@ -14,20 +14,20 @@ * limitations under the License. */ -import type { IUnitRange, Nullable } from '@univerjs/core'; +import type { IRTreeItem, IUnitRange, Nullable } from '@univerjs/core'; import type { FormulaDependencyTree } from '../engine/dependency/dependency-tree'; import { createIdentifier, Disposable, ObjectMatrix, RTree } from '@univerjs/core'; export interface IOtherFormulaDependencyParam { - [unitId: string]: Nullable<{ [sheetId: string]: { [formulaId: string]: Nullable } }>; + [unitId: string]: Nullable<{ [sheetId: string]: { [formulaId: string]: Nullable } }>; } export interface IFeatureFormulaDependencyParam { - [unitId: string]: Nullable<{ [sheetId: string]: { [featureId: string]: Nullable } }>; + [unitId: string]: Nullable<{ [sheetId: string]: { [featureId: string]: Nullable } }>; } export interface IFormulaDependencyParam { - [unitId: string]: Nullable<{ [sheetId: string]: ObjectMatrix< string> }>; + [unitId: string]: Nullable<{ [sheetId: string]: ObjectMatrix< number> }>; } export interface IDependencyManagerService { @@ -65,7 +65,7 @@ export interface IDependencyManagerService { addDependencyRTreeCache(tree: FormulaDependencyTree): void; - searchDependency(search: IUnitRange[]): Set; + searchDependency(search: IUnitRange[]): Set; getLastTreeId(): number; @@ -77,7 +77,7 @@ export interface IDependencyManagerService { openKdTree(): void; closeKdTree(): void; - getTreeById(treeId: string): Nullable; + getTreeById(treeId: number): Nullable; } /** @@ -93,7 +93,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM private _formulaData: IFormulaDependencyParam = {}; - private _allTreeMap: Map = new Map(); + private _allTreeMap: Map = new Map(); private _dependencyRTreeCache: RTree = new RTree(true); // true: open kd-tree search state @@ -105,6 +105,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM this._formulaData = {}; this._dependencyRTreeCache.dispose(); this._restDependencyTreeId(); + this._allTreeMap.clear(); } /** @@ -178,7 +179,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM return trees; } - getTreeById(treeId: string) { + getTreeById(treeId: number) { return this._allTreeMap.get(treeId); } @@ -194,8 +195,8 @@ export class DependencyManagerService extends Disposable implements IDependencyM return allTrees; } - searchDependency(search: IUnitRange[]): Set { - return this._dependencyRTreeCache.bulkSearch(search); + searchDependency(search: IUnitRange[]): Set { + return this._dependencyRTreeCache.bulkSearch(search) as Set; } /** @@ -204,7 +205,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM * @param shouldBeBuildTrees FormulaDependencyTree[] | FormulaDependencyTreeCache */ private _buildDependencyTree(allTrees: FormulaDependencyTree[], shouldBeBuildTrees: FormulaDependencyTree[]) { - const shouldBeBuildTreeMap = new Map(); + const shouldBeBuildTreeMap = new Map(); for (let i = 0; i < shouldBeBuildTrees.length; i++) { const tree = shouldBeBuildTrees[i]; shouldBeBuildTreeMap.set(tree.treeId, tree); @@ -217,7 +218,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM const searchResults = this._dependencyRTreeCache.search(RTreeItem); for (let j = 0; j < searchResults.length; j++) { - const id = searchResults[j]; + const id = searchResults[j] as number; const shouldBeBuildTree = shouldBeBuildTreeMap.get(id); if (shouldBeBuildTree && tree !== shouldBeBuildTree && !shouldBeBuildTree.hasChildren(tree.treeId)) { @@ -237,7 +238,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM * @param dependencyTrees */ private _buildReverseDependency(allTrees: FormulaDependencyTree[], dependencyTrees: FormulaDependencyTree[]) { - const allTreeMap = new Map(); + const allTreeMap = new Map(); for (let i = 0; i < allTrees.length; i++) { const tree = allTrees[i]; @@ -251,7 +252,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM const searchResults = this._dependencyRTreeCache.search(RTreeItem); for (let j = 0; j < searchResults.length; j++) { - const id = searchResults[j]; + const id = searchResults[j] as number; const allTree = allTreeMap.get(id); if (allTree && tree !== allTree && !allTree.hasChildren(tree.treeId)) { @@ -317,7 +318,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM if (this._otherFormulaData[unitId] && this._otherFormulaData[unitId]![sheetId]) { formulaIds.forEach((formulaId) => { const deleteTreeId = this._otherFormulaData[unitId]![sheetId][formulaId]; - const deleteTree = this._allTreeMap.get(deleteTreeId || ''); + if (deleteTreeId == null) { + return; + } + const deleteTree = this._allTreeMap.get(deleteTreeId); this._removeDependencyRTreeCache(deleteTree); this.clearDependencyForTree(deleteTree); delete this._otherFormulaData[unitId]![sheetId][formulaId]; @@ -327,7 +331,11 @@ export class DependencyManagerService extends Disposable implements IDependencyM } getOtherFormulaDependency(unitId: string, sheetId: string, formulaId: string) { - return this._allTreeMap.get(this._otherFormulaData[unitId]?.[sheetId]?.[formulaId] || ''); + let treeId = this._otherFormulaData[unitId]?.[sheetId]?.[formulaId]; + if (treeId == null) { + treeId = -1; + } + return this._allTreeMap.get(treeId); } hasOtherFormulaDependency(unitId: string, sheetId: string, formulaId: string) { @@ -338,7 +346,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM if (sheetId && this._otherFormulaData[unitId] && this._otherFormulaData[unitId]![sheetId]) { this._removeDependencyRTreeCacheById(unitId, sheetId); Object.values(this._otherFormulaData[unitId]![sheetId]).forEach((formulaTreeId) => { - const formula = this._allTreeMap.get(formulaTreeId || ''); + if (formulaTreeId == null) { + return; + } + const formula = this._allTreeMap.get(formulaTreeId); this.clearDependencyForTree(formula); this._removeAllTreeMap(formulaTreeId); }); @@ -352,7 +363,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM } this._removeDependencyRTreeCacheById(unitId, sheetId); Object.values(unitOtherData[sheetId]!).forEach((formulaTreeId) => { - const formula = this._allTreeMap.get(formulaTreeId || ''); + if (formulaTreeId == null) { + return; + } + const formula = this._allTreeMap.get(formulaTreeId); this.clearDependencyForTree(formula); this._removeAllTreeMap(formulaTreeId); }); @@ -378,7 +392,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM if (this._featureFormulaData[unitId] && this._featureFormulaData[unitId]![sheetId]) { featureIds.forEach((featureId) => { const deleteTreeId = this._featureFormulaData[unitId]![sheetId][featureId]; - const deleteTree = this._allTreeMap.get(deleteTreeId || ''); + if (deleteTreeId == null) { + return; + } + const deleteTree = this._allTreeMap.get(deleteTreeId); this._removeDependencyRTreeCache(deleteTree); this.clearDependencyForTree(deleteTree); delete this._featureFormulaData[unitId]![sheetId][featureId]; @@ -391,7 +408,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM if (sheetId && this._featureFormulaData[unitId] && this._featureFormulaData[unitId]![sheetId]) { this._removeDependencyRTreeCacheById(unitId, sheetId); Object.values(this._featureFormulaData[unitId]![sheetId]).forEach((featureTreeId) => { - const feature = this._allTreeMap.get(featureTreeId || ''); + if (featureTreeId == null) { + return; + } + const feature = this._allTreeMap.get(featureTreeId); this._removeDependencyRTreeCache(feature); this.clearDependencyForTree(feature); this._removeAllTreeMap(featureTreeId); @@ -406,7 +426,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM } this._removeDependencyRTreeCacheById(unitId, sheetId); Object.values(unitFeatureData[sheetId]!).forEach((featureTreeId) => { - const feature = this._allTreeMap.get(featureTreeId || ''); + if (featureTreeId == null) { + return; + } + const feature = this._allTreeMap.get(featureTreeId); this.clearDependencyForTree(feature); this._removeAllTreeMap(featureTreeId); }); @@ -417,7 +440,11 @@ export class DependencyManagerService extends Disposable implements IDependencyM } getFeatureFormulaDependency(unitId: string, sheetId: string, featureId: string) { - return this._allTreeMap.get(this._featureFormulaData[unitId]?.[sheetId]?.[featureId] || ''); + const treeId = this._featureFormulaData[unitId]?.[sheetId]?.[featureId]; + if (treeId == null) { + return null; + } + return this._allTreeMap.get(treeId); } addFormulaDependency(unitId: string, sheetId: string, row: number, column: number, dependencyTree: FormulaDependencyTree) { @@ -425,7 +452,7 @@ export class DependencyManagerService extends Disposable implements IDependencyM this._formulaData[unitId] = {}; } if (!this._formulaData[unitId]![sheetId]) { - this._formulaData[unitId]![sheetId] = new ObjectMatrix(); + this._formulaData[unitId]![sheetId] = new ObjectMatrix(); } this._formulaData[unitId]![sheetId].setValue(row, column, dependencyTree.treeId); this._allTreeMap.set(dependencyTree.treeId, dependencyTree); @@ -434,7 +461,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM removeFormulaDependency(unitId: string, sheetId: string, row: number, column: number) { if (this._formulaData[unitId] && this._formulaData[unitId]![sheetId]) { const deleteTreeId = this._formulaData[unitId]![sheetId].getValue(row, column); - const deleteTree = this._allTreeMap.get(deleteTreeId || ''); + if (deleteTreeId == null) { + return; + } + const deleteTree = this._allTreeMap.get(deleteTreeId); this._removeDependencyRTreeCache(deleteTree); this.clearDependencyForTree(deleteTree); this._formulaData[unitId]![sheetId].realDeleteValue(row, column); @@ -446,7 +476,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM if (sheetId && this._formulaData[unitId] && this._formulaData[unitId]![sheetId]) { this._removeDependencyRTreeCacheById(unitId, sheetId); this._formulaData[unitId]![sheetId].forValue((row, column, treeId) => { - const tree = this._allTreeMap.get(treeId || ''); + if (treeId == null) { + return true; + } + const tree = this._allTreeMap.get(treeId); this.clearDependencyForTree(tree); this._removeAllTreeMap(treeId); }); @@ -460,7 +493,10 @@ export class DependencyManagerService extends Disposable implements IDependencyM } this._removeDependencyRTreeCacheById(unitId, sheetId); unitFormulaData[sheetId].forValue((row, column, treeId) => { - const tree = this._allTreeMap.get(treeId || ''); + if (treeId == null) { + return true; + } + const tree = this._allTreeMap.get(treeId); this.clearDependencyForTree(tree); this._removeAllTreeMap(treeId); }); @@ -479,16 +515,28 @@ export class DependencyManagerService extends Disposable implements IDependencyM } getFormulaDependency(unitId: string, sheetId: string, row: number, column: number) { - return this._allTreeMap.get(this._formulaData[unitId]?.[sheetId]?.getValue(row, column) || ''); + const treeId = this._formulaData[unitId]?.[sheetId]?.getValue(row, column); + if (treeId == null) { + return null; + } + return this._allTreeMap.get(treeId); } addDependencyRTreeCache(tree: FormulaDependencyTree) { - this._dependencyRTreeCache.bulkInsert(tree.rangeList.map((range) => { - return { - ...range, + const searchRanges: IRTreeItem[] = []; + for (let i = 0; i < tree.rangeList.length; i++) { + const unitRangeWithNum = tree.rangeList[i]; + const { unitId, sheetId, range } = unitRangeWithNum; + + searchRanges.push({ + unitId, + sheetId, + range, id: tree.treeId, - }; - })); + }); + } + + this._dependencyRTreeCache.bulkInsert(searchRanges); } private _restDependencyTreeId() { @@ -509,19 +557,28 @@ export class DependencyManagerService extends Disposable implements IDependencyM if (tree == null) { return; } - this._dependencyRTreeCache.bulkRemove(tree.rangeList.map((range) => { - return { - ...range, + + const searchRanges: IRTreeItem[] = []; + for (let i = 0; i < tree.rangeList.length; i++) { + const unitRangeWithNum = tree.rangeList[i]; + const { unitId, sheetId, range } = unitRangeWithNum; + + searchRanges.push({ + unitId, + sheetId, + range, id: tree.treeId, - }; - })); + }); + } + + this._dependencyRTreeCache.bulkRemove(searchRanges); } removeFormulaDependencyByDefinedName(unitId: string, definedName: string) { if (this._formulaData[unitId]) { Object.values(this._formulaData[unitId]).forEach((sheet) => { sheet.forValue((row, column, treeId) => { - const tree = this._allTreeMap.get(treeId || ''); + const tree = this._allTreeMap.get(treeId); if (tree?.nodeData?.node.hasDefinedName(definedName)) { this._removeDependencyRTreeCache(tree); this.clearDependencyForTree(tree); @@ -540,8 +597,11 @@ export class DependencyManagerService extends Disposable implements IDependencyM this._dependencyRTreeCache.closeKdTree(); } - private _removeAllTreeMap(treeId: Nullable) { - this._allTreeMap.delete(treeId || ''); + private _removeAllTreeMap(treeId: Nullable) { + if (treeId == null) { + return; + } + this._allTreeMap.delete(treeId); } }