{"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\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  /**\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   * @returns This SortedMap instance for chaining\n   */\n  set(key: TKey, value: TValue): this {\n    if (this.map.has(key)) {\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\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   * @returns True if the key was found and removed, false otherwise\n   */\n  delete(key: TKey): boolean {\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      return this.map.delete(key)\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  }\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    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    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      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    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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"}