From 76a4f0c17e4d754a30e8b536bb94528a17b793a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Oliva?= Date: Wed, 25 Oct 2023 10:52:02 +0200 Subject: [PATCH] improve nested map --- .../context-state/src/internal/nested-map.ts | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/packages/context-state/src/internal/nested-map.ts b/packages/context-state/src/internal/nested-map.ts index 75b6f3b..30bb519 100644 --- a/packages/context-state/src/internal/nested-map.ts +++ b/packages/context-state/src/internal/nested-map.ts @@ -1,79 +1,78 @@ +import { EMPTY_VALUE } from "./empty-value" + export const Wildcard = Symbol("Wildcard") export type Wildcard = typeof Wildcard export class NestedMap { - private root: Map - private rootValue?: V - constructor() { - this.root = new Map() - this.rootValue = undefined - } + protected subtree: Map> = new Map() + protected value: V | EMPTY_VALUE = EMPTY_VALUE get(keys: K[]): V | undefined { - if (keys.length === 0) return this.rootValue - let current: any = this.root + let current: NestedMap = this for (let i = 0; i < keys.length; i++) { - current = current.get(keys[i]) - if (!current) return undefined - // a child instance could be checking for a parent instance with its (longer) key - if (!(current instanceof Map)) return current + const next = current.subtree.get(keys[i]) + if (!next) return undefined + current = next } - return current + + return current.value === EMPTY_VALUE ? undefined : current.value } set(keys: K[], value: V): void { - if (keys.length === 0) { - this.rootValue = value - return - } - let current: Map = this.root - let i - for (i = 0; i < keys.length - 1; i++) { - let nextCurrent = current.get(keys[i]) + let current: NestedMap = this + for (let i = 0; i < keys.length; i++) { + let nextCurrent = current.subtree.get(keys[i]) if (!nextCurrent) { - nextCurrent = new Map() - current.set(keys[i], nextCurrent) + nextCurrent = new NestedMap() + current.subtree.set(keys[i], nextCurrent) } current = nextCurrent } - current.set(keys[i], value) + current.value = value } delete(keys: K[]): void { - if (keys.length === 0) { - delete this.rootValue - return - } - const maps: Map[] = [this.root] - let current: Map = this.root + let current: NestedMap = this + const maps = [current] - for (let i = 0; i < keys.length - 1; i++) { - maps.push((current = current.get(keys[i]))) + for (let i = 0; i < keys.length; i++) { + const next = current.subtree.get(keys[i]) + if (!next) break + maps.push((current = next)) } - let mapIdx = maps.length - 1 - maps[mapIdx].delete(keys[mapIdx]) - - while (--mapIdx > -1 && maps[mapIdx].get(keys[mapIdx]).size === 0) { - maps[mapIdx].delete(keys[mapIdx]) + current.value = EMPTY_VALUE + let currentIdx = maps.length + while ( + --currentIdx > 0 && + maps[currentIdx].value === EMPTY_VALUE && + maps[currentIdx].subtree.size === 0 + ) { + maps[currentIdx - 1].subtree.delete(keys[currentIdx - 1]) } } *values(keys?: Array): Generator { - if (this.rootValue && (!keys || keys.length === 0)) { - yield this.rootValue + if (this.value !== EMPTY_VALUE && (!keys || keys.length === 0)) { + yield this.value } - const mapsToIterate: Array<[Map, number]> = [[this.root, 0]] - let iteration: [Map, number] | undefined + const mapsToIterate: Array<[NestedMap, number]> = [[this, 0]] + let iteration: [NestedMap, number] | undefined while ((iteration = mapsToIterate.pop())) { const [map, depth] = iteration - for (let [key, value] of map) { + if ( + map.value !== EMPTY_VALUE && + (!keys || keys.length <= depth || keys[depth] === Wildcard) + ) { + yield map.value + } + for (let [key, nestedMap] of map.subtree) { if (keys && keys[depth] !== Wildcard && keys[depth] !== key) continue - if (value instanceof Map) { - mapsToIterate.push([value, depth + 1]) - } else { - yield value + + mapsToIterate.push([nestedMap, depth + 1]) + if (nestedMap.value !== EMPTY_VALUE) { + yield nestedMap.value } } }