Merged PR 212: Optimize FindChildrenById from O(n) to O(1)
Optimize FindChildrenById from O(n) to O(1): - Deprecate FindContainerByIdDFS - Container: Replace Children to string[] - Add HashMap to IHistoryState that contains all containers To access a container by id now cost O(1) without any additional cost + Implement CICD for SVGLibs
This commit is contained in:
parent
466ef2b08b
commit
c256a76e01
45 changed files with 775 additions and 450 deletions
|
@ -124,6 +124,8 @@ export function GetDefaultEditorState(configuration: IConfiguration): IEditorSta
|
|||
null,
|
||||
mainContainerConfig
|
||||
);
|
||||
const containers = new Map<string, IContainerModel>();
|
||||
containers.set(mainContainer.properties.id, mainContainer);
|
||||
|
||||
const typeCounters = {};
|
||||
(typeCounters as any)[mainContainer.properties.type] = 0;
|
||||
|
@ -133,7 +135,8 @@ export function GetDefaultEditorState(configuration: IConfiguration): IEditorSta
|
|||
history: [
|
||||
{
|
||||
lastAction: '',
|
||||
mainContainer,
|
||||
mainContainer: mainContainer.properties.id,
|
||||
containers,
|
||||
selectedContainerId: mainContainer.properties.id,
|
||||
typeCounters,
|
||||
symbols: new Map(),
|
||||
|
@ -175,6 +178,13 @@ export const DEFAULT_CONFIG: IConfiguration = {
|
|||
/* eslint-enable */
|
||||
};
|
||||
|
||||
const DEFAULT_CONTAINER_STYLE = {
|
||||
stroke: 'black',
|
||||
fillOpacity: 1,
|
||||
fill: 'white',
|
||||
strokeWidth: 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Main container properties
|
||||
*/
|
||||
|
@ -203,10 +213,7 @@ export const DEFAULT_MAINCONTAINER_PROPS: IContainerProperties = {
|
|||
showDimensionWithMarks: [Position.Down, Position.Right],
|
||||
markPosition: [],
|
||||
warning: '',
|
||||
style: {
|
||||
stroke: 'black',
|
||||
fillOpacity: 0
|
||||
}
|
||||
style: DEFAULT_CONTAINER_STYLE
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -256,7 +263,7 @@ export function GetDefaultContainerProps(type: string,
|
|||
showDimensionWithMarks: containerConfig.ShowDimensionWithMarks ?? [],
|
||||
warning: '',
|
||||
customSVG: containerConfig.CustomSVG,
|
||||
style: structuredClone(containerConfig.Style),
|
||||
style: Object.assign(structuredClone(DEFAULT_CONTAINER_STYLE), structuredClone(containerConfig.Style)),
|
||||
userData: structuredClone(containerConfig.UserData)
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,9 +1,22 @@
|
|||
import { IContainerModel } from '../Interfaces/IContainerModel';
|
||||
|
||||
export function * MakeChildrenIterator(containers: Map<string, IContainerModel>, childrenIds: string[]): Generator<IContainerModel, void, unknown> {
|
||||
for (const childId of childrenIds) {
|
||||
const child = FindContainerById(containers, childId);
|
||||
|
||||
if (child === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield child;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Generator iterating of over the children depth-first
|
||||
*/
|
||||
export function * MakeDFSIterator(root: IContainerModel, enableHideChildrenInTreeview = false): Generator<IContainerModel, void, unknown> {
|
||||
export function * MakeDFSIterator(root: IContainerModel, containers: Map<string, IContainerModel>, enableHideChildrenInTreeview = false): Generator<IContainerModel, void, unknown> {
|
||||
const queue: IContainerModel[] = [root];
|
||||
const visited = new Set<IContainerModel>(queue);
|
||||
while (queue.length > 0) {
|
||||
|
@ -16,8 +29,9 @@ export function * MakeDFSIterator(root: IContainerModel, enableHideChildrenInTre
|
|||
}
|
||||
|
||||
for (let i = container.children.length - 1; i >= 0; i--) {
|
||||
const child = container.children[i];
|
||||
if (visited.has(child)) {
|
||||
const childId = container.children[i];
|
||||
const child = FindContainerById(containers, childId);
|
||||
if (child === undefined || visited.has(child)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(child);
|
||||
|
@ -38,7 +52,7 @@ export interface ContainerAndDepthAndTransform extends ContainerAndDepth {
|
|||
/**
|
||||
* Returns a Generator iterating of over the children depth-first
|
||||
*/
|
||||
export function * MakeBFSIterator(root: IContainerModel): Generator<ContainerAndDepth, void, unknown> {
|
||||
export function * MakeBFSIterator(root: IContainerModel, containers: Map<string, IContainerModel>): Generator<ContainerAndDepth, void, unknown> {
|
||||
const queue: IContainerModel[] = [root];
|
||||
let depth = 0;
|
||||
while (queue.length > 0) {
|
||||
|
@ -51,7 +65,13 @@ export function * MakeBFSIterator(root: IContainerModel): Generator<ContainerAnd
|
|||
};
|
||||
|
||||
for (let i = container.children.length - 1; i >= 0; i--) {
|
||||
const child = container.children[i];
|
||||
const childId = container.children[i];
|
||||
const child = FindContainerById(containers, childId);
|
||||
|
||||
if (child === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queue.push(child);
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +81,7 @@ export function * MakeBFSIterator(root: IContainerModel): Generator<ContainerAnd
|
|||
|
||||
export function * MakeRecursionDFSIterator(
|
||||
root: IContainerModel | null,
|
||||
containers: Map<string, IContainerModel>,
|
||||
depth: number,
|
||||
currentTransform: [number, number],
|
||||
enableHideChildrenInTreeview: boolean = false
|
||||
|
@ -79,9 +100,16 @@ export function * MakeRecursionDFSIterator(
|
|||
return;
|
||||
}
|
||||
|
||||
for (const container of root.children) {
|
||||
for (const containerId of root.children) {
|
||||
const container = FindContainerById(containers, containerId);
|
||||
|
||||
if (container === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield * MakeRecursionDFSIterator(
|
||||
container,
|
||||
containers,
|
||||
depth + 1,
|
||||
[
|
||||
currentTransform[0] + root.properties.x,
|
||||
|
@ -185,8 +213,15 @@ export function ApplyParentTransform(
|
|||
return [x, y];
|
||||
}
|
||||
|
||||
export function FindContainerById(root: IContainerModel, id: string): IContainerModel | undefined {
|
||||
const it = MakeDFSIterator(root);
|
||||
/**
|
||||
* Returns the container by id
|
||||
* @deprecated Please use FindContainerById
|
||||
* @param root Root of the container tree
|
||||
* @param id Id of the container to find
|
||||
* @returns The container found or undefined if not found
|
||||
*/
|
||||
export function FindContainerByIdDFS(root: IContainerModel, containers: Map<string, IContainerModel>, id: string): IContainerModel | undefined {
|
||||
const it = MakeDFSIterator(root, containers);
|
||||
for (const container of it) {
|
||||
if (container.properties.id === id) {
|
||||
return container;
|
||||
|
@ -195,6 +230,17 @@ export function FindContainerById(root: IContainerModel, id: string): IContainer
|
|||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the container by id
|
||||
* For now, does the same as containers.get(id)
|
||||
* @param containers Map of containers
|
||||
* @param id id of container
|
||||
* @returns Container by id
|
||||
*/
|
||||
export function FindContainerById(containers: Map<string, IContainerModel>, id: string): IContainerModel | undefined {
|
||||
return containers.get(id);
|
||||
}
|
||||
|
||||
export interface IPair<T> {
|
||||
cur: T
|
||||
next: T
|
||||
|
|
|
@ -32,15 +32,22 @@ export function ReviveState(state: IHistoryState): void {
|
|||
for (const symbol of state.symbols.values()) {
|
||||
symbol.linkedContainers = new Set(symbol.linkedContainers);
|
||||
}
|
||||
state.containers = new Map(state.containers);
|
||||
|
||||
const it = MakeDFSIterator(state.mainContainer);
|
||||
const root = FindContainerById(state.containers, state.mainContainer);
|
||||
|
||||
if (root === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const it = MakeDFSIterator(root, state.containers);
|
||||
for (const container of it) {
|
||||
const parentId = container.properties.parentId;
|
||||
if (parentId === null) {
|
||||
container.parent = null;
|
||||
continue;
|
||||
}
|
||||
const parent = FindContainerById(state.mainContainer, parentId);
|
||||
const parent = FindContainerById(state.containers, parentId);
|
||||
if (parent === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
@ -53,6 +60,10 @@ export function GetCircularReplacer(): (key: any, value: object | Map<string, an
|
|||
if (key === 'parent') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === 'containers') {
|
||||
return Array.from((value as Map<string, any>).entries());
|
||||
}
|
||||
|
||||
if (key === 'symbols') {
|
||||
return Array.from((value as Map<string, any>).entries());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue