@zengrid/shared 1.0.2 → 1.0.4
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/index.cjs.js +1157 -13
- package/dist/index.esm.js +1137 -1
- package/dist/package.json +1 -1
- package/dist/src/algorithms/filter/bloom-filter.d.ts.map +1 -1
- package/dist/src/algorithms/filter/index.d.ts.map +1 -1
- package/dist/src/algorithms/graph/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/graph/dfs.d.ts.map +1 -1
- package/dist/src/algorithms/graph/graph.interface.d.ts.map +1 -1
- package/dist/src/algorithms/graph/index.d.ts.map +1 -1
- package/dist/src/algorithms/index.d.ts.map +1 -1
- package/dist/src/algorithms/pattern/index.d.ts.map +1 -1
- package/dist/src/algorithms/pattern/sequence-detector.d.ts.map +1 -1
- package/dist/src/algorithms/search/binary-search.d.ts.map +1 -1
- package/dist/src/algorithms/search/index.d.ts.map +1 -1
- package/dist/src/algorithms/sorting/comparators.d.ts.map +1 -1
- package/dist/src/algorithms/sorting/index.d.ts.map +1 -1
- package/dist/src/algorithms/sorting/sorting.interface.d.ts.map +1 -1
- package/dist/src/algorithms/sorting/timsort.d.ts.map +1 -1
- package/dist/src/data-structures/column-store/column-store.d.ts.map +1 -1
- package/dist/src/data-structures/column-store/column-store.interface.d.ts.map +1 -1
- package/dist/src/data-structures/column-store/index.d.ts.map +1 -1
- package/dist/src/data-structures/command-stack/command-stack.d.ts.map +1 -1
- package/dist/src/data-structures/command-stack/command-stack.interface.d.ts.map +1 -1
- package/dist/src/data-structures/command-stack/index.d.ts.map +1 -1
- package/dist/src/data-structures/dependency-graph/dependency-graph.d.ts.map +1 -1
- package/dist/src/data-structures/dependency-graph/dependency-graph.interface.d.ts.map +1 -1
- package/dist/src/data-structures/dependency-graph/index.d.ts.map +1 -1
- package/dist/src/data-structures/disjoint-set/disjoint-set.d.ts.map +1 -1
- package/dist/src/data-structures/disjoint-set/disjoint-set.interface.d.ts.map +1 -1
- package/dist/src/data-structures/disjoint-set/index.d.ts.map +1 -1
- package/dist/src/data-structures/index-map/index-map.d.ts.map +1 -1
- package/dist/src/data-structures/index-map/index-map.interface.d.ts.map +1 -1
- package/dist/src/data-structures/index-map/index.d.ts.map +1 -1
- package/dist/src/data-structures/index.d.ts.map +1 -1
- package/dist/src/data-structures/interval-tree/index.d.ts.map +1 -1
- package/dist/src/data-structures/interval-tree/interval-tree.d.ts.map +1 -1
- package/dist/src/data-structures/interval-tree/interval-tree.interface.d.ts.map +1 -1
- package/dist/src/data-structures/lru-cache/index.d.ts.map +1 -1
- package/dist/src/data-structures/lru-cache/lru-cache.d.ts.map +1 -1
- package/dist/src/data-structures/lru-cache/lru-cache.interface.d.ts.map +1 -1
- package/dist/src/data-structures/prefix-sum-array/index.d.ts.map +1 -1
- package/dist/src/data-structures/prefix-sum-array/prefix-sum-array.d.ts.map +1 -1
- package/dist/src/data-structures/prefix-sum-array/prefix-sum-array.interface.d.ts.map +1 -1
- package/dist/src/data-structures/rtree/index.d.ts.map +1 -1
- package/dist/src/data-structures/rtree/rtree.d.ts.map +1 -1
- package/dist/src/data-structures/rtree/rtree.interface.d.ts.map +1 -1
- package/dist/src/data-structures/segment-tree/index.d.ts.map +1 -1
- package/dist/src/data-structures/segment-tree/segment-tree.d.ts.map +1 -1
- package/dist/src/data-structures/segment-tree/segment-tree.interface.d.ts.map +1 -1
- package/dist/src/data-structures/skip-list/index.d.ts.map +1 -1
- package/dist/src/data-structures/skip-list/skip-list.d.ts.map +1 -1
- package/dist/src/data-structures/skip-list/skip-list.interface.d.ts.map +1 -1
- package/dist/src/data-structures/sparse-matrix/index.d.ts.map +1 -1
- package/dist/src/data-structures/sparse-matrix/sparse-matrix.d.ts.map +1 -1
- package/dist/src/data-structures/sparse-matrix/sparse-matrix.interface.d.ts.map +1 -1
- package/dist/src/data-structures/suffix-array/index.d.ts.map +1 -1
- package/dist/src/data-structures/suffix-array/suffix-array.d.ts.map +1 -1
- package/dist/src/data-structures/suffix-array/suffix-array.interface.d.ts.map +1 -1
- package/dist/src/data-structures/trie/index.d.ts.map +1 -1
- package/dist/src/data-structures/trie/trie.d.ts.map +1 -1
- package/dist/src/data-structures/trie/trie.interface.d.ts.map +1 -1
- package/dist/src/index.d.ts +7 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/patterns/coordinator.d.ts.map +1 -1
- package/dist/src/patterns/event-emitter.d.ts.map +1 -1
- package/dist/src/patterns/factory.d.ts.map +1 -1
- package/dist/src/patterns/index.d.ts.map +1 -1
- package/dist/src/patterns/mediator.d.ts.map +1 -1
- package/dist/src/patterns/object-pool.d.ts.map +1 -1
- package/dist/src/patterns/observer.d.ts.map +1 -1
- package/dist/src/patterns/operation-mode.d.ts.map +1 -1
- package/dist/src/patterns/state-machine.d.ts.map +1 -1
- package/dist/src/types/common.d.ts.map +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/timing.d.ts.map +1 -1
- package/dist/src/utils/timing.interface.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1187,7 +1187,7 @@ class CommandStack {
|
|
|
1187
1187
|
/**
|
|
1188
1188
|
* Common aggregation operations
|
|
1189
1189
|
*/
|
|
1190
|
-
|
|
1190
|
+
exports.AggregationType = void 0;
|
|
1191
1191
|
(function (AggregationType) {
|
|
1192
1192
|
AggregationType["SUM"] = "sum";
|
|
1193
1193
|
AggregationType["MIN"] = "min";
|
|
@@ -1196,7 +1196,7 @@ var AggregationType;
|
|
|
1196
1196
|
AggregationType["LCM"] = "lcm";
|
|
1197
1197
|
AggregationType["PRODUCT"] = "product";
|
|
1198
1198
|
AggregationType["CUSTOM"] = "custom";
|
|
1199
|
-
})(AggregationType || (AggregationType = {}));
|
|
1199
|
+
})(exports.AggregationType || (exports.AggregationType = {}));
|
|
1200
1200
|
/**
|
|
1201
1201
|
* Predefined aggregation functions and identities
|
|
1202
1202
|
*/
|
|
@@ -1324,10 +1324,10 @@ class SegmentTree {
|
|
|
1324
1324
|
constructor(options) {
|
|
1325
1325
|
this.arr = options.values ? [...options.values] : [];
|
|
1326
1326
|
this.n = this.arr.length;
|
|
1327
|
-
this._type = options.type ?? AggregationType.CUSTOM;
|
|
1327
|
+
this._type = options.type ?? exports.AggregationType.CUSTOM;
|
|
1328
1328
|
this.useLazy = options.lazy ?? true;
|
|
1329
1329
|
// Determine aggregation function and identity
|
|
1330
|
-
if (this._type === AggregationType.CUSTOM) {
|
|
1330
|
+
if (this._type === exports.AggregationType.CUSTOM) {
|
|
1331
1331
|
if (!options.customAggregate || options.identity === undefined) {
|
|
1332
1332
|
throw new Error('CUSTOM aggregation type requires customAggregate function and identity value');
|
|
1333
1333
|
}
|
|
@@ -1353,17 +1353,17 @@ class SegmentTree {
|
|
|
1353
1353
|
*/
|
|
1354
1354
|
getAggregationConfig(type) {
|
|
1355
1355
|
switch (type) {
|
|
1356
|
-
case AggregationType.SUM:
|
|
1356
|
+
case exports.AggregationType.SUM:
|
|
1357
1357
|
return Aggregations.sum;
|
|
1358
|
-
case AggregationType.MIN:
|
|
1358
|
+
case exports.AggregationType.MIN:
|
|
1359
1359
|
return Aggregations.min;
|
|
1360
|
-
case AggregationType.MAX:
|
|
1360
|
+
case exports.AggregationType.MAX:
|
|
1361
1361
|
return Aggregations.max;
|
|
1362
|
-
case AggregationType.GCD:
|
|
1362
|
+
case exports.AggregationType.GCD:
|
|
1363
1363
|
return Aggregations.gcd;
|
|
1364
|
-
case AggregationType.LCM:
|
|
1364
|
+
case exports.AggregationType.LCM:
|
|
1365
1365
|
return Aggregations.lcm;
|
|
1366
|
-
case AggregationType.PRODUCT:
|
|
1366
|
+
case exports.AggregationType.PRODUCT:
|
|
1367
1367
|
return Aggregations.product;
|
|
1368
1368
|
default:
|
|
1369
1369
|
throw new Error(`Unknown aggregation type: ${type}`);
|
|
@@ -1409,7 +1409,7 @@ class SegmentTree {
|
|
|
1409
1409
|
* For MIN/MAX: just use the update value
|
|
1410
1410
|
*/
|
|
1411
1411
|
applyUpdate(nodeValue, updateValue, rangeSize) {
|
|
1412
|
-
if (this._type === AggregationType.SUM) {
|
|
1412
|
+
if (this._type === exports.AggregationType.SUM) {
|
|
1413
1413
|
// For sum, we need to multiply by range size
|
|
1414
1414
|
const update = updateValue * rangeSize;
|
|
1415
1415
|
return this.aggregate(nodeValue, update);
|
|
@@ -1599,7 +1599,7 @@ class SegmentTree {
|
|
|
1599
1599
|
/**
|
|
1600
1600
|
* Create SegmentTree from array
|
|
1601
1601
|
*/
|
|
1602
|
-
static from(values, type = AggregationType.SUM) {
|
|
1602
|
+
static from(values, type = exports.AggregationType.SUM) {
|
|
1603
1603
|
return new SegmentTree({ values, type });
|
|
1604
1604
|
}
|
|
1605
1605
|
/**
|
|
@@ -1608,7 +1608,7 @@ class SegmentTree {
|
|
|
1608
1608
|
static custom(values, aggregate, identity) {
|
|
1609
1609
|
return new SegmentTree({
|
|
1610
1610
|
values,
|
|
1611
|
-
type: AggregationType.CUSTOM,
|
|
1611
|
+
type: exports.AggregationType.CUSTOM,
|
|
1612
1612
|
customAggregate: aggregate,
|
|
1613
1613
|
identity,
|
|
1614
1614
|
});
|
|
@@ -4791,6 +4791,1142 @@ class SuffixArray {
|
|
|
4791
4791
|
}
|
|
4792
4792
|
}
|
|
4793
4793
|
|
|
4794
|
+
/**
|
|
4795
|
+
* Sequence Detection for Autofill
|
|
4796
|
+
*
|
|
4797
|
+
* Detects patterns in data sequences for intelligent autofill.
|
|
4798
|
+
*
|
|
4799
|
+
* **Supported Patterns:**
|
|
4800
|
+
* - Arithmetic sequences: 1, 2, 3, 4, ...
|
|
4801
|
+
* - Geometric sequences: 2, 4, 8, 16, ...
|
|
4802
|
+
* - Date sequences: Jan 1, Jan 2, Jan 3, ...
|
|
4803
|
+
* - Day sequences: Mon, Tue, Wed, ...
|
|
4804
|
+
* - Text patterns: Item 1, Item 2, Item 3, ...
|
|
4805
|
+
*
|
|
4806
|
+
* @example
|
|
4807
|
+
* ```typescript
|
|
4808
|
+
* // Detect arithmetic sequence
|
|
4809
|
+
* const pattern = detectSequence([1, 2, 3, 4]);
|
|
4810
|
+
* // pattern: { type: 'arithmetic', step: 1 }
|
|
4811
|
+
*
|
|
4812
|
+
* // Generate next values
|
|
4813
|
+
* const next = generateSequence(pattern, 5, 3);
|
|
4814
|
+
* // next: [5, 6, 7]
|
|
4815
|
+
* ```
|
|
4816
|
+
*/
|
|
4817
|
+
/**
|
|
4818
|
+
* Detect sequence pattern from an array of values
|
|
4819
|
+
*
|
|
4820
|
+
* @param values - Array of values (at least 2 required)
|
|
4821
|
+
* @returns Detected pattern
|
|
4822
|
+
*/
|
|
4823
|
+
function detectSequence(values) {
|
|
4824
|
+
if (values.length < 2) {
|
|
4825
|
+
return { type: 'none', confidence: 0 };
|
|
4826
|
+
}
|
|
4827
|
+
// Try numeric sequences first
|
|
4828
|
+
if (values.every(v => typeof v === 'number' || !isNaN(Number(v)))) {
|
|
4829
|
+
const numbers = values.map(v => Number(v));
|
|
4830
|
+
// Check arithmetic sequence
|
|
4831
|
+
const arithmeticPattern = detectArithmetic(numbers);
|
|
4832
|
+
if (arithmeticPattern.confidence > 0.8) {
|
|
4833
|
+
return arithmeticPattern;
|
|
4834
|
+
}
|
|
4835
|
+
// Check geometric sequence
|
|
4836
|
+
const geometricPattern = detectGeometric(numbers);
|
|
4837
|
+
if (geometricPattern.confidence > 0.8) {
|
|
4838
|
+
return geometricPattern;
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4841
|
+
// Try text patterns
|
|
4842
|
+
const textPattern = detectTextPattern(values.map(v => String(v)));
|
|
4843
|
+
if (textPattern.confidence > 0.7) {
|
|
4844
|
+
return textPattern;
|
|
4845
|
+
}
|
|
4846
|
+
// Check for constant value
|
|
4847
|
+
if (values.every(v => v === values[0])) {
|
|
4848
|
+
return { type: 'constant', confidence: 1.0 };
|
|
4849
|
+
}
|
|
4850
|
+
return { type: 'none', confidence: 0 };
|
|
4851
|
+
}
|
|
4852
|
+
/**
|
|
4853
|
+
* Detect arithmetic sequence (constant difference)
|
|
4854
|
+
*/
|
|
4855
|
+
function detectArithmetic(numbers) {
|
|
4856
|
+
if (numbers.length < 2) {
|
|
4857
|
+
return { type: 'none', confidence: 0 };
|
|
4858
|
+
}
|
|
4859
|
+
const differences = [];
|
|
4860
|
+
for (let i = 1; i < numbers.length; i++) {
|
|
4861
|
+
differences.push(numbers[i] - numbers[i - 1]);
|
|
4862
|
+
}
|
|
4863
|
+
// Check if all differences are the same (within small tolerance)
|
|
4864
|
+
const avgDiff = differences.reduce((a, b) => a + b, 0) / differences.length;
|
|
4865
|
+
const variance = differences.reduce((sum, d) => sum + Math.pow(d - avgDiff, 2), 0) / differences.length;
|
|
4866
|
+
if (variance < 0.01) {
|
|
4867
|
+
return {
|
|
4868
|
+
type: 'arithmetic',
|
|
4869
|
+
step: avgDiff,
|
|
4870
|
+
confidence: 1.0,
|
|
4871
|
+
};
|
|
4872
|
+
}
|
|
4873
|
+
return { type: 'none', confidence: 0 };
|
|
4874
|
+
}
|
|
4875
|
+
/**
|
|
4876
|
+
* Detect geometric sequence (constant ratio)
|
|
4877
|
+
*/
|
|
4878
|
+
function detectGeometric(numbers) {
|
|
4879
|
+
if (numbers.length < 2 || numbers.some(n => n === 0)) {
|
|
4880
|
+
return { type: 'none', confidence: 0 };
|
|
4881
|
+
}
|
|
4882
|
+
const ratios = [];
|
|
4883
|
+
for (let i = 1; i < numbers.length; i++) {
|
|
4884
|
+
ratios.push(numbers[i] / numbers[i - 1]);
|
|
4885
|
+
}
|
|
4886
|
+
// Check if all ratios are the same
|
|
4887
|
+
const avgRatio = ratios.reduce((a, b) => a + b, 0) / ratios.length;
|
|
4888
|
+
const variance = ratios.reduce((sum, r) => sum + Math.pow(r - avgRatio, 2), 0) / ratios.length;
|
|
4889
|
+
if (variance < 0.01) {
|
|
4890
|
+
return {
|
|
4891
|
+
type: 'geometric',
|
|
4892
|
+
ratio: avgRatio,
|
|
4893
|
+
confidence: 1.0,
|
|
4894
|
+
};
|
|
4895
|
+
}
|
|
4896
|
+
return { type: 'none', confidence: 0 };
|
|
4897
|
+
}
|
|
4898
|
+
/**
|
|
4899
|
+
* Detect text pattern with number suffix
|
|
4900
|
+
* E.g., "Item 1", "Item 2", "Item 3"
|
|
4901
|
+
*/
|
|
4902
|
+
function detectTextPattern(strings) {
|
|
4903
|
+
if (strings.length < 2) {
|
|
4904
|
+
return { type: 'none', confidence: 0 };
|
|
4905
|
+
}
|
|
4906
|
+
// Extract text prefix and number suffix
|
|
4907
|
+
const parts = strings.map(s => {
|
|
4908
|
+
const match = s.match(/^(.*?)(\d+)$/);
|
|
4909
|
+
if (match) {
|
|
4910
|
+
return { prefix: match[1], number: parseInt(match[2], 10) };
|
|
4911
|
+
}
|
|
4912
|
+
return null;
|
|
4913
|
+
});
|
|
4914
|
+
// Check if all have the same prefix
|
|
4915
|
+
if (parts.every(p => p !== null)) {
|
|
4916
|
+
const prefix = parts[0].prefix;
|
|
4917
|
+
if (parts.every(p => p.prefix === prefix)) {
|
|
4918
|
+
const numbers = parts.map(p => p.number);
|
|
4919
|
+
const arithmeticPattern = detectArithmetic(numbers);
|
|
4920
|
+
if (arithmeticPattern.type === 'arithmetic') {
|
|
4921
|
+
return {
|
|
4922
|
+
type: 'text',
|
|
4923
|
+
template: prefix + '{n}',
|
|
4924
|
+
step: arithmeticPattern.step,
|
|
4925
|
+
confidence: 0.9,
|
|
4926
|
+
};
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
return { type: 'none', confidence: 0 };
|
|
4931
|
+
}
|
|
4932
|
+
/**
|
|
4933
|
+
* Generate next values in a sequence
|
|
4934
|
+
*
|
|
4935
|
+
* @param pattern - Detected sequence pattern
|
|
4936
|
+
* @param startValue - Starting value
|
|
4937
|
+
* @param count - Number of values to generate
|
|
4938
|
+
* @returns Array of generated values
|
|
4939
|
+
*/
|
|
4940
|
+
function generateSequence(pattern, startValue, count) {
|
|
4941
|
+
const result = [];
|
|
4942
|
+
switch (pattern.type) {
|
|
4943
|
+
case 'arithmetic':
|
|
4944
|
+
{
|
|
4945
|
+
let current = Number(startValue);
|
|
4946
|
+
for (let i = 0; i < count; i++) {
|
|
4947
|
+
result.push(current);
|
|
4948
|
+
current += pattern.step;
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
break;
|
|
4952
|
+
case 'geometric':
|
|
4953
|
+
{
|
|
4954
|
+
let current = Number(startValue);
|
|
4955
|
+
for (let i = 0; i < count; i++) {
|
|
4956
|
+
result.push(current);
|
|
4957
|
+
current *= pattern.ratio;
|
|
4958
|
+
}
|
|
4959
|
+
}
|
|
4960
|
+
break;
|
|
4961
|
+
case 'text':
|
|
4962
|
+
{
|
|
4963
|
+
// Extract number from start value
|
|
4964
|
+
const match = String(startValue).match(/^(.*?)(\d+)$/);
|
|
4965
|
+
if (match) {
|
|
4966
|
+
let num = parseInt(match[2], 10);
|
|
4967
|
+
const prefix = match[1];
|
|
4968
|
+
for (let i = 0; i < count; i++) {
|
|
4969
|
+
result.push(prefix + num);
|
|
4970
|
+
num += pattern.step ?? 1;
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
break;
|
|
4975
|
+
case 'constant':
|
|
4976
|
+
for (let i = 0; i < count; i++) {
|
|
4977
|
+
result.push(startValue);
|
|
4978
|
+
}
|
|
4979
|
+
break;
|
|
4980
|
+
default:
|
|
4981
|
+
// No pattern - just repeat the start value
|
|
4982
|
+
for (let i = 0; i < count; i++) {
|
|
4983
|
+
result.push(startValue);
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
return result;
|
|
4987
|
+
}
|
|
4988
|
+
/**
|
|
4989
|
+
* Autofill a range based on detected pattern
|
|
4990
|
+
*
|
|
4991
|
+
* @param source - Source values to detect pattern from
|
|
4992
|
+
* @param targetLength - Desired length of result
|
|
4993
|
+
* @returns Autofilled array
|
|
4994
|
+
*/
|
|
4995
|
+
function autofill(source, targetLength) {
|
|
4996
|
+
if (source.length === 0)
|
|
4997
|
+
return [];
|
|
4998
|
+
if (targetLength <= source.length)
|
|
4999
|
+
return source.slice(0, targetLength);
|
|
5000
|
+
const pattern = detectSequence(source);
|
|
5001
|
+
if (pattern.type === 'none' || pattern.confidence < 0.5) {
|
|
5002
|
+
// No pattern - just repeat the source cyclically
|
|
5003
|
+
const result = [...source];
|
|
5004
|
+
while (result.length < targetLength) {
|
|
5005
|
+
result.push(source[result.length % source.length]);
|
|
5006
|
+
}
|
|
5007
|
+
return result.slice(0, targetLength);
|
|
5008
|
+
}
|
|
5009
|
+
// Generate remaining values based on pattern
|
|
5010
|
+
const remaining = targetLength - source.length;
|
|
5011
|
+
const lastValue = source[source.length - 1];
|
|
5012
|
+
const generated = generateSequence(pattern, lastValue, remaining + 1).slice(1); // Skip first (same as last)
|
|
5013
|
+
return [...source, ...generated];
|
|
5014
|
+
}
|
|
5015
|
+
|
|
5016
|
+
/**
|
|
5017
|
+
* Bloom Filter - Probabilistic Data Structure
|
|
5018
|
+
*
|
|
5019
|
+
* A space-efficient probabilistic data structure for testing set membership.
|
|
5020
|
+
* May have false positives but never false negatives.
|
|
5021
|
+
*
|
|
5022
|
+
* **Time Complexity:**
|
|
5023
|
+
* - Add: O(k) where k = number of hash functions
|
|
5024
|
+
* - Check: O(k)
|
|
5025
|
+
*
|
|
5026
|
+
* **Space Complexity:** O(m) where m = bit array size
|
|
5027
|
+
*
|
|
5028
|
+
* **Use Cases:**
|
|
5029
|
+
* - Quick "definitely not in set" checks (e.g., "does this filter value exist?")
|
|
5030
|
+
* - Cache optimization (avoid expensive lookups for non-existent items)
|
|
5031
|
+
* - Duplicate detection in large datasets
|
|
5032
|
+
* - Spell checkers
|
|
5033
|
+
*
|
|
5034
|
+
* @example
|
|
5035
|
+
* ```typescript
|
|
5036
|
+
* const filter = new BloomFilter(1000, 3); // 1000 bits, 3 hash functions
|
|
5037
|
+
*
|
|
5038
|
+
* // Add some items
|
|
5039
|
+
* filter.add('apple');
|
|
5040
|
+
* filter.add('banana');
|
|
5041
|
+
* filter.add('cherry');
|
|
5042
|
+
*
|
|
5043
|
+
* filter.contains('apple'); // true (definitely in set)
|
|
5044
|
+
* filter.contains('grape'); // false (definitely NOT in set)
|
|
5045
|
+
* filter.contains('apples'); // might be true (false positive possible)
|
|
5046
|
+
* ```
|
|
5047
|
+
*
|
|
5048
|
+
* @example Grid Filter Optimization
|
|
5049
|
+
* ```typescript
|
|
5050
|
+
* // Quickly check if a filter value might exist before scanning column
|
|
5051
|
+
* class ColumnFilter {
|
|
5052
|
+
* private bloomFilter = new BloomFilter(10000, 4);
|
|
5053
|
+
*
|
|
5054
|
+
* indexColumn(values: any[]): void {
|
|
5055
|
+
* values.forEach(v => this.bloomFilter.add(String(v)));
|
|
5056
|
+
* }
|
|
5057
|
+
*
|
|
5058
|
+
* mightContain(value: string): boolean {
|
|
5059
|
+
* return this.bloomFilter.contains(value);
|
|
5060
|
+
* }
|
|
5061
|
+
* }
|
|
5062
|
+
* ```
|
|
5063
|
+
*/
|
|
5064
|
+
class BloomFilter {
|
|
5065
|
+
/**
|
|
5066
|
+
* Create a new Bloom Filter
|
|
5067
|
+
*
|
|
5068
|
+
* @param size - Size of the bit array (larger = fewer false positives)
|
|
5069
|
+
* @param hashCount - Number of hash functions (more = fewer false positives, slower)
|
|
5070
|
+
*/
|
|
5071
|
+
constructor(size, hashCount = 3) {
|
|
5072
|
+
this.size = size;
|
|
5073
|
+
this.hashCount = hashCount;
|
|
5074
|
+
this.bitArray = new Array(size).fill(false);
|
|
5075
|
+
}
|
|
5076
|
+
/**
|
|
5077
|
+
* Add an item to the filter
|
|
5078
|
+
*
|
|
5079
|
+
* @param item - Item to add
|
|
5080
|
+
*/
|
|
5081
|
+
add(item) {
|
|
5082
|
+
const hashes = this.getHashes(item);
|
|
5083
|
+
for (const hash of hashes) {
|
|
5084
|
+
this.bitArray[hash] = true;
|
|
5085
|
+
}
|
|
5086
|
+
}
|
|
5087
|
+
/**
|
|
5088
|
+
* Check if an item might be in the set
|
|
5089
|
+
*
|
|
5090
|
+
* @param item - Item to check
|
|
5091
|
+
* @returns true if item might be in set, false if definitely NOT in set
|
|
5092
|
+
*/
|
|
5093
|
+
contains(item) {
|
|
5094
|
+
const hashes = this.getHashes(item);
|
|
5095
|
+
for (const hash of hashes) {
|
|
5096
|
+
if (!this.bitArray[hash]) {
|
|
5097
|
+
return false; // Definitely not in set
|
|
5098
|
+
}
|
|
5099
|
+
}
|
|
5100
|
+
return true; // Might be in set (could be false positive)
|
|
5101
|
+
}
|
|
5102
|
+
/**
|
|
5103
|
+
* Clear the filter
|
|
5104
|
+
*/
|
|
5105
|
+
clear() {
|
|
5106
|
+
this.bitArray.fill(false);
|
|
5107
|
+
}
|
|
5108
|
+
/**
|
|
5109
|
+
* Get the false positive probability
|
|
5110
|
+
*
|
|
5111
|
+
* P(false positive) ≈ (1 - e^(-kn/m))^k
|
|
5112
|
+
* where k = hash functions, n = items added, m = bit array size
|
|
5113
|
+
*
|
|
5114
|
+
* @param itemCount - Number of items added
|
|
5115
|
+
* @returns Estimated false positive probability
|
|
5116
|
+
*/
|
|
5117
|
+
getFalsePositiveRate(itemCount) {
|
|
5118
|
+
const k = this.hashCount;
|
|
5119
|
+
const m = this.size;
|
|
5120
|
+
const n = itemCount;
|
|
5121
|
+
return Math.pow(1 - Math.exp((-k * n) / m), k);
|
|
5122
|
+
}
|
|
5123
|
+
/**
|
|
5124
|
+
* Calculate optimal bit array size for desired false positive rate
|
|
5125
|
+
*
|
|
5126
|
+
* m = -(n * ln(p)) / (ln(2)^2)
|
|
5127
|
+
*
|
|
5128
|
+
* @param itemCount - Expected number of items
|
|
5129
|
+
* @param falsePositiveRate - Desired false positive rate (e.g., 0.01 for 1%)
|
|
5130
|
+
* @returns Optimal bit array size
|
|
5131
|
+
*/
|
|
5132
|
+
static optimalSize(itemCount, falsePositiveRate) {
|
|
5133
|
+
return Math.ceil(-(itemCount * Math.log(falsePositiveRate)) / Math.pow(Math.log(2), 2));
|
|
5134
|
+
}
|
|
5135
|
+
/**
|
|
5136
|
+
* Calculate optimal number of hash functions
|
|
5137
|
+
*
|
|
5138
|
+
* k = (m/n) * ln(2)
|
|
5139
|
+
*
|
|
5140
|
+
* @param bitArraySize - Size of bit array
|
|
5141
|
+
* @param itemCount - Expected number of items
|
|
5142
|
+
* @returns Optimal number of hash functions
|
|
5143
|
+
*/
|
|
5144
|
+
static optimalHashCount(bitArraySize, itemCount) {
|
|
5145
|
+
return Math.ceil((bitArraySize / itemCount) * Math.log(2));
|
|
5146
|
+
}
|
|
5147
|
+
// ==================== Private Methods ====================
|
|
5148
|
+
/**
|
|
5149
|
+
* Generate multiple hash values for an item
|
|
5150
|
+
*/
|
|
5151
|
+
getHashes(item) {
|
|
5152
|
+
const hashes = [];
|
|
5153
|
+
// Use double hashing: h_i(x) = h1(x) + i * h2(x)
|
|
5154
|
+
const hash1 = this.hashFunc1(item);
|
|
5155
|
+
const hash2 = this.hashFunc2(item);
|
|
5156
|
+
for (let i = 0; i < this.hashCount; i++) {
|
|
5157
|
+
const hash = (hash1 + i * hash2) % this.size;
|
|
5158
|
+
hashes.push(Math.abs(hash));
|
|
5159
|
+
}
|
|
5160
|
+
return hashes;
|
|
5161
|
+
}
|
|
5162
|
+
/**
|
|
5163
|
+
* First hash function (simple polynomial hash)
|
|
5164
|
+
*/
|
|
5165
|
+
hashFunc1(str) {
|
|
5166
|
+
let hash = 0;
|
|
5167
|
+
for (let i = 0; i < str.length; i++) {
|
|
5168
|
+
hash = (hash * 31 + str.charCodeAt(i)) % this.size;
|
|
5169
|
+
}
|
|
5170
|
+
return hash;
|
|
5171
|
+
}
|
|
5172
|
+
/**
|
|
5173
|
+
* Second hash function (FNV-1a variant)
|
|
5174
|
+
*/
|
|
5175
|
+
hashFunc2(str) {
|
|
5176
|
+
let hash = 2166136261; // FNV offset basis
|
|
5177
|
+
for (let i = 0; i < str.length; i++) {
|
|
5178
|
+
hash ^= str.charCodeAt(i);
|
|
5179
|
+
hash = (hash * 16777619) % this.size; // FNV prime
|
|
5180
|
+
}
|
|
5181
|
+
return hash;
|
|
5182
|
+
}
|
|
5183
|
+
}
|
|
5184
|
+
|
|
5185
|
+
/**
|
|
5186
|
+
* Helper to handle null values in comparisons
|
|
5187
|
+
*/
|
|
5188
|
+
function compareWithNulls(a, b, nullPosition, compareFn) {
|
|
5189
|
+
const aIsNull = a === null || a === undefined || Number.isNaN(a);
|
|
5190
|
+
const bIsNull = b === null || b === undefined || Number.isNaN(b);
|
|
5191
|
+
if (aIsNull && bIsNull)
|
|
5192
|
+
return 0;
|
|
5193
|
+
if (aIsNull) {
|
|
5194
|
+
return nullPosition === 'first' ? -1 : nullPosition === 'last' ? 1 : 0;
|
|
5195
|
+
}
|
|
5196
|
+
if (bIsNull) {
|
|
5197
|
+
return nullPosition === 'first' ? 1 : nullPosition === 'last' ? -1 : 0;
|
|
5198
|
+
}
|
|
5199
|
+
return compareFn(a, b);
|
|
5200
|
+
}
|
|
5201
|
+
/**
|
|
5202
|
+
* Create a numeric comparator
|
|
5203
|
+
*
|
|
5204
|
+
* @param nullPosition - Where to place null values in sort order
|
|
5205
|
+
* @returns Comparator function
|
|
5206
|
+
*
|
|
5207
|
+
* @example
|
|
5208
|
+
* ```typescript
|
|
5209
|
+
* const numbers = [3, null, 1, undefined, 2];
|
|
5210
|
+
* numbers.sort(numericComparator('last'));
|
|
5211
|
+
* // [1, 2, 3, null, undefined]
|
|
5212
|
+
* ```
|
|
5213
|
+
*/
|
|
5214
|
+
function numericComparator(nullPosition = 'last') {
|
|
5215
|
+
return (a, b) => {
|
|
5216
|
+
return compareWithNulls(a, b, nullPosition, (x, y) => {
|
|
5217
|
+
const numX = Number(x);
|
|
5218
|
+
const numY = Number(y);
|
|
5219
|
+
if (Number.isNaN(numX) && Number.isNaN(numY))
|
|
5220
|
+
return 0;
|
|
5221
|
+
if (Number.isNaN(numX))
|
|
5222
|
+
return nullPosition === 'last' ? 1 : -1;
|
|
5223
|
+
if (Number.isNaN(numY))
|
|
5224
|
+
return nullPosition === 'last' ? -1 : 1;
|
|
5225
|
+
return numX - numY;
|
|
5226
|
+
});
|
|
5227
|
+
};
|
|
5228
|
+
}
|
|
5229
|
+
/**
|
|
5230
|
+
* Create a string comparator
|
|
5231
|
+
*
|
|
5232
|
+
* @param options - Comparator options
|
|
5233
|
+
* @returns Comparator function
|
|
5234
|
+
*
|
|
5235
|
+
* @example
|
|
5236
|
+
* ```typescript
|
|
5237
|
+
* const names = ['Bob', 'alice', 'Charlie'];
|
|
5238
|
+
* names.sort(stringComparator({ caseInsensitive: true }));
|
|
5239
|
+
* // ['alice', 'Bob', 'Charlie']
|
|
5240
|
+
* ```
|
|
5241
|
+
*/
|
|
5242
|
+
function stringComparator(options = {}) {
|
|
5243
|
+
const { caseInsensitive = false, localeCompare = false, locale = 'en-US', nullPosition = 'last', } = options;
|
|
5244
|
+
return (a, b) => {
|
|
5245
|
+
return compareWithNulls(a, b, nullPosition, (x, y) => {
|
|
5246
|
+
let strA = String(x);
|
|
5247
|
+
let strB = String(y);
|
|
5248
|
+
if (caseInsensitive) {
|
|
5249
|
+
strA = strA.toLowerCase();
|
|
5250
|
+
strB = strB.toLowerCase();
|
|
5251
|
+
}
|
|
5252
|
+
if (localeCompare) {
|
|
5253
|
+
return strA.localeCompare(strB, locale);
|
|
5254
|
+
}
|
|
5255
|
+
return strA < strB ? -1 : strA > strB ? 1 : 0;
|
|
5256
|
+
});
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5259
|
+
|
|
5260
|
+
/**
|
|
5261
|
+
* Minimum gallop threshold
|
|
5262
|
+
* How many times one run must "win" before we switch to galloping mode
|
|
5263
|
+
*
|
|
5264
|
+
* JavaScript Note: Set higher than Python's default (7) due to function call overhead.
|
|
5265
|
+
* Galloping mode has more overhead in JS, so we require more consecutive wins
|
|
5266
|
+
* to justify entering gallop mode.
|
|
5267
|
+
*/
|
|
5268
|
+
const MIN_GALLOP = 32;
|
|
5269
|
+
/**
|
|
5270
|
+
* Minimum merge threshold for stack invariants
|
|
5271
|
+
*/
|
|
5272
|
+
const MIN_MERGE = 32;
|
|
5273
|
+
/**
|
|
5274
|
+
* Timsort - Production-grade stable O(n log n) sorting algorithm
|
|
5275
|
+
*
|
|
5276
|
+
* This is a full implementation of Timsort with all optimizations:
|
|
5277
|
+
* - Natural run detection (finds already-sorted sequences)
|
|
5278
|
+
* - Galloping mode (binary search optimization during merges)
|
|
5279
|
+
* - Stack-based merge strategy (maintains merge invariants)
|
|
5280
|
+
* - Reusable temporary buffer (reduces allocations)
|
|
5281
|
+
*
|
|
5282
|
+
* Used by Python, Java, and V8's Array.sort().
|
|
5283
|
+
*
|
|
5284
|
+
* @param array - Array to sort (modified in-place)
|
|
5285
|
+
* @param comparator - Comparison function
|
|
5286
|
+
* @param options - Timsort options
|
|
5287
|
+
* @returns The sorted array
|
|
5288
|
+
*
|
|
5289
|
+
* @complexity
|
|
5290
|
+
* - Time: O(n log n) worst case, O(n) best case (already sorted)
|
|
5291
|
+
* - Space: O(n) for temporary merge buffer
|
|
5292
|
+
*/
|
|
5293
|
+
function timsort(array, comparator, options = {}) {
|
|
5294
|
+
const n = array.length;
|
|
5295
|
+
if (n < 2) {
|
|
5296
|
+
return array;
|
|
5297
|
+
}
|
|
5298
|
+
const sorter = new TimsortImpl(array, comparator, options);
|
|
5299
|
+
sorter.sort();
|
|
5300
|
+
return array;
|
|
5301
|
+
}
|
|
5302
|
+
/**
|
|
5303
|
+
* Sort indices based on values without modifying the values
|
|
5304
|
+
*
|
|
5305
|
+
* @param indices - Array of indices to sort
|
|
5306
|
+
* @param getValue - Function to get value at an index
|
|
5307
|
+
* @param comparator - Comparison function for values
|
|
5308
|
+
* @param options - Timsort options
|
|
5309
|
+
* @returns Sorted array of indices
|
|
5310
|
+
*
|
|
5311
|
+
* @example
|
|
5312
|
+
* ```typescript
|
|
5313
|
+
* const values = ['Charlie', 'Alice', 'Bob'];
|
|
5314
|
+
* const indices = [0, 1, 2];
|
|
5315
|
+
*
|
|
5316
|
+
* const sorted = timsortIndices(
|
|
5317
|
+
* indices,
|
|
5318
|
+
* (i) => values[i],
|
|
5319
|
+
* (a, b) => a.localeCompare(b)
|
|
5320
|
+
* );
|
|
5321
|
+
* // sorted = [1, 2, 0] (Alice, Bob, Charlie)
|
|
5322
|
+
* ```
|
|
5323
|
+
*/
|
|
5324
|
+
function timsortIndices(indices, getValue, comparator, options = {}) {
|
|
5325
|
+
// Create index comparator
|
|
5326
|
+
const indexComparator = (idxA, idxB) => {
|
|
5327
|
+
return comparator(getValue(idxA), getValue(idxB));
|
|
5328
|
+
};
|
|
5329
|
+
return timsort(indices, indexComparator, options);
|
|
5330
|
+
}
|
|
5331
|
+
/**
|
|
5332
|
+
* TimsortImpl - Internal implementation class
|
|
5333
|
+
* Maintains state for the sorting process
|
|
5334
|
+
*/
|
|
5335
|
+
class TimsortImpl {
|
|
5336
|
+
constructor(array, comparator, options) {
|
|
5337
|
+
this.array = array;
|
|
5338
|
+
this.comparator = comparator;
|
|
5339
|
+
this.minGallop = MIN_GALLOP;
|
|
5340
|
+
this.configuredMinRun = options.minRun;
|
|
5341
|
+
this.runStack = [];
|
|
5342
|
+
// Pre-allocate temporary buffer (reused across all merges)
|
|
5343
|
+
const tmpSize = Math.floor(array.length / 2);
|
|
5344
|
+
this.tmp = new Array(tmpSize);
|
|
5345
|
+
}
|
|
5346
|
+
/**
|
|
5347
|
+
* Main sort entry point
|
|
5348
|
+
*/
|
|
5349
|
+
sort() {
|
|
5350
|
+
const n = this.array.length;
|
|
5351
|
+
// Calculate optimal minRun (use configured value if provided)
|
|
5352
|
+
const minRun = this.configuredMinRun ?? this.computeMinRun(n);
|
|
5353
|
+
let lo = 0;
|
|
5354
|
+
// Identify and sort runs
|
|
5355
|
+
while (lo < n) {
|
|
5356
|
+
// Find next run (either ascending or descending)
|
|
5357
|
+
let runLen = this.countRunAndMakeAscending(lo);
|
|
5358
|
+
// If run is too short, extend it with insertion sort
|
|
5359
|
+
if (runLen < minRun) {
|
|
5360
|
+
const force = Math.min(n - lo, minRun);
|
|
5361
|
+
this.binaryInsertionSort(lo, lo + force, lo + runLen);
|
|
5362
|
+
runLen = force;
|
|
5363
|
+
}
|
|
5364
|
+
// Push run onto stack and maybe merge
|
|
5365
|
+
this.pushRun(lo, runLen);
|
|
5366
|
+
this.mergeCollapse();
|
|
5367
|
+
lo += runLen;
|
|
5368
|
+
}
|
|
5369
|
+
// Force merge all remaining runs
|
|
5370
|
+
this.mergeForceCollapse();
|
|
5371
|
+
}
|
|
5372
|
+
/**
|
|
5373
|
+
* Count length of run starting at lo and reverse if descending
|
|
5374
|
+
* Returns length of run (at least 2 if array has 2+ elements)
|
|
5375
|
+
*/
|
|
5376
|
+
countRunAndMakeAscending(lo) {
|
|
5377
|
+
const n = this.array.length;
|
|
5378
|
+
if (lo + 1 >= n) {
|
|
5379
|
+
return 1;
|
|
5380
|
+
}
|
|
5381
|
+
let runHi = lo + 1;
|
|
5382
|
+
// Check if descending
|
|
5383
|
+
if (this.comparator(this.array[runHi], this.array[lo]) < 0) {
|
|
5384
|
+
// Descending run - find end and reverse
|
|
5385
|
+
runHi++;
|
|
5386
|
+
while (runHi < n && this.comparator(this.array[runHi], this.array[runHi - 1]) < 0) {
|
|
5387
|
+
runHi++;
|
|
5388
|
+
}
|
|
5389
|
+
this.reverseRange(lo, runHi);
|
|
5390
|
+
}
|
|
5391
|
+
else {
|
|
5392
|
+
// Ascending run - find end
|
|
5393
|
+
while (runHi < n && this.comparator(this.array[runHi], this.array[runHi - 1]) >= 0) {
|
|
5394
|
+
runHi++;
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
return runHi - lo;
|
|
5398
|
+
}
|
|
5399
|
+
/**
|
|
5400
|
+
* Reverse array[lo:hi]
|
|
5401
|
+
*/
|
|
5402
|
+
reverseRange(lo, hi) {
|
|
5403
|
+
hi--;
|
|
5404
|
+
while (lo < hi) {
|
|
5405
|
+
const temp = this.array[lo];
|
|
5406
|
+
this.array[lo++] = this.array[hi];
|
|
5407
|
+
this.array[hi--] = temp;
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
/**
|
|
5411
|
+
* Binary insertion sort - more efficient than regular insertion sort
|
|
5412
|
+
* Sorts array[lo:hi] where array[lo:start] is already sorted
|
|
5413
|
+
*/
|
|
5414
|
+
binaryInsertionSort(lo, hi, start) {
|
|
5415
|
+
if (start === lo) {
|
|
5416
|
+
start++;
|
|
5417
|
+
}
|
|
5418
|
+
for (; start < hi; start++) {
|
|
5419
|
+
const pivot = this.array[start];
|
|
5420
|
+
// Binary search to find insertion point
|
|
5421
|
+
let left = lo;
|
|
5422
|
+
let right = start;
|
|
5423
|
+
while (left < right) {
|
|
5424
|
+
const mid = (left + right) >>> 1;
|
|
5425
|
+
if (this.comparator(pivot, this.array[mid]) < 0) {
|
|
5426
|
+
right = mid;
|
|
5427
|
+
}
|
|
5428
|
+
else {
|
|
5429
|
+
left = mid + 1;
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
// Shift elements and insert
|
|
5433
|
+
const n = start - left;
|
|
5434
|
+
if (n > 0) {
|
|
5435
|
+
for (let i = start; i > left; i--) {
|
|
5436
|
+
this.array[i] = this.array[i - 1];
|
|
5437
|
+
}
|
|
5438
|
+
this.array[left] = pivot;
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
/**
|
|
5443
|
+
* Push a run onto the pending-run stack
|
|
5444
|
+
*/
|
|
5445
|
+
pushRun(runBase, runLen) {
|
|
5446
|
+
this.runStack.push({ start: runBase, length: runLen });
|
|
5447
|
+
}
|
|
5448
|
+
/**
|
|
5449
|
+
* Merge runs to maintain stack invariants
|
|
5450
|
+
*
|
|
5451
|
+
* Invariants (from Python's timsort):
|
|
5452
|
+
* 1. runLen[i - 2] > runLen[i - 1] + runLen[i]
|
|
5453
|
+
* 2. runLen[i - 1] > runLen[i]
|
|
5454
|
+
*/
|
|
5455
|
+
mergeCollapse() {
|
|
5456
|
+
while (this.runStack.length > 1) {
|
|
5457
|
+
let n = this.runStack.length - 2;
|
|
5458
|
+
if ((n > 0 && this.runStack[n - 1].length <= this.runStack[n].length + this.runStack[n + 1].length) ||
|
|
5459
|
+
(n > 1 && this.runStack[n - 2].length <= this.runStack[n - 1].length + this.runStack[n].length)) {
|
|
5460
|
+
// Merge the smaller of the two pairs
|
|
5461
|
+
if (this.runStack[n - 1].length < this.runStack[n + 1].length) {
|
|
5462
|
+
n--;
|
|
5463
|
+
}
|
|
5464
|
+
this.mergeAt(n);
|
|
5465
|
+
}
|
|
5466
|
+
else if (this.runStack[n].length <= this.runStack[n + 1].length) {
|
|
5467
|
+
this.mergeAt(n);
|
|
5468
|
+
}
|
|
5469
|
+
else {
|
|
5470
|
+
break; // Invariants are satisfied
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
}
|
|
5474
|
+
/**
|
|
5475
|
+
* Force merge all runs on the stack
|
|
5476
|
+
*/
|
|
5477
|
+
mergeForceCollapse() {
|
|
5478
|
+
while (this.runStack.length > 1) {
|
|
5479
|
+
let n = this.runStack.length - 2;
|
|
5480
|
+
if (n > 0 && this.runStack[n - 1].length < this.runStack[n + 1].length) {
|
|
5481
|
+
n--;
|
|
5482
|
+
}
|
|
5483
|
+
this.mergeAt(n);
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
/**
|
|
5487
|
+
* Merge the two runs at stack indices i and i+1
|
|
5488
|
+
*/
|
|
5489
|
+
mergeAt(i) {
|
|
5490
|
+
const run1 = this.runStack[i];
|
|
5491
|
+
const run2 = this.runStack[i + 1];
|
|
5492
|
+
// Merge run1 with run2
|
|
5493
|
+
this.mergeRuns(run1.start, run1.length, run2.start, run2.length);
|
|
5494
|
+
// Update stack
|
|
5495
|
+
this.runStack[i] = { start: run1.start, length: run1.length + run2.length };
|
|
5496
|
+
this.runStack.splice(i + 1, 1);
|
|
5497
|
+
}
|
|
5498
|
+
/**
|
|
5499
|
+
* Merge two adjacent runs with galloping optimization
|
|
5500
|
+
*/
|
|
5501
|
+
mergeRuns(base1, len1, base2, len2) {
|
|
5502
|
+
// Optimization: Find where first element of run2 goes in run1
|
|
5503
|
+
// Elements before that can be ignored
|
|
5504
|
+
const k = this.gallopRight(this.array[base2], base1, len1, 0);
|
|
5505
|
+
base1 += k;
|
|
5506
|
+
len1 -= k;
|
|
5507
|
+
if (len1 === 0) {
|
|
5508
|
+
return;
|
|
5509
|
+
}
|
|
5510
|
+
// Optimization: Find where last element of run1 goes in run2
|
|
5511
|
+
// Elements after that can be ignored
|
|
5512
|
+
len2 = this.gallopLeft(this.array[base1 + len1 - 1], base2, len2, len2 - 1);
|
|
5513
|
+
if (len2 === 0) {
|
|
5514
|
+
return;
|
|
5515
|
+
}
|
|
5516
|
+
// Merge remaining runs, using tmp array for smaller run
|
|
5517
|
+
if (len1 <= len2) {
|
|
5518
|
+
this.mergeLo(base1, len1, base2, len2);
|
|
5519
|
+
}
|
|
5520
|
+
else {
|
|
5521
|
+
this.mergeHi(base1, len1, base2, len2);
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5524
|
+
/**
|
|
5525
|
+
* Merge with run1 in temporary array (run1 is smaller)
|
|
5526
|
+
*/
|
|
5527
|
+
mergeLo(base1, len1, base2, len2) {
|
|
5528
|
+
// Copy run1 to tmp
|
|
5529
|
+
for (let i = 0; i < len1; i++) {
|
|
5530
|
+
this.tmp[i] = this.array[base1 + i];
|
|
5531
|
+
}
|
|
5532
|
+
let cursor1 = 0; // Index in tmp
|
|
5533
|
+
let cursor2 = base2; // Index in array
|
|
5534
|
+
let dest = base1; // Index in array
|
|
5535
|
+
// Move first element of run2
|
|
5536
|
+
this.array[dest++] = this.array[cursor2++];
|
|
5537
|
+
len2--;
|
|
5538
|
+
if (len2 === 0) {
|
|
5539
|
+
// Run2 exhausted, copy remaining tmp
|
|
5540
|
+
for (let i = 0; i < len1; i++) {
|
|
5541
|
+
this.array[dest + i] = this.tmp[cursor1 + i];
|
|
5542
|
+
}
|
|
5543
|
+
return;
|
|
5544
|
+
}
|
|
5545
|
+
if (len1 === 1) {
|
|
5546
|
+
// Run1 has single element, copy run2 then the element
|
|
5547
|
+
for (let i = 0; i < len2; i++) {
|
|
5548
|
+
this.array[dest + i] = this.array[cursor2 + i];
|
|
5549
|
+
}
|
|
5550
|
+
this.array[dest + len2] = this.tmp[cursor1];
|
|
5551
|
+
return;
|
|
5552
|
+
}
|
|
5553
|
+
let minGallop = this.minGallop;
|
|
5554
|
+
outer: while (true) {
|
|
5555
|
+
let count1 = 0; // Number of times run1 won in a row
|
|
5556
|
+
let count2 = 0; // Number of times run2 won in a row
|
|
5557
|
+
// Simple merge until one run starts "winning" consistently
|
|
5558
|
+
do {
|
|
5559
|
+
if (this.comparator(this.array[cursor2], this.tmp[cursor1]) < 0) {
|
|
5560
|
+
this.array[dest++] = this.array[cursor2++];
|
|
5561
|
+
count2++;
|
|
5562
|
+
count1 = 0;
|
|
5563
|
+
len2--;
|
|
5564
|
+
if (len2 === 0)
|
|
5565
|
+
break outer;
|
|
5566
|
+
}
|
|
5567
|
+
else {
|
|
5568
|
+
this.array[dest++] = this.tmp[cursor1++];
|
|
5569
|
+
count1++;
|
|
5570
|
+
count2 = 0;
|
|
5571
|
+
len1--;
|
|
5572
|
+
if (len1 === 1)
|
|
5573
|
+
break outer;
|
|
5574
|
+
}
|
|
5575
|
+
} while ((count1 | count2) < minGallop);
|
|
5576
|
+
// One run is winning consistently - switch to galloping mode
|
|
5577
|
+
do {
|
|
5578
|
+
count1 = this.gallopRightInTmp(this.array[cursor2], cursor1, len1, 0);
|
|
5579
|
+
if (count1 !== 0) {
|
|
5580
|
+
for (let i = 0; i < count1; i++) {
|
|
5581
|
+
this.array[dest++] = this.tmp[cursor1++];
|
|
5582
|
+
}
|
|
5583
|
+
len1 -= count1;
|
|
5584
|
+
if (len1 <= 1)
|
|
5585
|
+
break outer;
|
|
5586
|
+
}
|
|
5587
|
+
this.array[dest++] = this.array[cursor2++];
|
|
5588
|
+
len2--;
|
|
5589
|
+
if (len2 === 0)
|
|
5590
|
+
break outer;
|
|
5591
|
+
count2 = this.gallopLeft(this.tmp[cursor1], cursor2, len2, 0);
|
|
5592
|
+
if (count2 !== 0) {
|
|
5593
|
+
for (let i = 0; i < count2; i++) {
|
|
5594
|
+
this.array[dest++] = this.array[cursor2++];
|
|
5595
|
+
}
|
|
5596
|
+
len2 -= count2;
|
|
5597
|
+
if (len2 === 0)
|
|
5598
|
+
break outer;
|
|
5599
|
+
}
|
|
5600
|
+
this.array[dest++] = this.tmp[cursor1++];
|
|
5601
|
+
len1--;
|
|
5602
|
+
if (len1 === 1)
|
|
5603
|
+
break outer;
|
|
5604
|
+
minGallop--;
|
|
5605
|
+
} while (count1 >= MIN_GALLOP || count2 >= MIN_GALLOP);
|
|
5606
|
+
if (minGallop < 0)
|
|
5607
|
+
minGallop = 0;
|
|
5608
|
+
minGallop += 2; // Penalize leaving gallop mode
|
|
5609
|
+
}
|
|
5610
|
+
this.minGallop = minGallop < 1 ? 1 : minGallop;
|
|
5611
|
+
// Handle remaining elements
|
|
5612
|
+
if (len1 === 1) {
|
|
5613
|
+
for (let i = 0; i < len2; i++) {
|
|
5614
|
+
this.array[dest + i] = this.array[cursor2 + i];
|
|
5615
|
+
}
|
|
5616
|
+
this.array[dest + len2] = this.tmp[cursor1];
|
|
5617
|
+
}
|
|
5618
|
+
else if (len1 > 0) {
|
|
5619
|
+
for (let i = 0; i < len1; i++) {
|
|
5620
|
+
this.array[dest + i] = this.tmp[cursor1 + i];
|
|
5621
|
+
}
|
|
5622
|
+
}
|
|
5623
|
+
}
|
|
5624
|
+
/**
|
|
5625
|
+
* Merge with run2 in temporary array (run2 is smaller)
|
|
5626
|
+
*/
|
|
5627
|
+
mergeHi(base1, len1, base2, len2) {
|
|
5628
|
+
// Copy run2 to tmp
|
|
5629
|
+
for (let i = 0; i < len2; i++) {
|
|
5630
|
+
this.tmp[i] = this.array[base2 + i];
|
|
5631
|
+
}
|
|
5632
|
+
let cursor1 = base1 + len1 - 1; // Index in array (run1, from end)
|
|
5633
|
+
let cursor2 = len2 - 1; // Index in tmp (from end)
|
|
5634
|
+
let dest = base2 + len2 - 1; // Index in array (from end)
|
|
5635
|
+
// Move last element of run1
|
|
5636
|
+
this.array[dest--] = this.array[cursor1--];
|
|
5637
|
+
len1--;
|
|
5638
|
+
if (len1 === 0) {
|
|
5639
|
+
// Run1 exhausted, copy remaining tmp
|
|
5640
|
+
for (let i = 0; i < len2; i++) {
|
|
5641
|
+
this.array[dest - len2 + 1 + i] = this.tmp[i];
|
|
5642
|
+
}
|
|
5643
|
+
return;
|
|
5644
|
+
}
|
|
5645
|
+
if (len2 === 1) {
|
|
5646
|
+
// Run2 has single element
|
|
5647
|
+
dest -= len1;
|
|
5648
|
+
cursor1 -= len1;
|
|
5649
|
+
for (let i = len1 - 1; i >= 0; i--) {
|
|
5650
|
+
this.array[dest + 1 + i] = this.array[cursor1 + 1 + i];
|
|
5651
|
+
}
|
|
5652
|
+
this.array[dest] = this.tmp[cursor2];
|
|
5653
|
+
return;
|
|
5654
|
+
}
|
|
5655
|
+
let minGallop = this.minGallop;
|
|
5656
|
+
outer: while (true) {
|
|
5657
|
+
let count1 = 0;
|
|
5658
|
+
let count2 = 0;
|
|
5659
|
+
do {
|
|
5660
|
+
if (this.comparator(this.tmp[cursor2], this.array[cursor1]) < 0) {
|
|
5661
|
+
this.array[dest--] = this.array[cursor1--];
|
|
5662
|
+
count1++;
|
|
5663
|
+
count2 = 0;
|
|
5664
|
+
len1--;
|
|
5665
|
+
if (len1 === 0)
|
|
5666
|
+
break outer;
|
|
5667
|
+
}
|
|
5668
|
+
else {
|
|
5669
|
+
this.array[dest--] = this.tmp[cursor2--];
|
|
5670
|
+
count2++;
|
|
5671
|
+
count1 = 0;
|
|
5672
|
+
len2--;
|
|
5673
|
+
if (len2 === 1)
|
|
5674
|
+
break outer;
|
|
5675
|
+
}
|
|
5676
|
+
} while ((count1 | count2) < minGallop);
|
|
5677
|
+
do {
|
|
5678
|
+
count1 = len1 - this.gallopRight(this.tmp[cursor2], base1, len1, cursor1 - base1);
|
|
5679
|
+
if (count1 !== 0) {
|
|
5680
|
+
dest -= count1;
|
|
5681
|
+
cursor1 -= count1;
|
|
5682
|
+
len1 -= count1;
|
|
5683
|
+
for (let i = count1 - 1; i >= 0; i--) {
|
|
5684
|
+
this.array[dest + 1 + i] = this.array[cursor1 + 1 + i];
|
|
5685
|
+
}
|
|
5686
|
+
if (len1 === 0)
|
|
5687
|
+
break outer;
|
|
5688
|
+
}
|
|
5689
|
+
this.array[dest--] = this.tmp[cursor2--];
|
|
5690
|
+
len2--;
|
|
5691
|
+
if (len2 === 1)
|
|
5692
|
+
break outer;
|
|
5693
|
+
count2 = len2 - this.gallopLeftInTmp(this.array[cursor1], 0, len2, cursor2);
|
|
5694
|
+
if (count2 !== 0) {
|
|
5695
|
+
dest -= count2;
|
|
5696
|
+
cursor2 -= count2;
|
|
5697
|
+
len2 -= count2;
|
|
5698
|
+
for (let i = 0; i < count2; i++) {
|
|
5699
|
+
this.array[dest + 1 + i] = this.tmp[cursor2 + 1 + i];
|
|
5700
|
+
}
|
|
5701
|
+
if (len2 <= 1)
|
|
5702
|
+
break outer;
|
|
5703
|
+
}
|
|
5704
|
+
this.array[dest--] = this.array[cursor1--];
|
|
5705
|
+
len1--;
|
|
5706
|
+
if (len1 === 0)
|
|
5707
|
+
break outer;
|
|
5708
|
+
minGallop--;
|
|
5709
|
+
} while (count1 >= MIN_GALLOP || count2 >= MIN_GALLOP);
|
|
5710
|
+
if (minGallop < 0)
|
|
5711
|
+
minGallop = 0;
|
|
5712
|
+
minGallop += 2;
|
|
5713
|
+
}
|
|
5714
|
+
this.minGallop = minGallop < 1 ? 1 : minGallop;
|
|
5715
|
+
if (len2 === 1) {
|
|
5716
|
+
dest -= len1;
|
|
5717
|
+
cursor1 -= len1;
|
|
5718
|
+
for (let i = len1 - 1; i >= 0; i--) {
|
|
5719
|
+
this.array[dest + 1 + i] = this.array[cursor1 + 1 + i];
|
|
5720
|
+
}
|
|
5721
|
+
this.array[dest] = this.tmp[cursor2];
|
|
5722
|
+
}
|
|
5723
|
+
else if (len2 > 0) {
|
|
5724
|
+
for (let i = 0; i < len2; i++) {
|
|
5725
|
+
this.array[dest - len2 + 1 + i] = this.tmp[i];
|
|
5726
|
+
}
|
|
5727
|
+
}
|
|
5728
|
+
}
|
|
5729
|
+
/**
|
|
5730
|
+
* Gallop right: Find position where key belongs in array[base:base+len]
|
|
5731
|
+
* Returns offset k where array[base+k-1] < key <= array[base+k]
|
|
5732
|
+
* Uses exponential search followed by binary search
|
|
5733
|
+
*/
|
|
5734
|
+
gallopRight(key, base, len, hint) {
|
|
5735
|
+
let lastOfs = 0;
|
|
5736
|
+
let ofs = 1;
|
|
5737
|
+
if (this.comparator(key, this.array[base + hint]) < 0) {
|
|
5738
|
+
// Gallop left until array[base+hint-ofs] < key <= array[base+hint-lastOfs]
|
|
5739
|
+
const maxOfs = hint + 1;
|
|
5740
|
+
while (ofs < maxOfs && this.comparator(key, this.array[base + hint - ofs]) < 0) {
|
|
5741
|
+
lastOfs = ofs;
|
|
5742
|
+
ofs = (ofs << 1) + 1;
|
|
5743
|
+
if (ofs <= 0)
|
|
5744
|
+
ofs = maxOfs; // Overflow
|
|
5745
|
+
}
|
|
5746
|
+
if (ofs > maxOfs)
|
|
5747
|
+
ofs = maxOfs;
|
|
5748
|
+
// Make offsets relative to base
|
|
5749
|
+
const tmp = lastOfs;
|
|
5750
|
+
lastOfs = hint - ofs;
|
|
5751
|
+
ofs = hint - tmp;
|
|
5752
|
+
}
|
|
5753
|
+
else {
|
|
5754
|
+
// Gallop right until array[base+hint+lastOfs] < key <= array[base+hint+ofs]
|
|
5755
|
+
const maxOfs = len - hint;
|
|
5756
|
+
while (ofs < maxOfs && this.comparator(key, this.array[base + hint + ofs]) >= 0) {
|
|
5757
|
+
lastOfs = ofs;
|
|
5758
|
+
ofs = (ofs << 1) + 1;
|
|
5759
|
+
if (ofs <= 0)
|
|
5760
|
+
ofs = maxOfs;
|
|
5761
|
+
}
|
|
5762
|
+
if (ofs > maxOfs)
|
|
5763
|
+
ofs = maxOfs;
|
|
5764
|
+
// Make offsets relative to base
|
|
5765
|
+
lastOfs += hint;
|
|
5766
|
+
ofs += hint;
|
|
5767
|
+
}
|
|
5768
|
+
// Binary search in array[base+lastOfs:base+ofs]
|
|
5769
|
+
lastOfs++;
|
|
5770
|
+
while (lastOfs < ofs) {
|
|
5771
|
+
const m = lastOfs + ((ofs - lastOfs) >>> 1);
|
|
5772
|
+
if (this.comparator(key, this.array[base + m]) < 0) {
|
|
5773
|
+
ofs = m;
|
|
5774
|
+
}
|
|
5775
|
+
else {
|
|
5776
|
+
lastOfs = m + 1;
|
|
5777
|
+
}
|
|
5778
|
+
}
|
|
5779
|
+
return ofs;
|
|
5780
|
+
}
|
|
5781
|
+
/**
|
|
5782
|
+
* Gallop left: Like gallopRight, but finds position where key < array[base+k]
|
|
5783
|
+
*/
|
|
5784
|
+
gallopLeft(key, base, len, hint) {
|
|
5785
|
+
let lastOfs = 0;
|
|
5786
|
+
let ofs = 1;
|
|
5787
|
+
if (this.comparator(key, this.array[base + hint]) > 0) {
|
|
5788
|
+
const maxOfs = len - hint;
|
|
5789
|
+
while (ofs < maxOfs && this.comparator(key, this.array[base + hint + ofs]) > 0) {
|
|
5790
|
+
lastOfs = ofs;
|
|
5791
|
+
ofs = (ofs << 1) + 1;
|
|
5792
|
+
if (ofs <= 0)
|
|
5793
|
+
ofs = maxOfs;
|
|
5794
|
+
}
|
|
5795
|
+
if (ofs > maxOfs)
|
|
5796
|
+
ofs = maxOfs;
|
|
5797
|
+
lastOfs += hint;
|
|
5798
|
+
ofs += hint;
|
|
5799
|
+
}
|
|
5800
|
+
else {
|
|
5801
|
+
const maxOfs = hint + 1;
|
|
5802
|
+
while (ofs < maxOfs && this.comparator(key, this.array[base + hint - ofs]) <= 0) {
|
|
5803
|
+
lastOfs = ofs;
|
|
5804
|
+
ofs = (ofs << 1) + 1;
|
|
5805
|
+
if (ofs <= 0)
|
|
5806
|
+
ofs = maxOfs;
|
|
5807
|
+
}
|
|
5808
|
+
if (ofs > maxOfs)
|
|
5809
|
+
ofs = maxOfs;
|
|
5810
|
+
const tmp = lastOfs;
|
|
5811
|
+
lastOfs = hint - ofs;
|
|
5812
|
+
ofs = hint - tmp;
|
|
5813
|
+
}
|
|
5814
|
+
lastOfs++;
|
|
5815
|
+
while (lastOfs < ofs) {
|
|
5816
|
+
const m = lastOfs + ((ofs - lastOfs) >>> 1);
|
|
5817
|
+
if (this.comparator(key, this.array[base + m]) > 0) {
|
|
5818
|
+
lastOfs = m + 1;
|
|
5819
|
+
}
|
|
5820
|
+
else {
|
|
5821
|
+
ofs = m;
|
|
5822
|
+
}
|
|
5823
|
+
}
|
|
5824
|
+
return ofs;
|
|
5825
|
+
}
|
|
5826
|
+
/**
|
|
5827
|
+
* Gallop right in tmp array: Find position where key belongs in tmp[base:base+len]
|
|
5828
|
+
*/
|
|
5829
|
+
gallopRightInTmp(key, base, len, hint) {
|
|
5830
|
+
let lastOfs = 0;
|
|
5831
|
+
let ofs = 1;
|
|
5832
|
+
if (this.comparator(key, this.tmp[base + hint]) < 0) {
|
|
5833
|
+
const maxOfs = hint + 1;
|
|
5834
|
+
while (ofs < maxOfs && this.comparator(key, this.tmp[base + hint - ofs]) < 0) {
|
|
5835
|
+
lastOfs = ofs;
|
|
5836
|
+
ofs = (ofs << 1) + 1;
|
|
5837
|
+
if (ofs <= 0)
|
|
5838
|
+
ofs = maxOfs;
|
|
5839
|
+
}
|
|
5840
|
+
if (ofs > maxOfs)
|
|
5841
|
+
ofs = maxOfs;
|
|
5842
|
+
const tmp = lastOfs;
|
|
5843
|
+
lastOfs = hint - ofs;
|
|
5844
|
+
ofs = hint - tmp;
|
|
5845
|
+
}
|
|
5846
|
+
else {
|
|
5847
|
+
const maxOfs = len - hint;
|
|
5848
|
+
while (ofs < maxOfs && this.comparator(key, this.tmp[base + hint + ofs]) >= 0) {
|
|
5849
|
+
lastOfs = ofs;
|
|
5850
|
+
ofs = (ofs << 1) + 1;
|
|
5851
|
+
if (ofs <= 0)
|
|
5852
|
+
ofs = maxOfs;
|
|
5853
|
+
}
|
|
5854
|
+
if (ofs > maxOfs)
|
|
5855
|
+
ofs = maxOfs;
|
|
5856
|
+
lastOfs += hint;
|
|
5857
|
+
ofs += hint;
|
|
5858
|
+
}
|
|
5859
|
+
lastOfs++;
|
|
5860
|
+
while (lastOfs < ofs) {
|
|
5861
|
+
const m = lastOfs + ((ofs - lastOfs) >>> 1);
|
|
5862
|
+
if (this.comparator(key, this.tmp[base + m]) < 0) {
|
|
5863
|
+
ofs = m;
|
|
5864
|
+
}
|
|
5865
|
+
else {
|
|
5866
|
+
lastOfs = m + 1;
|
|
5867
|
+
}
|
|
5868
|
+
}
|
|
5869
|
+
return ofs;
|
|
5870
|
+
}
|
|
5871
|
+
/**
|
|
5872
|
+
* Gallop left in tmp array
|
|
5873
|
+
*/
|
|
5874
|
+
gallopLeftInTmp(key, base, len, hint) {
|
|
5875
|
+
let lastOfs = 0;
|
|
5876
|
+
let ofs = 1;
|
|
5877
|
+
if (this.comparator(key, this.tmp[base + hint]) > 0) {
|
|
5878
|
+
const maxOfs = len - hint;
|
|
5879
|
+
while (ofs < maxOfs && this.comparator(key, this.tmp[base + hint + ofs]) > 0) {
|
|
5880
|
+
lastOfs = ofs;
|
|
5881
|
+
ofs = (ofs << 1) + 1;
|
|
5882
|
+
if (ofs <= 0)
|
|
5883
|
+
ofs = maxOfs;
|
|
5884
|
+
}
|
|
5885
|
+
if (ofs > maxOfs)
|
|
5886
|
+
ofs = maxOfs;
|
|
5887
|
+
lastOfs += hint;
|
|
5888
|
+
ofs += hint;
|
|
5889
|
+
}
|
|
5890
|
+
else {
|
|
5891
|
+
const maxOfs = hint + 1;
|
|
5892
|
+
while (ofs < maxOfs && this.comparator(key, this.tmp[base + hint - ofs]) <= 0) {
|
|
5893
|
+
lastOfs = ofs;
|
|
5894
|
+
ofs = (ofs << 1) + 1;
|
|
5895
|
+
if (ofs <= 0)
|
|
5896
|
+
ofs = maxOfs;
|
|
5897
|
+
}
|
|
5898
|
+
if (ofs > maxOfs)
|
|
5899
|
+
ofs = maxOfs;
|
|
5900
|
+
const tmp = lastOfs;
|
|
5901
|
+
lastOfs = hint - ofs;
|
|
5902
|
+
ofs = hint - tmp;
|
|
5903
|
+
}
|
|
5904
|
+
lastOfs++;
|
|
5905
|
+
while (lastOfs < ofs) {
|
|
5906
|
+
const m = lastOfs + ((ofs - lastOfs) >>> 1);
|
|
5907
|
+
if (this.comparator(key, this.tmp[base + m]) > 0) {
|
|
5908
|
+
lastOfs = m + 1;
|
|
5909
|
+
}
|
|
5910
|
+
else {
|
|
5911
|
+
ofs = m;
|
|
5912
|
+
}
|
|
5913
|
+
}
|
|
5914
|
+
return ofs;
|
|
5915
|
+
}
|
|
5916
|
+
/**
|
|
5917
|
+
* Compute optimal minRun value
|
|
5918
|
+
* Returns a value in range [32, 64] such that n/minRun is close to a power of 2
|
|
5919
|
+
*/
|
|
5920
|
+
computeMinRun(n) {
|
|
5921
|
+
let r = 0;
|
|
5922
|
+
while (n >= MIN_MERGE) {
|
|
5923
|
+
r |= n & 1;
|
|
5924
|
+
n >>= 1;
|
|
5925
|
+
}
|
|
5926
|
+
return n + r;
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
|
|
4794
5930
|
/**
|
|
4795
5931
|
* @fileoverview Timing utilities for performance optimization
|
|
4796
5932
|
* @module @zengrid/shared/utils/timing
|
|
@@ -6208,6 +7344,7 @@ const VERSION = '0.1.0';
|
|
|
6208
7344
|
|
|
6209
7345
|
exports.Aggregations = Aggregations;
|
|
6210
7346
|
exports.BaseCoordinator = BaseCoordinator;
|
|
7347
|
+
exports.BloomFilter = BloomFilter;
|
|
6211
7348
|
exports.ColumnStore = ColumnStore;
|
|
6212
7349
|
exports.CommandStack = CommandStack;
|
|
6213
7350
|
exports.DependencyGraph = DependencyGraph;
|
|
@@ -6238,13 +7375,20 @@ exports.Subject = Subject;
|
|
|
6238
7375
|
exports.SuffixArray = SuffixArray;
|
|
6239
7376
|
exports.Trie = Trie;
|
|
6240
7377
|
exports.VERSION = VERSION;
|
|
7378
|
+
exports.autofill = autofill;
|
|
6241
7379
|
exports.binarySearch = binarySearch;
|
|
6242
7380
|
exports.binarySearchLeft = binarySearchLeft;
|
|
6243
7381
|
exports.binarySearchRight = binarySearchRight;
|
|
6244
7382
|
exports.createRAFBatchScheduler = createRAFBatchScheduler;
|
|
6245
7383
|
exports.debounce = debounce;
|
|
6246
7384
|
exports.delay = delay;
|
|
7385
|
+
exports.detectSequence = detectSequence;
|
|
7386
|
+
exports.generateSequence = generateSequence;
|
|
7387
|
+
exports.numericComparator = numericComparator;
|
|
6247
7388
|
exports.resolveOperationMode = resolveOperationMode;
|
|
6248
7389
|
exports.skipListDefaultComparator = defaultComparator;
|
|
7390
|
+
exports.stringComparator = stringComparator;
|
|
6249
7391
|
exports.throttle = throttle;
|
|
6250
7392
|
exports.timeout = timeout;
|
|
7393
|
+
exports.timsort = timsort;
|
|
7394
|
+
exports.timsortIndices = timsortIndices;
|