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:
Eric Nguyen 2022-10-12 09:39:54 +00:00
parent 466ef2b08b
commit c256a76e01
45 changed files with 775 additions and 450 deletions

View file

@ -69,12 +69,11 @@ export function AddContainers(
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
const current = history[history.length - 1];
// Deep clone the main container for the history
const clone: IContainerModel = structuredClone(current.mainContainer);
const containers = structuredClone(current.containers);
// Find the parent in the clone
const parentClone: IContainerModel | undefined = FindContainerById(
clone, parentId
containers, parentId
);
if (parentClone === null || parentClone === undefined) {
@ -90,14 +89,15 @@ export function AddContainers(
// Iterate over the containers
availableContainers.forEach((availableContainer, typeIndex) => {
// Get the preset properties from the API
AddNewContainerToParent(availableContainer, configuration, parentClone, index, typeIndex, newCounters, current.symbols, containerIds);
AddNewContainerToParent(availableContainer, configuration, containers, parentClone, index, typeIndex, newCounters, current.symbols, containerIds);
});
// Update the state
history.push({
lastAction: `Add [${containerIds.join(', ')}] in ${parentClone.properties.id}`,
mainContainer: clone,
mainContainer: current.mainContainer,
selectedContainerId: parentClone.properties.id,
containers,
typeCounters: newCounters,
symbols: structuredClone(current.symbols),
selectedSymbolId: current.selectedSymbolId
@ -109,6 +109,7 @@ export function AddContainers(
function AddNewContainerToParent(
availableContainer: IAvailableContainer,
configuration: IConfiguration,
containers: Map<string, IContainerModel>,
parentClone: IContainerModel,
index: number,
typeIndex: number,
@ -143,7 +144,7 @@ function AddNewContainerToParent(
({ x, y, width, height } = ApplyMargin(x, y, width, height, left, bottom, top, right));
// Apply an add method (append or insert/replace)
({ x, y } = ApplyAddMethod(index + typeIndex, containerConfig, parentClone, x, y));
({ x, y } = ApplyAddMethod(containers, index + typeIndex, containerConfig, parentClone, x, y));
// Set the counter of the object type in order to assign an unique id
UpdateCounters(newCounters, type);
@ -170,22 +171,25 @@ function AddNewContainerToParent(
}
);
// Register the container in the hashmap
containers.set(newContainer.properties.id, newContainer);
// Add it to the parent
if (index === parentClone.children.length) {
parentClone.children.push(newContainer);
parentClone.children.push(newContainer.properties.id);
} else {
parentClone.children.splice(index, 0, newContainer);
parentClone.children.splice(index, 0, newContainer.properties.id);
}
// Sort the parent children by x
SortChildren(parentClone);
SortChildren(containers, parentClone);
/// Handle behaviors here ///
// Apply the behaviors (flex, rigid, anchor)
ApplyBehaviors(newContainer, symbols);
ApplyBehaviors(containers, newContainer, symbols);
// Then, apply the behaviors on its siblings (mostly for flex)
ApplyBehaviorsOnSiblingsChildren(newContainer, symbols);
ApplyBehaviorsOnSiblingsChildren(containers, newContainer, symbols);
// Initialize default children of the container
if (initChilds) {
@ -194,6 +198,7 @@ function AddNewContainerToParent(
newContainer,
configuration,
containerConfig,
containers,
newCounters,
symbols
);
@ -201,6 +206,7 @@ function AddNewContainerToParent(
InitializeChildrenWithPattern(
newContainer,
configuration,
containers,
containerConfig,
newCounters,
symbols
@ -258,6 +264,7 @@ function InitializeDefaultChild(
newContainer: ContainerModel,
configuration: IConfiguration,
containerConfig: IAvailableContainer,
containers: Map<string, IContainerModel>,
newCounters: Record<string, number>,
symbols: Map<string, ISymbolModel>
): void {
@ -276,6 +283,7 @@ function InitializeDefaultChild(
AddNewContainerToParent(
currentConfig,
configuration,
containers,
parent,
0, 0,
newCounters,
@ -286,6 +294,7 @@ function InitializeDefaultChild(
function InitializeChildrenWithPattern(
newContainer: ContainerModel,
configuration: IConfiguration,
containers: Map<string, IContainerModel>,
containerConfig: IAvailableContainer,
newCounters: Record<string, number>,
symbols: Map<string, ISymbolModel>
@ -307,6 +316,7 @@ function InitializeChildrenWithPattern(
AddNewContainerToParent(
container,
configuration,
containers,
newContainer,
0, 0,
newCounters,
@ -334,6 +344,7 @@ function InitializeChildrenWithPattern(
AddNewContainerToParent(
containerConfig,
configuration,
containers,
node.parent,
0, 0,
newCounters,
@ -350,9 +361,10 @@ function InitializeChildrenWithPattern(
console.warn(`[InitializeChildrenFromPattern] IAvailableContainer from pattern was not found in the configuration: ${pattern.wrapper}.
Process will ignore the container.`);
} else {
parent = AddNewContainerToParent(
const newChildContainer = AddNewContainerToParent(
container,
configuration,
containers,
parent,
0, 0,
newCounters,
@ -360,6 +372,9 @@ function InitializeChildrenWithPattern(
undefined,
false
);
// iterate
parent = newChildContainer;
}
}
@ -398,6 +413,7 @@ interface Node {
* @returns New offset
*/
function ApplyAddMethod(
containers: Map<string, IContainerModel>,
index: number,
containerConfig: IAvailableContainer,
parent: IContainerModel,
@ -410,8 +426,8 @@ function ApplyAddMethod(
containerConfig.AddMethod === AddMethod.Append
)) {
// Append method (default)
const lastChild: IContainerModel | undefined = parent.children
.at(index - 1);
const lastChildId: string = parent.children[index - 1];
const lastChild = FindContainerById(containers, lastChildId);
if (lastChild !== undefined) {
const isHorizontal = parent.properties.orientation === Orientation.Horizontal;