@@ -3,12 +3,14 @@ import { IterationOptions, PartialKey, TraverseMode, YieldMode } from './types';
33
44const VAL = Symbol ( 'value' ) ;
55const SET = Symbol ( 'valueSet' ) ;
6+ const COUNT = Symbol ( 'count' ) ;
67const MAP = Symbol ( 'objectMap' ) ;
78
89type CacheNode = {
910 [ MAP ] ?: Map < unknown , CacheNode > ;
1011 [ SET ] ?: number ;
1112 [ VAL ] ?: unknown ;
13+ [ COUNT ] : number ;
1214} ;
1315
1416type PathArray = readonly unknown [ ] ;
@@ -198,9 +200,9 @@ const traverser = {
198200 * ```
199201 */
200202export class NestedMap < K , V > {
201- private readonly _root : CacheNode = { } ;
202-
203- private _size = 0 ;
203+ private readonly _root : CacheNode = {
204+ [ COUNT ] : 0 ,
205+ } ;
204206
205207 /**
206208 * Creates a new NestedMap instance.
@@ -218,24 +220,43 @@ export class NestedMap<K, V> {
218220 * Gets the number of key-value pairs in the map.
219221 */
220222 get size ( ) : number {
221- return this . _size ;
223+ return this . _root [ COUNT ] ;
222224 }
223225
224- private _getOrCreateNode ( nestedKey : K ) {
226+ private _getOrCreateNode ( nestedKey : K , path : CacheNode [ ] ) {
225227 const keyArray = treatKey ( nestedKey ) ;
226228 let current = this . _root ;
229+ path . push ( current ) ;
227230
228231 // Navigate/create the path
229232 for ( let i = 0 ; i < keyArray . length ; i ++ ) {
230233 const key = keyArray [ i ] ;
231234 const map = ( current [ MAP ] ??= new Map ( ) ) ;
232- let next = map . get ( key ) ;
233- if ( ! next ) map . set ( key , ( next = { } ) ) ;
235+ let next : CacheNode = map . get ( key ) ;
236+ if ( ! next ) {
237+ next = {
238+ [ COUNT ] : 0 ,
239+ } ;
240+ map . set ( key , next ) ;
241+ }
242+ path . push ( next ) ;
234243 current = next ;
235244 }
236245 return current ;
237246 }
238247
248+ #internalSet( current : CacheNode , value : V , path : CacheNode [ ] ) {
249+ const isNewEntry = current [ SET ] !== 1 ;
250+
251+ // Store the actual value using the special VALUE_KEY
252+ current [ VAL ] = value ;
253+
254+ if ( isNewEntry ) {
255+ path . forEach ( ( p ) => p [ COUNT ] ++ ) ;
256+ current [ SET ] = 1 ;
257+ }
258+ }
259+
239260 /**
240261 * Stores a value with the given array key.
241262 *
@@ -244,18 +265,11 @@ export class NestedMap<K, V> {
244265 * @returns This NestedMap instance for chaining
245266 */
246267 set ( nestedKey : K , value : V ) : this {
247- const current = this . _getOrCreateNode ( nestedKey ) ;
268+ const path : CacheNode [ ] = [ ] ;
269+ const current = this . _getOrCreateNode ( nestedKey , path ) ;
248270
249271 // Check if this is a new entry by seeing if VALUE_KEY already exists
250- const isNewEntry = current [ SET ] !== 1 ;
251-
252- // Store the actual value using the special VALUE_KEY
253- current [ VAL ] = value ;
254-
255- if ( isNewEntry ) {
256- this . _size ++ ;
257- current [ SET ] = 1 ;
258- }
272+ this . #internalSet( current , value , path ) ;
259273
260274 return this ;
261275 }
@@ -282,10 +296,11 @@ export class NestedMap<K, V> {
282296 * @returns The existing or newly created value
283297 */
284298 getOrSet < T extends V > ( nestedKey : K , getNewValue : ( nestedKey : K ) => T ) : T {
285- const node = this . _getOrCreateNode ( nestedKey ) ;
286- if ( node ?. [ VAL ] !== undefined ) return node [ VAL ] as T ;
299+ const path : CacheNode [ ] = [ ] ;
300+ const node = this . _getOrCreateNode ( nestedKey , path ) ;
301+ if ( node [ VAL ] !== undefined ) return node [ VAL ] as T ;
287302 const value = getNewValue ( nestedKey ) ;
288- this . set ( nestedKey , value ) ;
303+ this . #internalSet ( node , value , path ) ;
289304 return value ;
290305 }
291306
@@ -336,19 +351,24 @@ export class NestedMap<K, V> {
336351 }
337352 // Remove the value
338353 current [ VAL ] = undefined ;
354+ let decrement = current [ SET ] ? 1 : 0 ;
339355 current [ SET ] = 0 ;
340- this . _size -- ;
341356
342357 // Clean up empty Maps from the bottom up
343358 if ( current [ MAP ] ?. size ) {
344- if ( ! deleteSubTree ) return true ;
359+ if ( ! deleteSubTree ) {
360+ this . _root [ COUNT ] -= decrement ;
361+ return true ;
362+ }
363+ decrement = current [ COUNT ] ;
345364 current [ MAP ] = undefined ;
346365 }
347366 for ( let i = path . length - 1 ; i >= 0 ; i -- ) {
348367 const pathItem = path [ i ] as Required < ( typeof path ) [ 0 ] > ;
349368 const nodeMap = pathItem . map [ MAP ] as Map < unknown , CacheNode > ;
350369 const { map, key } = pathItem ;
351370 nodeMap . delete ( key ) ;
371+ pathItem . map [ COUNT ] -= decrement ;
352372 if ( nodeMap . size ) break ;
353373 map [ MAP ] = undefined ;
354374 }
@@ -361,7 +381,7 @@ export class NestedMap<K, V> {
361381 */
362382 clear ( ) : void {
363383 this . _root [ MAP ] ?. clear ( ) ;
364- this . _size = 0 ;
384+ this . _root [ COUNT ] = 0 ;
365385 }
366386
367387 /**
@@ -394,7 +414,7 @@ export class NestedMap<K, V> {
394414 root = this . _getNode ( basePath ) ;
395415 if ( ! root ) {
396416 return traverser [ TraverseMode . BreadthFirst ] [ yieldMode ] (
397- { } ,
417+ { [ COUNT ] : 0 } ,
398418 EMPTY ,
399419 justValue ,
400420 ) ;
0 commit comments