@tldraw/state
Version:
tldraw infinite canvas SDK (state).
8 lines (7 loc) • 9.53 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/lib/ArraySet.ts"],
"sourcesContent": ["/**\n * The maximum number of items that can be stored in an ArraySet in array mode before switching to Set mode.\n *\n * @public\n * @example\n * ```ts\n * import { ARRAY_SIZE_THRESHOLD } from '@tldraw/state'\n *\n * console.log(ARRAY_SIZE_THRESHOLD) // 8\n * ```\n */\nexport const ARRAY_SIZE_THRESHOLD = 8\n\n/**\n * An ArraySet operates as an array until it reaches a certain size, after which a Set is used\n * instead. In either case, the same methods are used to get, set, remove, and visit the items.\n * @internal\n */\nexport class ArraySet<T> {\n\tprivate arraySize = 0\n\n\tprivate array: (T | undefined)[] | null = Array(ARRAY_SIZE_THRESHOLD)\n\n\tprivate set: Set<T> | null = null\n\n\t/**\n\t * Get whether this ArraySet has any elements.\n\t *\n\t * @returns True if this ArraySet has any elements, false otherwise.\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isEmpty() {\n\t\tif (this.array) {\n\t\t\treturn this.arraySize === 0\n\t\t}\n\n\t\tif (this.set) {\n\t\t\treturn this.set.size === 0\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Add an element to the ArraySet if it is not already present.\n\t *\n\t * @param elem - The element to add to the set\n\t * @returns `true` if the element was added, `false` if it was already present\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t *\n\t * console.log(arraySet.add('hello')) // true\n\t * console.log(arraySet.add('hello')) // false (already exists)\n\t * ```\n\t */\n\tadd(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// Return false if the element is already in the array.\n\t\t\tif (idx !== -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif (this.arraySize < ARRAY_SIZE_THRESHOLD) {\n\t\t\t\t// If the array is below the size threshold, push items into the array.\n\n\t\t\t\t// Insert the element into the array's next available slot.\n\t\t\t\tthis.array[this.arraySize] = elem\n\t\t\t\tthis.arraySize++\n\n\t\t\t\treturn true\n\t\t\t} else {\n\t\t\t\t// If the array is full, convert it to a set and remove the array.\n\t\t\t\tthis.set = new Set(this.array as any)\n\t\t\t\tthis.array = null\n\t\t\t\tthis.set.add(elem)\n\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// Return false if the element is already in the set.\n\t\t\tif (this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.add(elem)\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Remove an element from the ArraySet if it is present.\n\t *\n\t * @param elem - The element to remove from the set\n\t * @returns `true` if the element was removed, `false` if it was not present\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t *\n\t * console.log(arraySet.remove('hello')) // true\n\t * console.log(arraySet.remove('hello')) // false (not present)\n\t * ```\n\t */\n\tremove(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// If the item is not in the array, return false.\n\t\t\tif (idx === -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.array[idx] = undefined\n\t\t\tthis.arraySize--\n\n\t\t\tif (idx !== this.arraySize) {\n\t\t\t\t// If the item is not the last item in the array, move the last item into the\n\t\t\t\t// removed item's slot.\n\t\t\t\tthis.array[idx] = this.array[this.arraySize]\n\t\t\t\tthis.array[this.arraySize] = undefined\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// If the item is not in the set, return false.\n\t\t\tif (!this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.delete(elem)\n\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Execute a callback function for each element in the ArraySet.\n\t *\n\t * @param visitor - A function to call for each element in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t * arraySet.add('world')\n\t *\n\t * arraySet.visit((item) => {\n\t * console.log(item) // 'hello', 'world'\n\t * })\n\t * ```\n\t */\n\tvisit(visitor: (item: T) => void) {\n\t\tif (this.array) {\n\t\t\tfor (let i = 0; i < this.arraySize; i++) {\n\t\t\t\tconst elem = this.array[i]\n\n\t\t\t\tif (typeof elem !== 'undefined') {\n\t\t\t\t\tvisitor(elem)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\n\t\tif (this.set) {\n\t\t\tthis.set.forEach(visitor)\n\n\t\t\treturn\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Make the ArraySet iterable, allowing it to be used in for...of loops and with spread syntax.\n\t *\n\t * @returns An iterator that yields each element in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<number>()\n\t * arraySet.add(1)\n\t * arraySet.add(2)\n\t *\n\t * for (const item of arraySet) {\n\t * console.log(item) // 1, 2\n\t * }\n\t *\n\t * const items = [...arraySet] // [1, 2]\n\t * ```\n\t */\n\t*[Symbol.iterator]() {\n\t\tif (this.array) {\n\t\t\tfor (let i = 0; i < this.arraySize; i++) {\n\t\t\t\tconst elem = this.array[i]\n\n\t\t\t\tif (typeof elem !== 'undefined') {\n\t\t\t\t\tyield elem\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.set) {\n\t\t\tyield* this.set\n\t\t} else {\n\t\t\tthrow new Error('no set or array')\n\t\t}\n\t}\n\n\t/**\n\t * Check whether an element is present in the ArraySet.\n\t *\n\t * @param elem - The element to check for\n\t * @returns `true` if the element is present, `false` otherwise\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t *\n\t * console.log(arraySet.has('hello')) // true\n\t * console.log(arraySet.has('world')) // false\n\t * ```\n\t */\n\thas(elem: T) {\n\t\tif (this.array) {\n\t\t\treturn this.array.indexOf(elem) !== -1\n\t\t} else {\n\t\t\treturn this.set!.has(elem)\n\t\t}\n\t}\n\n\t/**\n\t * Remove all elements from the ArraySet.\n\t *\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t * arraySet.add('world')\n\t *\n\t * arraySet.clear()\n\t * console.log(arraySet.size()) // 0\n\t * ```\n\t */\n\tclear() {\n\t\tif (this.set) {\n\t\t\tthis.set.clear()\n\t\t} else {\n\t\t\tthis.arraySize = 0\n\t\t\tthis.array = []\n\t\t}\n\t}\n\n\t/**\n\t * Get the number of elements in the ArraySet.\n\t *\n\t * @returns The number of elements in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * console.log(arraySet.size()) // 0\n\t *\n\t * arraySet.add('hello')\n\t * console.log(arraySet.size()) // 1\n\t * ```\n\t */\n\tsize() {\n\t\tif (this.set) {\n\t\t\treturn this.set.size\n\t\t} else {\n\t\t\treturn this.arraySize\n\t\t}\n\t}\n}\n"],
"mappings": "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",
"names": []
}