/** * @class LazyFactoryMap * * The LazyFactoryMap object holds key-value pairs in the structure similar to the * regular Map. Once created, items can be moved around a grid depending on the operations * performed on that grid - adding or removing rows. The collection requires "key" * to be a zero-based index. * * It's essential to notice that the "key" index under which the item was created * is volatile. After altering the grid, the "key" index can change. * * Values live in a single native Map keyed by the CURRENT volatile key. Lookups are a * single integer-keyed `Map.get` - a native Map is always a hash table, so far-apart keys * (for example, physical row 999990 on a million-row grid) cannot push the storage into a * slow mode, unlike a sparse array. Key shifts coming from `insert`/`remove` are buffered: * contiguous runs of same-type calls merge into one buffered shift, single-key reads * (`obtain`/`has`/`getIfExists`/`evict`) resolve through the buffer by mapping the requested * key back to its stored key in O(buffered shifts), and only full-view reads * (`size`/`values`/`entries`) apply the buffer in a single O(materialized) re-key pass that * rebuilds the map in its original iteration order - which keeps `values()` returning items * in order of initialization and makes a loop of single-row alters pay one pass per batch, * not one per call. The materialized size is normally viewport-bound thanks to the * render-derived cell meta eviction. */ export default class LazyFactoryMap> { #private; /** * The data factory function. * * @type {Function} */ valueFactory: (key: number) => V; /** * Initializes the map with the given factory function used to create values for new keys on first access. */ constructor(valueFactory: (key: number) => V); /** * Gets or if data not exist creates and returns new data. * * @param {number} key The item key as zero-based index. * @returns {*} */ obtain(key: number): V; /** * Checks whether a value for the given key has already been created, without creating one. * Unlike `obtain`, this never triggers the value factory. * * @param {number} key The item key as zero-based index. * @returns {boolean} */ has(key: number): boolean; /** * Inserts an empty space for new data. Materialized values stored under keys at or after * the insertion point are re-keyed upwards by `amount`; the inserted keys themselves stay * unmaterialized until the first `obtain` call. The re-keying is buffered (a contiguous run * of inserts merges into one buffered shift) and applied once on the next full-view read, so * a loop of inserts costs one re-key pass, not one per call. When the insertion point sits * at or above every stored key (the common case on a large grid, where only the viewport * band is materialized), nothing is buffered at all. * * @param {number} key The key as volatile zero-based index at which to begin inserting space for new data. * @param {number} [amount=1] Amount of data to insert. */ insert(key: number | null | undefined, amount?: number): void; /** * Removes (soft remove) data from the map. Materialized values stored under the removed keys * are dropped (freed for garbage collection) and values under higher keys are re-keyed * downwards by `amount`. The re-keying is buffered (a contiguous run of removes - ascending * or descending - merges into one buffered shift) and applied once on the next full-view * read, so a loop of single-row removes (for example, the per-physical-row calls made by the * data layer when removing many rows at once) costs one re-key pass, not one per call. When * the removal point sits at or above every stored key, nothing is buffered at all. * * @param {number} key The key as volatile zero-based index at which to begin removing the data. * @param {number} [amount=1] Amount data to remove. */ remove(key: number | null | undefined, amount?: number): void; /** * Returns the number of materialized values this map currently holds. Keys reserved through * `insert` but never obtained, and keys released through `evict` or `remove`, are not counted. * * @returns {number} */ size(): number; /** * Returns a new Iterator object that contains the values for each item in the LazyMap object, * in order of value initialization. * * @returns {Iterator} */ values(): IterableIterator; /** * Returns a new Iterator object that contains an array of `[index, value]` for each item in * the LazyMap object, in order of value initialization. * * Mutation-during-iteration contract (also applies to `values()`): the iterator follows * native Map semantics. Releasing the currently visited key through `evict` (as * `CellMeta.evictRow` does) is safe; a value materialized mid-loop through `obtain` of a new * key WILL be visited. Calling `insert`/`remove` mid-loop only buffers the key shift, so the * walk continues undisturbed over the pre-shift view; if another read flushes the buffered * shifts mid-loop, the walk still completes over the pre-shift map it started on. * * @returns {Iterator} */ entries(): IterableIterator<[number, V]>; /** * Releases the value stored under the given key. The next `obtain` call for that key * re-creates the value through the factory (with a new identity). Unlike `remove`, the * surrounding keys do not shift, so this is safe for values that can be reconstructed * deterministically - for example render-derived cell meta for rows scrolled out of the * viewport. The entry is genuinely deleted, so its memory is freed - there is no leftover * slot. Does nothing when the key has no materialized value. * * @param {number} key The item key as zero-based index. */ evict(key: number): void; /** * Returns the value stored under the given key, or `undefined` when the key has no materialized * value. Unlike `obtain`, it never creates a value through the factory, so it is safe for * read-only existence checks against the current contents. * * @param {number} key The item key as zero-based index. * @returns {*} */ getIfExists(key: number): V | undefined; /** * Clears the map. */ clear(): void; /** * Makes this object iterable. * * @returns {Iterator} */ [Symbol.iterator](): IterableIterator<[number, V]>; }