{"version":3,"file":"SortedMap.cjs","sources":["../../src/SortedMap.ts"],"sourcesContent":["import { compareKeys } from '@tanstack/db-ivm'\n\n/**\n * A Map implementation that keeps its entries sorted based on a comparator function\n * @template TKey - The type of keys in the map (must be string | number)\n * @template TValue - The type of values in the map\n */\nexport class SortedMap<TKey extends string | number, TValue> {\n  private map: Map<TKey, TValue>\n  private sortedKeys: Array<TKey>\n  private comparator: ((a: TValue, b: TValue) => number) | undefined\n  private orderDirty = false\n  private runtimeKeyCount = 0\n\n  /**\n   * Creates a new SortedMap instance\n   *\n   * @param comparator - Optional function to compare values for sorting.\n   *                     If not provided, entries are sorted by key only.\n   */\n  constructor(comparator?: (a: TValue, b: TValue) => number) {\n    this.map = new Map<TKey, TValue>()\n    this.sortedKeys = []\n    this.comparator = comparator\n  }\n\n  /**\n   * Finds the index where a key-value pair should be inserted to maintain sort order.\n   * Uses binary search to find the correct position based on the value (if comparator provided),\n   * with key-based tie-breaking for deterministic ordering when values compare as equal.\n   * If no comparator is provided, sorts by key only.\n   * Runs in O(log n) time.\n   *\n   * @param key - The key to find position for (used as tie-breaker or primary sort when no comparator)\n   * @param value - The value to compare against (only used if comparator is provided)\n   * @returns The index where the key should be inserted\n   */\n  private indexOf(key: TKey, value: TValue): number {\n    let left = 0\n    let right = this.sortedKeys.length\n\n    // Fast path: no comparator means sort by key only\n    if (!this.comparator) {\n      while (left < right) {\n        const mid = Math.floor((left + right) / 2)\n        const midKey = this.sortedKeys[mid]!\n        const keyComparison = compareKeys(key, midKey)\n        if (keyComparison < 0) {\n          right = mid\n        } else if (keyComparison > 0) {\n          left = mid + 1\n        } else {\n          return mid\n        }\n      }\n      return left\n    }\n\n    // With comparator: sort by value first, then key as tie-breaker\n    while (left < right) {\n      const mid = Math.floor((left + right) / 2)\n      const midKey = this.sortedKeys[mid]!\n      const midValue = this.map.get(midKey)!\n      const valueComparison = this.comparator(value, midValue)\n\n      if (valueComparison < 0) {\n        right = mid\n      } else if (valueComparison > 0) {\n        left = mid + 1\n      } else {\n        // Values are equal, use key as tie-breaker for deterministic ordering\n        const keyComparison = compareKeys(key, midKey)\n        if (keyComparison < 0) {\n          right = mid\n        } else if (keyComparison > 0) {\n          left = mid + 1\n        } else {\n          // Same key (shouldn't happen during insert, but handle for lookups)\n          return mid\n        }\n      }\n    }\n\n    return left\n  }\n\n  /** Restore the ordered view after a synchronous batch of deferred writes. */\n  restoreOrder(): void {\n    if (!this.orderDirty) return\n    this.sortedKeys.length = 0\n    for (const key of this.map.keys()) this.sortedKeys.push(key)\n    this.sortedKeys.sort((left, right) => {\n      const byValue =\n        this.comparator?.(this.map.get(left)!, this.map.get(right)!) ?? 0\n      return byValue || compareKeys(left, right)\n    })\n    this.orderDirty = false\n  }\n\n  /**\n   * Sets a key-value pair in the map and maintains sort order\n   *\n   * @param key - The key to set\n   * @param value - The value to associate with the key\n   * @param deferOrder - Defer ordering until restoreOrder or the next ordered read\n   * @returns This SortedMap instance for chaining\n   */\n  set(key: TKey, value: TValue, deferOrder = false): this {\n    // Grouped Collections can produce nullish keys at runtime. compareKeys\n    // is not a total order there, so retain the existing binary-insert path.\n    const runtimeKey = typeof key !== `string` && typeof key !== `number`\n    if (deferOrder && this.runtimeKeyCount === 0 && !runtimeKey) {\n      this.map.set(key, value)\n      this.orderDirty = true\n      return this\n    }\n    this.restoreOrder()\n    const exists = this.map.has(key)\n    if (exists) {\n      // Need to remove the old key from the sorted keys array\n      const oldValue = this.map.get(key)!\n      const oldIndex = this.indexOf(key, oldValue)\n      this.sortedKeys.splice(oldIndex, 1)\n    }\n\n    // Insert the new key at the correct position\n    const index = this.indexOf(key, value)\n    this.sortedKeys.splice(index, 0, key)\n\n    this.map.set(key, value)\n    if (runtimeKey && !exists) this.runtimeKeyCount++\n\n    return this\n  }\n\n  /**\n   * Gets a value by its key\n   *\n   * @param key - The key to look up\n   * @returns The value associated with the key, or undefined if not found\n   */\n  get(key: TKey): TValue | undefined {\n    return this.map.get(key)\n  }\n\n  /**\n   * Removes a key-value pair from the map\n   *\n   * @param key - The key to remove\n   * @param deferOrder - Defer ordering until restoreOrder or the next ordered read\n   * @returns True if the key was found and removed, false otherwise\n   */\n  delete(key: TKey, deferOrder = false): boolean {\n    if (deferOrder && this.runtimeKeyCount === 0) {\n      const deleted = this.map.delete(key)\n      this.orderDirty ||= deleted\n      return deleted\n    }\n    this.restoreOrder()\n    if (this.map.has(key)) {\n      const oldValue = this.map.get(key)\n      const index = this.indexOf(key, oldValue!)\n      this.sortedKeys.splice(index, 1)\n      const deleted = this.map.delete(key)\n      if (deleted && typeof key !== `string` && typeof key !== `number`)\n        this.runtimeKeyCount--\n      return deleted\n    }\n\n    return false\n  }\n\n  /**\n   * Checks if a key exists in the map\n   *\n   * @param key - The key to check\n   * @returns True if the key exists, false otherwise\n   */\n  has(key: TKey): boolean {\n    return this.map.has(key)\n  }\n\n  /**\n   * Removes all key-value pairs from the map\n   */\n  clear(): void {\n    this.map.clear()\n    this.sortedKeys = []\n    this.orderDirty = false\n    this.runtimeKeyCount = 0\n  }\n\n  /**\n   * Gets the number of key-value pairs in the map\n   */\n  get size(): number {\n    return this.map.size\n  }\n\n  /**\n   * Default iterator that returns entries in sorted order\n   *\n   * @returns An iterator for the map's entries\n   */\n  *[Symbol.iterator](): IterableIterator<[TKey, TValue]> {\n    this.restoreOrder()\n    for (const key of this.sortedKeys) {\n      yield [key, this.map.get(key)!] as [TKey, TValue]\n    }\n  }\n\n  /**\n   * Returns an iterator for the map's entries in sorted order\n   *\n   * @returns An iterator for the map's entries\n   */\n  entries(): IterableIterator<[TKey, TValue]> {\n    return this[Symbol.iterator]()\n  }\n\n  /**\n   * Returns an iterator for the map's keys in sorted order\n   *\n   * @returns An iterator for the map's keys\n   */\n  keys(): IterableIterator<TKey> {\n    this.restoreOrder()\n    return this.sortedKeys[Symbol.iterator]()\n  }\n\n  /**\n   * Returns an iterator for the map's values in sorted order\n   *\n   * @returns An iterator for the map's values\n   */\n  values(): IterableIterator<TValue> {\n    return function* (this: SortedMap<TKey, TValue>) {\n      this.restoreOrder()\n      for (const key of this.sortedKeys) {\n        yield this.map.get(key)!\n      }\n    }.call(this)\n  }\n\n  /**\n   * Executes a callback function for each key-value pair in the map in sorted order\n   *\n   * @param callbackfn - Function to execute for each entry\n   */\n  forEach(\n    callbackfn: (value: TValue, key: TKey, map: Map<TKey, TValue>) => void,\n  ): void {\n    this.restoreOrder()\n    for (const key of this.sortedKeys) {\n      callbackfn(this.map.get(key)!, key, this.map)\n    }\n  }\n}\n"],"names":["compareKeys"],"mappings":"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"}