@tanstack/db-ivm 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/d2.cjs +25 -49
- package/dist/cjs/d2.cjs.map +1 -1
- package/dist/cjs/graph.cjs +8 -20
- package/dist/cjs/graph.cjs.map +1 -1
- package/dist/cjs/indexes.cjs +118 -79
- package/dist/cjs/indexes.cjs.map +1 -1
- package/dist/cjs/indexes.d.cts +23 -0
- package/dist/cjs/multiset.cjs +106 -115
- package/dist/cjs/multiset.cjs.map +1 -1
- package/dist/cjs/multiset.d.cts +1 -0
- package/dist/cjs/operators/debug.cjs +5 -15
- package/dist/cjs/operators/debug.cjs.map +1 -1
- package/dist/cjs/operators/distinct.cjs +11 -22
- package/dist/cjs/operators/distinct.cjs.map +1 -1
- package/dist/cjs/operators/filter.cjs +3 -12
- package/dist/cjs/operators/filter.cjs.map +1 -1
- package/dist/cjs/operators/filterBy.cjs.map +1 -1
- package/dist/cjs/operators/filterBy.d.cts +1 -2
- package/dist/cjs/operators/groupBy.cjs +13 -12
- package/dist/cjs/operators/groupBy.cjs.map +1 -1
- package/dist/cjs/operators/groupBy.d.cts +7 -4
- package/dist/cjs/operators/join.cjs +104 -93
- package/dist/cjs/operators/join.cjs.map +1 -1
- package/dist/cjs/operators/join.d.cts +11 -8
- package/dist/cjs/operators/map.cjs +3 -12
- package/dist/cjs/operators/map.cjs.map +1 -1
- package/dist/cjs/operators/orderBy.cjs +10 -10
- package/dist/cjs/operators/orderBy.cjs.map +1 -1
- package/dist/cjs/operators/orderBy.d.cts +1 -2
- package/dist/cjs/operators/output.cjs +3 -12
- package/dist/cjs/operators/output.cjs.map +1 -1
- package/dist/cjs/operators/reduce.cjs +11 -22
- package/dist/cjs/operators/reduce.cjs.map +1 -1
- package/dist/cjs/operators/tap.cjs +3 -12
- package/dist/cjs/operators/tap.cjs.map +1 -1
- package/dist/cjs/operators/topK.cjs +4 -4
- package/dist/cjs/operators/topK.cjs.map +1 -1
- package/dist/cjs/operators/topK.d.cts +1 -2
- package/dist/cjs/operators/topKWithFractionalIndex.cjs +56 -75
- package/dist/cjs/operators/topKWithFractionalIndex.cjs.map +1 -1
- package/dist/esm/d2.js +25 -49
- package/dist/esm/d2.js.map +1 -1
- package/dist/esm/graph.js +8 -20
- package/dist/esm/graph.js.map +1 -1
- package/dist/esm/indexes.d.ts +23 -0
- package/dist/esm/indexes.js +118 -79
- package/dist/esm/indexes.js.map +1 -1
- package/dist/esm/multiset.d.ts +1 -0
- package/dist/esm/multiset.js +106 -115
- package/dist/esm/multiset.js.map +1 -1
- package/dist/esm/operators/debug.js +5 -15
- package/dist/esm/operators/debug.js.map +1 -1
- package/dist/esm/operators/distinct.js +11 -22
- package/dist/esm/operators/distinct.js.map +1 -1
- package/dist/esm/operators/filter.js +3 -12
- package/dist/esm/operators/filter.js.map +1 -1
- package/dist/esm/operators/filterBy.d.ts +1 -2
- package/dist/esm/operators/filterBy.js.map +1 -1
- package/dist/esm/operators/groupBy.d.ts +7 -4
- package/dist/esm/operators/groupBy.js +13 -12
- package/dist/esm/operators/groupBy.js.map +1 -1
- package/dist/esm/operators/join.d.ts +11 -8
- package/dist/esm/operators/join.js +104 -93
- package/dist/esm/operators/join.js.map +1 -1
- package/dist/esm/operators/map.js +3 -12
- package/dist/esm/operators/map.js.map +1 -1
- package/dist/esm/operators/orderBy.d.ts +1 -2
- package/dist/esm/operators/orderBy.js +10 -10
- package/dist/esm/operators/orderBy.js.map +1 -1
- package/dist/esm/operators/output.js +3 -12
- package/dist/esm/operators/output.js.map +1 -1
- package/dist/esm/operators/reduce.js +11 -22
- package/dist/esm/operators/reduce.js.map +1 -1
- package/dist/esm/operators/tap.js +3 -12
- package/dist/esm/operators/tap.js.map +1 -1
- package/dist/esm/operators/topK.d.ts +1 -2
- package/dist/esm/operators/topK.js +4 -4
- package/dist/esm/operators/topK.js.map +1 -1
- package/dist/esm/operators/topKWithFractionalIndex.js +56 -75
- package/dist/esm/operators/topKWithFractionalIndex.js.map +1 -1
- package/package.json +1 -1
- package/src/indexes.ts +54 -0
- package/src/multiset.ts +6 -0
- package/src/operators/filterBy.ts +1 -2
- package/src/operators/groupBy.ts +38 -18
- package/src/operators/join.ts +249 -139
- package/src/operators/orderBy.ts +1 -2
- package/src/operators/topK.ts +1 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topKWithFractionalIndex.cjs","sources":["../../../src/operators/topKWithFractionalIndex.ts"],"sourcesContent":["import { generateKeyBetween } from \"fractional-indexing\"\nimport { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport { binarySearch, globalObjectIdGenerator } from \"../utils.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types.js\"\n\nexport interface TopKWithFractionalIndexOptions {\n limit?: number\n offset?: number\n setSizeCallback?: (getSize: () => number) => void\n}\n\nexport type TopKChanges<V> = {\n /** Indicates which element moves into the topK (if any) */\n moveIn: IndexedValue<V> | null\n /** Indicates which element moves out of the topK (if any) */\n moveOut: IndexedValue<V> | null\n}\n\n/**\n * A topK data structure that supports insertions and deletions\n * and returns changes to the topK.\n */\nexport interface TopK<V> {\n size: number\n insert: (value: V) => TopKChanges<V>\n delete: (value: V) => TopKChanges<V>\n}\n\n/**\n * Implementation of a topK data structure.\n * Uses a sorted array internally to store the values and keeps a topK window over that array.\n * Inserts and deletes are O(n) operations because worst case an element is inserted/deleted\n * at the start of the array which causes all the elements to shift to the right/left.\n */\nclass TopKArray<V> implements TopK<V> {\n #sortedValues: Array<IndexedValue<V>> = []\n #comparator: (a: V, b: V) => number\n #topKStart: number\n #topKEnd: number\n\n constructor(\n offset: number,\n limit: number,\n comparator: (a: V, b: V) => number\n ) {\n this.#topKStart = offset\n this.#topKEnd = offset + limit\n this.#comparator = comparator\n }\n\n get size(): number {\n const offset = this.#topKStart\n const limit = this.#topKEnd - this.#topKStart\n const available = this.#sortedValues.length - offset\n return Math.max(0, Math.min(limit, available))\n }\n\n insert(value: V): TopKChanges<V> {\n const result: TopKChanges<V> = { moveIn: null, moveOut: null }\n\n // Lookup insert position\n const index = this.#findIndex(value)\n // Generate fractional index based on the fractional indices of the elements before and after it\n const indexBefore =\n index === 0 ? null : getIndex(this.#sortedValues[index - 1]!)\n const indexAfter =\n index === this.#sortedValues.length\n ? null\n : getIndex(this.#sortedValues[index]!)\n const fractionalIndex = generateKeyBetween(indexBefore, indexAfter)\n\n // Insert the value at the correct position\n const val = indexedValue(value, fractionalIndex)\n // Splice is O(n) where n = all elements in the collection (i.e. n >= k) !\n this.#sortedValues.splice(index, 0, val)\n\n // Check if the topK changed\n if (index < this.#topKEnd) {\n // The inserted element is either before the top K or within the top K\n // If it is before the top K then it moves the element that was right before the topK into the topK\n // If it is within the top K then the inserted element moves into the top K\n // In both cases the last element of the old top K now moves out of the top K\n const moveInIndex = Math.max(index, this.#topKStart)\n if (moveInIndex < this.#sortedValues.length) {\n // We actually have a topK\n // because in some cases there may not be enough elements in the array to reach the start of the topK\n // e.g. [1, 2, 3] with K = 2 and offset = 3 does not have a topK\n result.moveIn = this.#sortedValues[moveInIndex]!\n\n // We need to remove the element that falls out of the top K\n // The element that falls out of the top K has shifted one to the right\n // because of the element we inserted, so we find it at index topKEnd\n if (this.#topKEnd < this.#sortedValues.length) {\n result.moveOut = this.#sortedValues[this.#topKEnd]!\n }\n }\n }\n\n return result\n }\n\n /**\n * Deletes a value that may or may not be in the topK.\n * IMPORTANT: this assumes that the value is present in the collection\n * if it's not the case it will remove the element\n * that is on the position where the provided `value` would be.\n */\n delete(value: V): TopKChanges<V> {\n const result: TopKChanges<V> = { moveIn: null, moveOut: null }\n\n // Lookup delete position\n const index = this.#findIndex(value)\n // Remove the value at that position\n const [removedElem] = this.#sortedValues.splice(index, 1)\n\n // Check if the topK changed\n if (index < this.#topKEnd) {\n // The removed element is either before the top K or within the top K\n // If it is before the top K then the first element of the topK moves out of the topK\n // If it is within the top K then the removed element moves out of the topK\n result.moveOut = removedElem!\n if (index < this.#topKStart) {\n // The removed element is before the topK\n // so actually, the first element of the topK moves out of the topK\n // and not the element that we removed\n // The first element of the topK is now at index topKStart - 1\n // since we removed an element before the topK\n const moveOutIndex = this.#topKStart - 1\n if (moveOutIndex < this.#sortedValues.length) {\n result.moveOut = this.#sortedValues[moveOutIndex]!\n } else {\n // No value is moving out of the topK\n // because there are no elements in the topK\n result.moveOut = null\n }\n }\n\n // Since we removed an element that was before or in the topK\n // the first element after the topK moved one position to the left\n // and thus falls into the topK now\n const moveInIndex = this.#topKEnd - 1\n if (moveInIndex < this.#sortedValues.length) {\n result.moveIn = this.#sortedValues[moveInIndex]!\n }\n }\n\n return result\n }\n\n // TODO: see if there is a way to refactor the code for insert and delete in the topK above\n // because they are very similar, one is shifting the topK window to the left and the other is shifting it to the right\n // so i have the feeling there is a common pattern here and we can implement both cases using that pattern\n\n #findIndex(value: V): number {\n return binarySearch(this.#sortedValues, indexedValue(value, ``), (a, b) =>\n this.#comparator(getValue(a), getValue(b))\n )\n }\n}\n\n/**\n * Operator for fractional indexed topK operations\n * This operator maintains fractional indices for sorted elements\n * and only updates indices when elements move position\n */\nexport class TopKWithFractionalIndexOperator<K, T> extends UnaryOperator<\n [K, T],\n [K, IndexedValue<T>]\n> {\n #index: Map<K, number> = new Map() // maps keys to their multiplicity\n\n /**\n * topK data structure that supports insertions and deletions\n * and returns changes to the topK.\n */\n #topK: TopK<TaggedValue<K, T>>\n\n #limit: number\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<[K, T]>,\n output: DifferenceStreamWriter<[K, IndexedValue<T>]>,\n comparator: (a: T, b: T) => number,\n options: TopKWithFractionalIndexOptions\n ) {\n super(id, inputA, output)\n this.#limit = options.limit ?? Infinity\n const offset = options.offset ?? 0\n const compareTaggedValues = (\n a: TaggedValue<K, T>,\n b: TaggedValue<K, T>\n ) => {\n // First compare on the value\n const valueComparison = comparator(getVal(a), getVal(b))\n if (valueComparison !== 0) {\n return valueComparison\n }\n // If the values are equal, compare on the tag (object identity)\n const tieBreakerA = getTag(a)\n const tieBreakerB = getTag(b)\n return tieBreakerA - tieBreakerB\n }\n this.#topK = this.createTopK(offset, this.#limit, compareTaggedValues)\n options.setSizeCallback?.(() => this.#topK.size)\n }\n\n protected createTopK(\n offset: number,\n limit: number,\n comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number\n ): TopK<TaggedValue<K, T>> {\n return new TopKArray(offset, limit, comparator)\n }\n\n run(): void {\n const result: Array<[[K, IndexedValue<T>], number]> = []\n for (const message of this.inputMessages()) {\n for (const [item, multiplicity] of message.getInner()) {\n const [key, value] = item\n this.processElement(key, value, multiplicity, result)\n }\n }\n\n if (result.length > 0) {\n this.output.sendData(new MultiSet(result))\n }\n }\n\n processElement(\n key: K,\n value: T,\n multiplicity: number,\n result: Array<[[K, IndexedValue<T>], number]>\n ): void {\n const { oldMultiplicity, newMultiplicity } = this.addKey(key, multiplicity)\n\n let res: TopKChanges<TaggedValue<K, T>> = {\n moveIn: null,\n moveOut: null,\n }\n if (oldMultiplicity <= 0 && newMultiplicity > 0) {\n // The value was invisible but should now be visible\n // Need to insert it into the array of sorted values\n const taggedValue = tagValue(key, value)\n res = this.#topK.insert(taggedValue)\n } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {\n // The value was visible but should now be invisible\n // Need to remove it from the array of sorted values\n const taggedValue = tagValue(key, value)\n res = this.#topK.delete(taggedValue)\n } else {\n // The value was invisible and it remains invisible\n // or it was visible and remains visible\n // so it doesn't affect the topK\n }\n\n if (res.moveIn) {\n const index = getIndex(res.moveIn)\n const taggedValue = getValue(res.moveIn)\n const k = getKey(taggedValue)\n const val = getVal(taggedValue)\n result.push([[k, [val, index]], 1])\n }\n\n if (res.moveOut) {\n const index = getIndex(res.moveOut)\n const taggedValue = getValue(res.moveOut)\n const k = getKey(taggedValue)\n const val = getVal(taggedValue)\n result.push([[k, [val, index]], -1])\n }\n\n return\n }\n\n private getMultiplicity(key: K): number {\n return this.#index.get(key) ?? 0\n }\n\n private addKey(\n key: K,\n multiplicity: number\n ): { oldMultiplicity: number; newMultiplicity: number } {\n const oldMultiplicity = this.getMultiplicity(key)\n const newMultiplicity = oldMultiplicity + multiplicity\n if (newMultiplicity === 0) {\n this.#index.delete(key)\n } else {\n this.#index.set(key, newMultiplicity)\n }\n return { oldMultiplicity, newMultiplicity }\n }\n}\n\n/**\n * Limits the number of results based on a comparator, with optional offset.\n * Uses fractional indexing to minimize the number of changes when elements move positions.\n * Each element is assigned a fractional index that is lexicographically sortable.\n * When elements move, only the indices of the moved elements are updated, not all elements.\n *\n * @param comparator - A function that compares two elements\n * @param options - An optional object containing limit and offset properties\n * @returns A piped operator that orders the elements and limits the number of results\n */\nexport function topKWithFractionalIndex<KType, T>(\n comparator: (a: T, b: T) => number,\n options?: TopKWithFractionalIndexOptions\n): PipedOperator<[KType, T], [KType, IndexedValue<T>]> {\n const opts = options || {}\n\n return (\n stream: IStreamBuilder<[KType, T]>\n ): IStreamBuilder<[KType, IndexedValue<T>]> => {\n const output = new StreamBuilder<[KType, IndexedValue<T>]>(\n stream.graph,\n new DifferenceStreamWriter<[KType, IndexedValue<T>]>()\n )\n const operator = new TopKWithFractionalIndexOperator<KType, T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n comparator,\n opts\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n\n// Abstraction for fractionally indexed values\nexport type FractionalIndex = string\nexport type IndexedValue<V> = [V, FractionalIndex]\n\nexport function indexedValue<V>(\n value: V,\n index: FractionalIndex\n): IndexedValue<V> {\n return [value, index]\n}\n\nexport function getValue<V>(indexedVal: IndexedValue<V>): V {\n return indexedVal[0]\n}\n\nexport function getIndex<V>(indexedVal: IndexedValue<V>): FractionalIndex {\n return indexedVal[1]\n}\n\nexport type Tag = number\nexport type TaggedValue<K, V> = [K, V, Tag]\n\nfunction tagValue<K, V>(key: K, value: V): TaggedValue<K, V> {\n return [key, value, globalObjectIdGenerator.getId(key)]\n}\n\nfunction getKey<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): K {\n return tieBreakerTaggedValue[0]\n}\n\nfunction getVal<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): V {\n return tieBreakerTaggedValue[1]\n}\n\nfunction getTag<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): Tag {\n return tieBreakerTaggedValue[2]\n}\n"],"names":["generateKeyBetween","binarySearch","UnaryOperator","MultiSet","StreamBuilder","DifferenceStreamWriter","globalObjectIdGenerator"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"topKWithFractionalIndex.cjs","sources":["../../../src/operators/topKWithFractionalIndex.ts"],"sourcesContent":["import { generateKeyBetween } from \"fractional-indexing\"\nimport { DifferenceStreamWriter, UnaryOperator } from \"../graph.js\"\nimport { StreamBuilder } from \"../d2.js\"\nimport { MultiSet } from \"../multiset.js\"\nimport { binarySearch, globalObjectIdGenerator } from \"../utils.js\"\nimport type { DifferenceStreamReader } from \"../graph.js\"\nimport type { IStreamBuilder, PipedOperator } from \"../types.js\"\n\nexport interface TopKWithFractionalIndexOptions {\n limit?: number\n offset?: number\n setSizeCallback?: (getSize: () => number) => void\n}\n\nexport type TopKChanges<V> = {\n /** Indicates which element moves into the topK (if any) */\n moveIn: IndexedValue<V> | null\n /** Indicates which element moves out of the topK (if any) */\n moveOut: IndexedValue<V> | null\n}\n\n/**\n * A topK data structure that supports insertions and deletions\n * and returns changes to the topK.\n */\nexport interface TopK<V> {\n size: number\n insert: (value: V) => TopKChanges<V>\n delete: (value: V) => TopKChanges<V>\n}\n\n/**\n * Implementation of a topK data structure.\n * Uses a sorted array internally to store the values and keeps a topK window over that array.\n * Inserts and deletes are O(n) operations because worst case an element is inserted/deleted\n * at the start of the array which causes all the elements to shift to the right/left.\n */\nclass TopKArray<V> implements TopK<V> {\n #sortedValues: Array<IndexedValue<V>> = []\n #comparator: (a: V, b: V) => number\n #topKStart: number\n #topKEnd: number\n\n constructor(\n offset: number,\n limit: number,\n comparator: (a: V, b: V) => number\n ) {\n this.#topKStart = offset\n this.#topKEnd = offset + limit\n this.#comparator = comparator\n }\n\n get size(): number {\n const offset = this.#topKStart\n const limit = this.#topKEnd - this.#topKStart\n const available = this.#sortedValues.length - offset\n return Math.max(0, Math.min(limit, available))\n }\n\n insert(value: V): TopKChanges<V> {\n const result: TopKChanges<V> = { moveIn: null, moveOut: null }\n\n // Lookup insert position\n const index = this.#findIndex(value)\n // Generate fractional index based on the fractional indices of the elements before and after it\n const indexBefore =\n index === 0 ? null : getIndex(this.#sortedValues[index - 1]!)\n const indexAfter =\n index === this.#sortedValues.length\n ? null\n : getIndex(this.#sortedValues[index]!)\n const fractionalIndex = generateKeyBetween(indexBefore, indexAfter)\n\n // Insert the value at the correct position\n const val = indexedValue(value, fractionalIndex)\n // Splice is O(n) where n = all elements in the collection (i.e. n >= k) !\n this.#sortedValues.splice(index, 0, val)\n\n // Check if the topK changed\n if (index < this.#topKEnd) {\n // The inserted element is either before the top K or within the top K\n // If it is before the top K then it moves the element that was right before the topK into the topK\n // If it is within the top K then the inserted element moves into the top K\n // In both cases the last element of the old top K now moves out of the top K\n const moveInIndex = Math.max(index, this.#topKStart)\n if (moveInIndex < this.#sortedValues.length) {\n // We actually have a topK\n // because in some cases there may not be enough elements in the array to reach the start of the topK\n // e.g. [1, 2, 3] with K = 2 and offset = 3 does not have a topK\n result.moveIn = this.#sortedValues[moveInIndex]!\n\n // We need to remove the element that falls out of the top K\n // The element that falls out of the top K has shifted one to the right\n // because of the element we inserted, so we find it at index topKEnd\n if (this.#topKEnd < this.#sortedValues.length) {\n result.moveOut = this.#sortedValues[this.#topKEnd]!\n }\n }\n }\n\n return result\n }\n\n /**\n * Deletes a value that may or may not be in the topK.\n * IMPORTANT: this assumes that the value is present in the collection\n * if it's not the case it will remove the element\n * that is on the position where the provided `value` would be.\n */\n delete(value: V): TopKChanges<V> {\n const result: TopKChanges<V> = { moveIn: null, moveOut: null }\n\n // Lookup delete position\n const index = this.#findIndex(value)\n // Remove the value at that position\n const [removedElem] = this.#sortedValues.splice(index, 1)\n\n // Check if the topK changed\n if (index < this.#topKEnd) {\n // The removed element is either before the top K or within the top K\n // If it is before the top K then the first element of the topK moves out of the topK\n // If it is within the top K then the removed element moves out of the topK\n result.moveOut = removedElem!\n if (index < this.#topKStart) {\n // The removed element is before the topK\n // so actually, the first element of the topK moves out of the topK\n // and not the element that we removed\n // The first element of the topK is now at index topKStart - 1\n // since we removed an element before the topK\n const moveOutIndex = this.#topKStart - 1\n if (moveOutIndex < this.#sortedValues.length) {\n result.moveOut = this.#sortedValues[moveOutIndex]!\n } else {\n // No value is moving out of the topK\n // because there are no elements in the topK\n result.moveOut = null\n }\n }\n\n // Since we removed an element that was before or in the topK\n // the first element after the topK moved one position to the left\n // and thus falls into the topK now\n const moveInIndex = this.#topKEnd - 1\n if (moveInIndex < this.#sortedValues.length) {\n result.moveIn = this.#sortedValues[moveInIndex]!\n }\n }\n\n return result\n }\n\n // TODO: see if there is a way to refactor the code for insert and delete in the topK above\n // because they are very similar, one is shifting the topK window to the left and the other is shifting it to the right\n // so i have the feeling there is a common pattern here and we can implement both cases using that pattern\n\n #findIndex(value: V): number {\n return binarySearch(this.#sortedValues, indexedValue(value, ``), (a, b) =>\n this.#comparator(getValue(a), getValue(b))\n )\n }\n}\n\n/**\n * Operator for fractional indexed topK operations\n * This operator maintains fractional indices for sorted elements\n * and only updates indices when elements move position\n */\nexport class TopKWithFractionalIndexOperator<K, T> extends UnaryOperator<\n [K, T],\n [K, IndexedValue<T>]\n> {\n #index: Map<K, number> = new Map() // maps keys to their multiplicity\n\n /**\n * topK data structure that supports insertions and deletions\n * and returns changes to the topK.\n */\n #topK: TopK<TaggedValue<K, T>>\n\n #limit: number\n\n constructor(\n id: number,\n inputA: DifferenceStreamReader<[K, T]>,\n output: DifferenceStreamWriter<[K, IndexedValue<T>]>,\n comparator: (a: T, b: T) => number,\n options: TopKWithFractionalIndexOptions\n ) {\n super(id, inputA, output)\n this.#limit = options.limit ?? Infinity\n const offset = options.offset ?? 0\n const compareTaggedValues = (\n a: TaggedValue<K, T>,\n b: TaggedValue<K, T>\n ) => {\n // First compare on the value\n const valueComparison = comparator(getVal(a), getVal(b))\n if (valueComparison !== 0) {\n return valueComparison\n }\n // If the values are equal, compare on the tag (object identity)\n const tieBreakerA = getTag(a)\n const tieBreakerB = getTag(b)\n return tieBreakerA - tieBreakerB\n }\n this.#topK = this.createTopK(offset, this.#limit, compareTaggedValues)\n options.setSizeCallback?.(() => this.#topK.size)\n }\n\n protected createTopK(\n offset: number,\n limit: number,\n comparator: (a: TaggedValue<K, T>, b: TaggedValue<K, T>) => number\n ): TopK<TaggedValue<K, T>> {\n return new TopKArray(offset, limit, comparator)\n }\n\n run(): void {\n const result: Array<[[K, IndexedValue<T>], number]> = []\n for (const message of this.inputMessages()) {\n for (const [item, multiplicity] of message.getInner()) {\n const [key, value] = item\n this.processElement(key, value, multiplicity, result)\n }\n }\n\n if (result.length > 0) {\n this.output.sendData(new MultiSet(result))\n }\n }\n\n processElement(\n key: K,\n value: T,\n multiplicity: number,\n result: Array<[[K, IndexedValue<T>], number]>\n ): void {\n const { oldMultiplicity, newMultiplicity } = this.addKey(key, multiplicity)\n\n let res: TopKChanges<TaggedValue<K, T>> = {\n moveIn: null,\n moveOut: null,\n }\n if (oldMultiplicity <= 0 && newMultiplicity > 0) {\n // The value was invisible but should now be visible\n // Need to insert it into the array of sorted values\n const taggedValue = tagValue(key, value)\n res = this.#topK.insert(taggedValue)\n } else if (oldMultiplicity > 0 && newMultiplicity <= 0) {\n // The value was visible but should now be invisible\n // Need to remove it from the array of sorted values\n const taggedValue = tagValue(key, value)\n res = this.#topK.delete(taggedValue)\n } else {\n // The value was invisible and it remains invisible\n // or it was visible and remains visible\n // so it doesn't affect the topK\n }\n\n if (res.moveIn) {\n const index = getIndex(res.moveIn)\n const taggedValue = getValue(res.moveIn)\n const k = getKey(taggedValue)\n const val = getVal(taggedValue)\n result.push([[k, [val, index]], 1])\n }\n\n if (res.moveOut) {\n const index = getIndex(res.moveOut)\n const taggedValue = getValue(res.moveOut)\n const k = getKey(taggedValue)\n const val = getVal(taggedValue)\n result.push([[k, [val, index]], -1])\n }\n\n return\n }\n\n private getMultiplicity(key: K): number {\n return this.#index.get(key) ?? 0\n }\n\n private addKey(\n key: K,\n multiplicity: number\n ): { oldMultiplicity: number; newMultiplicity: number } {\n const oldMultiplicity = this.getMultiplicity(key)\n const newMultiplicity = oldMultiplicity + multiplicity\n if (newMultiplicity === 0) {\n this.#index.delete(key)\n } else {\n this.#index.set(key, newMultiplicity)\n }\n return { oldMultiplicity, newMultiplicity }\n }\n}\n\n/**\n * Limits the number of results based on a comparator, with optional offset.\n * Uses fractional indexing to minimize the number of changes when elements move positions.\n * Each element is assigned a fractional index that is lexicographically sortable.\n * When elements move, only the indices of the moved elements are updated, not all elements.\n *\n * @param comparator - A function that compares two elements\n * @param options - An optional object containing limit and offset properties\n * @returns A piped operator that orders the elements and limits the number of results\n */\nexport function topKWithFractionalIndex<KType, T>(\n comparator: (a: T, b: T) => number,\n options?: TopKWithFractionalIndexOptions\n): PipedOperator<[KType, T], [KType, IndexedValue<T>]> {\n const opts = options || {}\n\n return (\n stream: IStreamBuilder<[KType, T]>\n ): IStreamBuilder<[KType, IndexedValue<T>]> => {\n const output = new StreamBuilder<[KType, IndexedValue<T>]>(\n stream.graph,\n new DifferenceStreamWriter<[KType, IndexedValue<T>]>()\n )\n const operator = new TopKWithFractionalIndexOperator<KType, T>(\n stream.graph.getNextOperatorId(),\n stream.connectReader(),\n output.writer,\n comparator,\n opts\n )\n stream.graph.addOperator(operator)\n return output\n }\n}\n\n// Abstraction for fractionally indexed values\nexport type FractionalIndex = string\nexport type IndexedValue<V> = [V, FractionalIndex]\n\nexport function indexedValue<V>(\n value: V,\n index: FractionalIndex\n): IndexedValue<V> {\n return [value, index]\n}\n\nexport function getValue<V>(indexedVal: IndexedValue<V>): V {\n return indexedVal[0]\n}\n\nexport function getIndex<V>(indexedVal: IndexedValue<V>): FractionalIndex {\n return indexedVal[1]\n}\n\nexport type Tag = number\nexport type TaggedValue<K, V> = [K, V, Tag]\n\nfunction tagValue<K, V>(key: K, value: V): TaggedValue<K, V> {\n return [key, value, globalObjectIdGenerator.getId(key)]\n}\n\nfunction getKey<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): K {\n return tieBreakerTaggedValue[0]\n}\n\nfunction getVal<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): V {\n return tieBreakerTaggedValue[1]\n}\n\nfunction getTag<K, V>(tieBreakerTaggedValue: TaggedValue<K, V>): Tag {\n return tieBreakerTaggedValue[2]\n}\n"],"names":["generateKeyBetween","binarySearch","UnaryOperator","MultiSet","StreamBuilder","DifferenceStreamWriter","globalObjectIdGenerator"],"mappings":"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"}
|
package/dist/esm/d2.js
CHANGED
|
@@ -1,56 +1,43 @@
|
|
|
1
|
-
var __typeError = (msg) => {
|
|
2
|
-
throw TypeError(msg);
|
|
3
|
-
};
|
|
4
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
5
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
-
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
9
|
-
var __privateWrapper = (obj, member, setter, getter) => ({
|
|
10
|
-
set _(value) {
|
|
11
|
-
__privateSet(obj, member, value, setter);
|
|
12
|
-
},
|
|
13
|
-
get _() {
|
|
14
|
-
return __privateGet(obj, member, getter);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
var _operators, _nextOperatorId, _finalized, _D2_instances, checkNotFinalized_fn, _graph, _writer;
|
|
18
1
|
import { DifferenceStreamWriter } from "./graph.js";
|
|
19
2
|
class D2 {
|
|
3
|
+
#operators = [];
|
|
4
|
+
#nextOperatorId = 0;
|
|
5
|
+
#finalized = false;
|
|
20
6
|
constructor() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
}
|
|
8
|
+
#checkNotFinalized() {
|
|
9
|
+
if (this.#finalized) {
|
|
10
|
+
throw new Error(`Graph already finalized`);
|
|
11
|
+
}
|
|
25
12
|
}
|
|
26
13
|
getNextOperatorId() {
|
|
27
|
-
|
|
28
|
-
return
|
|
14
|
+
this.#checkNotFinalized();
|
|
15
|
+
return this.#nextOperatorId++;
|
|
29
16
|
}
|
|
30
17
|
newInput() {
|
|
31
|
-
|
|
18
|
+
this.#checkNotFinalized();
|
|
32
19
|
const writer = new DifferenceStreamWriter();
|
|
33
20
|
const streamBuilder = new RootStreamBuilder(this, writer);
|
|
34
21
|
return streamBuilder;
|
|
35
22
|
}
|
|
36
23
|
addOperator(operator) {
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
this.#checkNotFinalized();
|
|
25
|
+
this.#operators.push(operator);
|
|
39
26
|
}
|
|
40
27
|
finalize() {
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
this.#checkNotFinalized();
|
|
29
|
+
this.#finalized = true;
|
|
43
30
|
}
|
|
44
31
|
step() {
|
|
45
|
-
if (!
|
|
32
|
+
if (!this.#finalized) {
|
|
46
33
|
throw new Error(`Graph not finalized`);
|
|
47
34
|
}
|
|
48
|
-
for (const op of
|
|
35
|
+
for (const op of this.#operators) {
|
|
49
36
|
op.run();
|
|
50
37
|
}
|
|
51
38
|
}
|
|
52
39
|
pendingWork() {
|
|
53
|
-
return
|
|
40
|
+
return this.#operators.some((op) => op.hasPendingWork());
|
|
54
41
|
}
|
|
55
42
|
run() {
|
|
56
43
|
while (this.pendingWork()) {
|
|
@@ -58,30 +45,21 @@ class D2 {
|
|
|
58
45
|
}
|
|
59
46
|
}
|
|
60
47
|
}
|
|
61
|
-
_operators = new WeakMap();
|
|
62
|
-
_nextOperatorId = new WeakMap();
|
|
63
|
-
_finalized = new WeakMap();
|
|
64
|
-
_D2_instances = new WeakSet();
|
|
65
|
-
checkNotFinalized_fn = function() {
|
|
66
|
-
if (__privateGet(this, _finalized)) {
|
|
67
|
-
throw new Error(`Graph already finalized`);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
48
|
class StreamBuilder {
|
|
49
|
+
#graph;
|
|
50
|
+
#writer;
|
|
71
51
|
constructor(graph, writer) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
__privateSet(this, _graph, graph);
|
|
75
|
-
__privateSet(this, _writer, writer);
|
|
52
|
+
this.#graph = graph;
|
|
53
|
+
this.#writer = writer;
|
|
76
54
|
}
|
|
77
55
|
connectReader() {
|
|
78
|
-
return
|
|
56
|
+
return this.#writer.newReader();
|
|
79
57
|
}
|
|
80
58
|
get writer() {
|
|
81
|
-
return
|
|
59
|
+
return this.#writer;
|
|
82
60
|
}
|
|
83
61
|
get graph() {
|
|
84
|
-
return
|
|
62
|
+
return this.#graph;
|
|
85
63
|
}
|
|
86
64
|
pipe(...operators) {
|
|
87
65
|
return operators.reduce((stream, operator) => {
|
|
@@ -89,8 +67,6 @@ class StreamBuilder {
|
|
|
89
67
|
}, this);
|
|
90
68
|
}
|
|
91
69
|
}
|
|
92
|
-
_graph = new WeakMap();
|
|
93
|
-
_writer = new WeakMap();
|
|
94
70
|
class RootStreamBuilder extends StreamBuilder {
|
|
95
71
|
sendData(collection) {
|
|
96
72
|
this.writer.sendData(collection);
|
package/dist/esm/d2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"d2.js","sources":["../../src/d2.ts"],"sourcesContent":["import { DifferenceStreamWriter } from \"./graph.js\"\nimport type {\n BinaryOperator,\n DifferenceStreamReader,\n UnaryOperator,\n} from \"./graph.js\"\nimport type { MultiSet, MultiSetArray } from \"./multiset.js\"\nimport type { ID2, IStreamBuilder, PipedOperator } from \"./types.js\"\n\nexport class D2 implements ID2 {\n #operators: Array<UnaryOperator<any> | BinaryOperator<any>> = []\n #nextOperatorId = 0\n #finalized = false\n\n constructor() {}\n\n #checkNotFinalized(): void {\n if (this.#finalized) {\n throw new Error(`Graph already finalized`)\n }\n }\n\n getNextOperatorId(): number {\n this.#checkNotFinalized()\n return this.#nextOperatorId++\n }\n\n newInput<T>(): RootStreamBuilder<T> {\n this.#checkNotFinalized()\n const writer = new DifferenceStreamWriter<T>()\n // Use the root stream builder that exposes the sendData and sendFrontier methods\n const streamBuilder = new RootStreamBuilder<T>(this, writer)\n return streamBuilder\n }\n\n addOperator(operator: UnaryOperator<any> | BinaryOperator<any>): void {\n this.#checkNotFinalized()\n this.#operators.push(operator)\n }\n\n finalize() {\n this.#checkNotFinalized()\n this.#finalized = true\n }\n\n step(): void {\n if (!this.#finalized) {\n throw new Error(`Graph not finalized`)\n }\n for (const op of this.#operators) {\n op.run()\n }\n }\n\n pendingWork(): boolean {\n return this.#operators.some((op) => op.hasPendingWork())\n }\n\n run(): void {\n while (this.pendingWork()) {\n this.step()\n }\n }\n}\n\nexport class StreamBuilder<T> implements IStreamBuilder<T> {\n #graph: ID2\n #writer: DifferenceStreamWriter<T>\n\n constructor(graph: ID2, writer: DifferenceStreamWriter<T>) {\n this.#graph = graph\n this.#writer = writer\n }\n\n connectReader(): DifferenceStreamReader<T> {\n return this.#writer.newReader()\n }\n\n get writer(): DifferenceStreamWriter<T> {\n return this.#writer\n }\n\n get graph(): ID2 {\n return this.#graph\n }\n\n // Don't judge, this is the only way to type this function.\n // rxjs has very similar code to type its pipe function\n // https://github.com/ReactiveX/rxjs/blob/master/packages/rxjs/src/internal/util/pipe.ts\n // We go to 20 operators deep, because surly that's enough for anyone...\n // A user can always split the pipe into multiple pipes to get around this.\n pipe<O>(o1: PipedOperator<T, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, T19>, o19: PipedOperator<T19, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, T19>, o19: PipedOperator<T19, T20>, o20: PipedOperator<T20, O>): IStreamBuilder<O>\n\n pipe(...operators: Array<PipedOperator<any, any>>): IStreamBuilder<any> {\n return operators.reduce((stream, operator) => {\n return operator(stream)\n }, this as IStreamBuilder<any>)\n }\n}\n\nexport class RootStreamBuilder<T> extends StreamBuilder<T> {\n sendData(collection: MultiSet<T> | MultiSetArray<T>): void {\n this.writer.sendData(collection)\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AASO,MAAM,GAAkB;AAAA,EAK7B,cAAc;AALT;AACL,mCAA8D,CAAA;AAC9D,wCAAkB;AAClB,mCAAa;AAAA,EAEE;AAAA,EAQf,oBAA4B;AAC1B,0BAAK,qCAAL;AACA,WAAO,uBAAK,iBAAL;AAAA,EACT;AAAA,EAEA,WAAoC;AAClC,0BAAK,qCAAL;AACA,UAAM,SAAS,IAAI,uBAAA;AAEnB,UAAM,gBAAgB,IAAI,kBAAqB,MAAM,MAAM;AAC3D,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,UAA0D;AACpE,0BAAK,qCAAL;AACA,uBAAK,YAAW,KAAK,QAAQ;AAAA,EAC/B;AAAA,EAEA,WAAW;AACT,0BAAK,qCAAL;AACA,uBAAK,YAAa;AAAA,EACpB;AAAA,EAEA,OAAa;AACX,QAAI,CAAC,mBAAK,aAAY;AACpB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AACA,eAAW,MAAM,mBAAK,aAAY;AAChC,SAAG,IAAA;AAAA,IACL;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAO,mBAAK,YAAW,KAAK,CAAC,OAAO,GAAG,gBAAgB;AAAA,EACzD;AAAA,EAEA,MAAY;AACV,WAAO,KAAK,eAAe;AACzB,WAAK,KAAA;AAAA,IACP;AAAA,EACF;AACF;AArDE;AACA;AACA;AAHK;AAOL,uBAAA,WAA2B;AACzB,MAAI,mBAAK,aAAY;AACnB,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AACF;AA6CK,MAAM,cAA8C;AAAA,EAIzD,YAAY,OAAY,QAAmC;AAH3D;AACA;AAGE,uBAAK,QAAS;AACd,uBAAK,SAAU;AAAA,EACjB;AAAA,EAEA,gBAA2C;AACzC,WAAO,mBAAK,SAAQ,UAAA;AAAA,EACtB;AAAA,EAEA,IAAI,SAAoC;AACtC,WAAO,mBAAK;AAAA,EACd;AAAA,EAEA,IAAI,QAAa;AACf,WAAO,mBAAK;AAAA,EACd;AAAA,EA+CA,QAAQ,WAAgE;AACtE,WAAO,UAAU,OAAO,CAAC,QAAQ,aAAa;AAC5C,aAAO,SAAS,MAAM;AAAA,IACxB,GAAG,IAA2B;AAAA,EAChC;AACF;AAtEE;AACA;AAuEK,MAAM,0BAA6B,cAAiB;AAAA,EACzD,SAAS,YAAkD;AACzD,SAAK,OAAO,SAAS,UAAU;AAAA,EACjC;AACF;"}
|
|
1
|
+
{"version":3,"file":"d2.js","sources":["../../src/d2.ts"],"sourcesContent":["import { DifferenceStreamWriter } from \"./graph.js\"\nimport type {\n BinaryOperator,\n DifferenceStreamReader,\n UnaryOperator,\n} from \"./graph.js\"\nimport type { MultiSet, MultiSetArray } from \"./multiset.js\"\nimport type { ID2, IStreamBuilder, PipedOperator } from \"./types.js\"\n\nexport class D2 implements ID2 {\n #operators: Array<UnaryOperator<any> | BinaryOperator<any>> = []\n #nextOperatorId = 0\n #finalized = false\n\n constructor() {}\n\n #checkNotFinalized(): void {\n if (this.#finalized) {\n throw new Error(`Graph already finalized`)\n }\n }\n\n getNextOperatorId(): number {\n this.#checkNotFinalized()\n return this.#nextOperatorId++\n }\n\n newInput<T>(): RootStreamBuilder<T> {\n this.#checkNotFinalized()\n const writer = new DifferenceStreamWriter<T>()\n // Use the root stream builder that exposes the sendData and sendFrontier methods\n const streamBuilder = new RootStreamBuilder<T>(this, writer)\n return streamBuilder\n }\n\n addOperator(operator: UnaryOperator<any> | BinaryOperator<any>): void {\n this.#checkNotFinalized()\n this.#operators.push(operator)\n }\n\n finalize() {\n this.#checkNotFinalized()\n this.#finalized = true\n }\n\n step(): void {\n if (!this.#finalized) {\n throw new Error(`Graph not finalized`)\n }\n for (const op of this.#operators) {\n op.run()\n }\n }\n\n pendingWork(): boolean {\n return this.#operators.some((op) => op.hasPendingWork())\n }\n\n run(): void {\n while (this.pendingWork()) {\n this.step()\n }\n }\n}\n\nexport class StreamBuilder<T> implements IStreamBuilder<T> {\n #graph: ID2\n #writer: DifferenceStreamWriter<T>\n\n constructor(graph: ID2, writer: DifferenceStreamWriter<T>) {\n this.#graph = graph\n this.#writer = writer\n }\n\n connectReader(): DifferenceStreamReader<T> {\n return this.#writer.newReader()\n }\n\n get writer(): DifferenceStreamWriter<T> {\n return this.#writer\n }\n\n get graph(): ID2 {\n return this.#graph\n }\n\n // Don't judge, this is the only way to type this function.\n // rxjs has very similar code to type its pipe function\n // https://github.com/ReactiveX/rxjs/blob/master/packages/rxjs/src/internal/util/pipe.ts\n // We go to 20 operators deep, because surly that's enough for anyone...\n // A user can always split the pipe into multiple pipes to get around this.\n pipe<O>(o1: PipedOperator<T, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, T19>, o19: PipedOperator<T19, O>): IStreamBuilder<O>\n // prettier-ignore\n pipe<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, O>(o1: PipedOperator<T, T2>, o2: PipedOperator<T2, T3>, o3: PipedOperator<T3, T4>, o4: PipedOperator<T4, T5>, o5: PipedOperator<T5, T6>, o6: PipedOperator<T6, T7>, o7: PipedOperator<T7, T8>, o8: PipedOperator<T8, T9>, o9: PipedOperator<T9, T10>, o10: PipedOperator<T10, T11>, o11: PipedOperator<T11, T12>, o12: PipedOperator<T12, T13>, o13: PipedOperator<T13, T14>, o14: PipedOperator<T14, T15>, o15: PipedOperator<T15, T16>, o16: PipedOperator<T16, T17>, o17: PipedOperator<T17, T18>, o18: PipedOperator<T18, T19>, o19: PipedOperator<T19, T20>, o20: PipedOperator<T20, O>): IStreamBuilder<O>\n\n pipe(...operators: Array<PipedOperator<any, any>>): IStreamBuilder<any> {\n return operators.reduce((stream, operator) => {\n return operator(stream)\n }, this as IStreamBuilder<any>)\n }\n}\n\nexport class RootStreamBuilder<T> extends StreamBuilder<T> {\n sendData(collection: MultiSet<T> | MultiSetArray<T>): void {\n this.writer.sendData(collection)\n }\n}\n"],"names":[],"mappings":";AASO,MAAM,GAAkB;AAAA,EAC7B,aAA8D,CAAA;AAAA,EAC9D,kBAAkB;AAAA,EAClB,aAAa;AAAA,EAEb,cAAc;AAAA,EAAC;AAAA,EAEf,qBAA2B;AACzB,QAAI,KAAK,YAAY;AACnB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,oBAA4B;AAC1B,SAAK,mBAAA;AACL,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAoC;AAClC,SAAK,mBAAA;AACL,UAAM,SAAS,IAAI,uBAAA;AAEnB,UAAM,gBAAgB,IAAI,kBAAqB,MAAM,MAAM;AAC3D,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,UAA0D;AACpE,SAAK,mBAAA;AACL,SAAK,WAAW,KAAK,QAAQ;AAAA,EAC/B;AAAA,EAEA,WAAW;AACT,SAAK,mBAAA;AACL,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,OAAa;AACX,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AACA,eAAW,MAAM,KAAK,YAAY;AAChC,SAAG,IAAA;AAAA,IACL;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,WAAW,KAAK,CAAC,OAAO,GAAG,gBAAgB;AAAA,EACzD;AAAA,EAEA,MAAY;AACV,WAAO,KAAK,eAAe;AACzB,WAAK,KAAA;AAAA,IACP;AAAA,EACF;AACF;AAEO,MAAM,cAA8C;AAAA,EACzD;AAAA,EACA;AAAA,EAEA,YAAY,OAAY,QAAmC;AACzD,SAAK,SAAS;AACd,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,gBAA2C;AACzC,WAAO,KAAK,QAAQ,UAAA;AAAA,EACtB;AAAA,EAEA,IAAI,SAAoC;AACtC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,QAAa;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EA+CA,QAAQ,WAAgE;AACtE,WAAO,UAAU,OAAO,CAAC,QAAQ,aAAa;AAC5C,aAAO,SAAS,MAAM;AAAA,IACxB,GAAG,IAA2B;AAAA,EAChC;AACF;AAEO,MAAM,0BAA6B,cAAiB;AAAA,EACzD,SAAS,YAAkD;AACzD,SAAK,OAAO,SAAS,UAAU;AAAA,EACjC;AACF;"}
|
package/dist/esm/graph.js
CHANGED
|
@@ -1,46 +1,34 @@
|
|
|
1
|
-
var __typeError = (msg) => {
|
|
2
|
-
throw TypeError(msg);
|
|
3
|
-
};
|
|
4
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
5
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
-
var _queue, _queues;
|
|
9
1
|
import { MultiSet } from "./multiset.js";
|
|
10
2
|
class DifferenceStreamReader {
|
|
3
|
+
#queue;
|
|
11
4
|
constructor(queue) {
|
|
12
|
-
|
|
13
|
-
__privateSet(this, _queue, queue);
|
|
5
|
+
this.#queue = queue;
|
|
14
6
|
}
|
|
15
7
|
drain() {
|
|
16
|
-
const out = [...
|
|
17
|
-
|
|
8
|
+
const out = [...this.#queue].reverse();
|
|
9
|
+
this.#queue.length = 0;
|
|
18
10
|
return out;
|
|
19
11
|
}
|
|
20
12
|
isEmpty() {
|
|
21
|
-
return
|
|
13
|
+
return this.#queue.length === 0;
|
|
22
14
|
}
|
|
23
15
|
}
|
|
24
|
-
_queue = new WeakMap();
|
|
25
16
|
class DifferenceStreamWriter {
|
|
26
|
-
|
|
27
|
-
__privateAdd(this, _queues, []);
|
|
28
|
-
}
|
|
17
|
+
#queues = [];
|
|
29
18
|
sendData(collection) {
|
|
30
19
|
if (!(collection instanceof MultiSet)) {
|
|
31
20
|
collection = new MultiSet(collection);
|
|
32
21
|
}
|
|
33
|
-
for (const q of
|
|
22
|
+
for (const q of this.#queues) {
|
|
34
23
|
q.unshift(collection);
|
|
35
24
|
}
|
|
36
25
|
}
|
|
37
26
|
newReader() {
|
|
38
27
|
const q = [];
|
|
39
|
-
|
|
28
|
+
this.#queues.push(q);
|
|
40
29
|
return new DifferenceStreamReader(q);
|
|
41
30
|
}
|
|
42
31
|
}
|
|
43
|
-
_queues = new WeakMap();
|
|
44
32
|
class Operator {
|
|
45
33
|
constructor(id, inputs, output) {
|
|
46
34
|
this.id = id;
|
package/dist/esm/graph.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.js","sources":["../../src/graph.ts"],"sourcesContent":["import { MultiSet } from \"./multiset.js\"\nimport type { MultiSetArray } from \"./multiset.js\"\nimport type {\n IDifferenceStreamReader,\n IDifferenceStreamWriter,\n IOperator,\n} from \"./types.js\"\n\n/**\n * A read handle to a dataflow edge that receives data from a writer.\n */\nexport class DifferenceStreamReader<T> implements IDifferenceStreamReader<T> {\n #queue: Array<MultiSet<T>>\n\n constructor(queue: Array<MultiSet<T>>) {\n this.#queue = queue\n }\n\n drain(): Array<MultiSet<T>> {\n const out = [...this.#queue].reverse()\n this.#queue.length = 0\n return out\n }\n\n isEmpty(): boolean {\n return this.#queue.length === 0\n }\n}\n\n/**\n * A write handle to a dataflow edge that is allowed to publish data.\n */\nexport class DifferenceStreamWriter<T> implements IDifferenceStreamWriter<T> {\n #queues: Array<Array<MultiSet<T>>> = []\n\n sendData(collection: MultiSet<T> | MultiSetArray<T>): void {\n if (!(collection instanceof MultiSet)) {\n collection = new MultiSet(collection)\n }\n\n for (const q of this.#queues) {\n q.unshift(collection)\n }\n }\n\n newReader(): DifferenceStreamReader<T> {\n const q: Array<MultiSet<T>> = []\n this.#queues.push(q)\n return new DifferenceStreamReader(q)\n }\n}\n\n/**\n * A generic implementation of a dataflow operator (node) that has multiple incoming edges (read handles) and\n * one outgoing edge (write handle).\n */\nexport abstract class Operator<T> implements IOperator<T> {\n protected inputs: Array<DifferenceStreamReader<T>>\n protected output: DifferenceStreamWriter<T>\n\n constructor(\n public id: number,\n inputs: Array<DifferenceStreamReader<T>>,\n output: DifferenceStreamWriter<T>\n ) {\n this.inputs = inputs\n this.output = output\n }\n\n abstract run(): void\n\n hasPendingWork(): boolean {\n return this.inputs.some((input) => !input.isEmpty())\n }\n}\n\n/**\n * A convenience implementation of a dataflow operator that has a handle to one\n * incoming stream of data, and one handle to an outgoing stream of data.\n */\nexport abstract class UnaryOperator<Tin, Tout = Tin> extends Operator<\n Tin | Tout\n> {\n constructor(\n public id: number,\n inputA: DifferenceStreamReader<Tin>,\n output: DifferenceStreamWriter<Tout>\n ) {\n super(id, [inputA], output)\n }\n\n inputMessages(): Array<MultiSet<Tin>> {\n return this.inputs[0]!.drain() as Array<MultiSet<Tin>>\n }\n}\n\n/**\n * A convenience implementation of a dataflow operator that has a handle to two\n * incoming streams of data, and one handle to an outgoing stream of data.\n */\nexport abstract class BinaryOperator<T> extends Operator<T> {\n constructor(\n public id: number,\n inputA: DifferenceStreamReader<T>,\n inputB: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>\n ) {\n super(id, [inputA, inputB], output)\n }\n\n inputAMessages(): Array<MultiSet<T>> {\n return this.inputs[0]!.drain()\n }\n\n inputBMessages(): Array<MultiSet<T>> {\n return this.inputs[1]!.drain()\n }\n}\n\n/**\n * Base class for operators that process a single input stream\n */\nexport abstract class LinearUnaryOperator<T, U> extends UnaryOperator<T | U> {\n abstract inner(collection: MultiSet<T | U>): MultiSet<U>\n\n run(): void {\n for (const message of this.inputMessages()) {\n this.output.sendData(this.inner(message))\n }\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graph.js","sources":["../../src/graph.ts"],"sourcesContent":["import { MultiSet } from \"./multiset.js\"\nimport type { MultiSetArray } from \"./multiset.js\"\nimport type {\n IDifferenceStreamReader,\n IDifferenceStreamWriter,\n IOperator,\n} from \"./types.js\"\n\n/**\n * A read handle to a dataflow edge that receives data from a writer.\n */\nexport class DifferenceStreamReader<T> implements IDifferenceStreamReader<T> {\n #queue: Array<MultiSet<T>>\n\n constructor(queue: Array<MultiSet<T>>) {\n this.#queue = queue\n }\n\n drain(): Array<MultiSet<T>> {\n const out = [...this.#queue].reverse()\n this.#queue.length = 0\n return out\n }\n\n isEmpty(): boolean {\n return this.#queue.length === 0\n }\n}\n\n/**\n * A write handle to a dataflow edge that is allowed to publish data.\n */\nexport class DifferenceStreamWriter<T> implements IDifferenceStreamWriter<T> {\n #queues: Array<Array<MultiSet<T>>> = []\n\n sendData(collection: MultiSet<T> | MultiSetArray<T>): void {\n if (!(collection instanceof MultiSet)) {\n collection = new MultiSet(collection)\n }\n\n for (const q of this.#queues) {\n q.unshift(collection)\n }\n }\n\n newReader(): DifferenceStreamReader<T> {\n const q: Array<MultiSet<T>> = []\n this.#queues.push(q)\n return new DifferenceStreamReader(q)\n }\n}\n\n/**\n * A generic implementation of a dataflow operator (node) that has multiple incoming edges (read handles) and\n * one outgoing edge (write handle).\n */\nexport abstract class Operator<T> implements IOperator<T> {\n protected inputs: Array<DifferenceStreamReader<T>>\n protected output: DifferenceStreamWriter<T>\n\n constructor(\n public id: number,\n inputs: Array<DifferenceStreamReader<T>>,\n output: DifferenceStreamWriter<T>\n ) {\n this.inputs = inputs\n this.output = output\n }\n\n abstract run(): void\n\n hasPendingWork(): boolean {\n return this.inputs.some((input) => !input.isEmpty())\n }\n}\n\n/**\n * A convenience implementation of a dataflow operator that has a handle to one\n * incoming stream of data, and one handle to an outgoing stream of data.\n */\nexport abstract class UnaryOperator<Tin, Tout = Tin> extends Operator<\n Tin | Tout\n> {\n constructor(\n public id: number,\n inputA: DifferenceStreamReader<Tin>,\n output: DifferenceStreamWriter<Tout>\n ) {\n super(id, [inputA], output)\n }\n\n inputMessages(): Array<MultiSet<Tin>> {\n return this.inputs[0]!.drain() as Array<MultiSet<Tin>>\n }\n}\n\n/**\n * A convenience implementation of a dataflow operator that has a handle to two\n * incoming streams of data, and one handle to an outgoing stream of data.\n */\nexport abstract class BinaryOperator<T> extends Operator<T> {\n constructor(\n public id: number,\n inputA: DifferenceStreamReader<T>,\n inputB: DifferenceStreamReader<T>,\n output: DifferenceStreamWriter<T>\n ) {\n super(id, [inputA, inputB], output)\n }\n\n inputAMessages(): Array<MultiSet<T>> {\n return this.inputs[0]!.drain()\n }\n\n inputBMessages(): Array<MultiSet<T>> {\n return this.inputs[1]!.drain()\n }\n}\n\n/**\n * Base class for operators that process a single input stream\n */\nexport abstract class LinearUnaryOperator<T, U> extends UnaryOperator<T | U> {\n abstract inner(collection: MultiSet<T | U>): MultiSet<U>\n\n run(): void {\n for (const message of this.inputMessages()) {\n this.output.sendData(this.inner(message))\n }\n }\n}\n"],"names":[],"mappings":";AAWO,MAAM,uBAAgE;AAAA,EAC3E;AAAA,EAEA,YAAY,OAA2B;AACrC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,QAA4B;AAC1B,UAAM,MAAM,CAAC,GAAG,KAAK,MAAM,EAAE,QAAA;AAC7B,SAAK,OAAO,SAAS;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,OAAO,WAAW;AAAA,EAChC;AACF;AAKO,MAAM,uBAAgE;AAAA,EAC3E,UAAqC,CAAA;AAAA,EAErC,SAAS,YAAkD;AACzD,QAAI,EAAE,sBAAsB,WAAW;AACrC,mBAAa,IAAI,SAAS,UAAU;AAAA,IACtC;AAEA,eAAW,KAAK,KAAK,SAAS;AAC5B,QAAE,QAAQ,UAAU;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,YAAuC;AACrC,UAAM,IAAwB,CAAA;AAC9B,SAAK,QAAQ,KAAK,CAAC;AACnB,WAAO,IAAI,uBAAuB,CAAC;AAAA,EACrC;AACF;AAMO,MAAe,SAAoC;AAAA,EAIxD,YACS,IACP,QACA,QACA;AAHO,SAAA,KAAA;AAIP,SAAK,SAAS;AACd,SAAK,SAAS;AAAA,EAChB;AAAA,EAIA,iBAA0B;AACxB,WAAO,KAAK,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,SAAS;AAAA,EACrD;AACF;AAMO,MAAe,sBAAuC,SAE3D;AAAA,EACA,YACS,IACP,QACA,QACA;AACA,UAAM,IAAI,CAAC,MAAM,GAAG,MAAM;AAJnB,SAAA,KAAA;AAAA,EAKT;AAAA,EAEA,gBAAsC;AACpC,WAAO,KAAK,OAAO,CAAC,EAAG,MAAA;AAAA,EACzB;AACF;AAMO,MAAe,uBAA0B,SAAY;AAAA,EAC1D,YACS,IACP,QACA,QACA,QACA;AACA,UAAM,IAAI,CAAC,QAAQ,MAAM,GAAG,MAAM;AAL3B,SAAA,KAAA;AAAA,EAMT;AAAA,EAEA,iBAAqC;AACnC,WAAO,KAAK,OAAO,CAAC,EAAG,MAAA;AAAA,EACzB;AAAA,EAEA,iBAAqC;AACnC,WAAO,KAAK,OAAO,CAAC,EAAG,MAAA;AAAA,EACzB;AACF;AAKO,MAAe,4BAAkC,cAAqB;AAAA,EAG3E,MAAY;AACV,eAAW,WAAW,KAAK,iBAAiB;AAC1C,WAAK,OAAO,SAAS,KAAK,MAAM,OAAO,CAAC;AAAA,IAC1C;AAAA,EACF;AACF;"}
|
package/dist/esm/indexes.d.ts
CHANGED
|
@@ -8,6 +8,12 @@ type SingleValue<TValue> = [TValue, number];
|
|
|
8
8
|
export declare class Index<TKey, TValue, TPrefix = any> {
|
|
9
9
|
#private;
|
|
10
10
|
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Create an Index from multiple MultiSet messages.
|
|
13
|
+
* @param messages - Array of MultiSet messages to build the index from.
|
|
14
|
+
* @returns A new Index containing all the data from the messages.
|
|
15
|
+
*/
|
|
16
|
+
static fromMultiSets<K, V>(messages: Array<MultiSet<[K, V]>>): Index<K, V>;
|
|
11
17
|
/**
|
|
12
18
|
* This method returns a string representation of the index.
|
|
13
19
|
* @param indent - Whether to indent the string representation.
|
|
@@ -24,6 +30,23 @@ export declare class Index<TKey, TValue, TPrefix = any> {
|
|
|
24
30
|
* @returns True if the index has the key, false otherwise.
|
|
25
31
|
*/
|
|
26
32
|
has(key: TKey): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a key has presence (non-zero consolidated multiplicity).
|
|
35
|
+
* @param key - The key to check.
|
|
36
|
+
* @returns True if the key has non-zero consolidated multiplicity, false otherwise.
|
|
37
|
+
*/
|
|
38
|
+
hasPresence(key: TKey): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Get the consolidated multiplicity (sum of multiplicities) for a key.
|
|
41
|
+
* @param key - The key to get the consolidated multiplicity for.
|
|
42
|
+
* @returns The consolidated multiplicity for the key.
|
|
43
|
+
*/
|
|
44
|
+
getConsolidatedMultiplicity(key: TKey): number;
|
|
45
|
+
/**
|
|
46
|
+
* Get all keys that have presence (non-zero consolidated multiplicity).
|
|
47
|
+
* @returns An iterator of keys with non-zero consolidated multiplicity.
|
|
48
|
+
*/
|
|
49
|
+
getPresenceKeys(): Iterable<TKey>;
|
|
27
50
|
/**
|
|
28
51
|
* This method returns all values for a given key.
|
|
29
52
|
* @param key - The key to get the values for.
|