fastds 0.0.5 → 0.0.7

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.
@@ -0,0 +1,129 @@
1
+ import { RingBuffer } from './ring-buffer.js';
2
+
3
+ export interface Comparator<T> {
4
+ (a: T, b: T): number;
5
+ }
6
+
7
+ export class BinarySearchArray<T> implements Iterable<T, void, unknown> {
8
+ #buffer: RingBuffer<T>;
9
+ #comparator: Comparator<T>;
10
+
11
+ constructor(comparator: Comparator<T>) {
12
+ this.#buffer = new RingBuffer();
13
+ this.#comparator = comparator;
14
+ }
15
+
16
+ readonly [Symbol.toStringTag] = 'BinarySearchArray';
17
+
18
+ get length(): number {
19
+ return this.#buffer.length;
20
+ }
21
+
22
+ at(index: number) {
23
+ return this.#buffer.peekAt(index);
24
+ }
25
+
26
+ lowerBound(value: T): number {
27
+ const length = this.#buffer.length;
28
+ if (length === 0) return 0;
29
+
30
+ const buffer = this.#buffer;
31
+ const comparator = this.#comparator;
32
+ let left = 0;
33
+ let right = length;
34
+
35
+ while (left < right) {
36
+ const mid = (left + right) >>> 1;
37
+ const midValue = buffer.peekAt(mid)!;
38
+ if (comparator(midValue, value) < 0) {
39
+ left = mid + 1;
40
+ } else {
41
+ right = mid;
42
+ }
43
+ }
44
+
45
+ return left;
46
+ }
47
+
48
+ upperBound(value: T): number {
49
+ const length = this.#buffer.length;
50
+ if (length === 0) return 0;
51
+
52
+ const buffer = this.#buffer;
53
+ const comparator = this.#comparator;
54
+ let left = 0;
55
+ let right = length;
56
+
57
+ while (left < right) {
58
+ const mid = (left + right) >>> 1;
59
+ const midValue = buffer.peekAt(mid)!;
60
+ if (comparator(midValue, value) <= 0) {
61
+ left = mid + 1;
62
+ } else {
63
+ right = mid;
64
+ }
65
+ }
66
+
67
+ return left;
68
+ }
69
+
70
+ indexOf(value: T, index = 0) {
71
+ const length = this.#buffer.length;
72
+ if (length === 0 || index >= length) return -1;
73
+
74
+ const buffer = this.#buffer;
75
+ const comparator = this.#comparator;
76
+ let left = index;
77
+ let right = length - 1;
78
+
79
+ while (left <= right) {
80
+ const mid = (left + right) >>> 1;
81
+ const midValue = buffer.peekAt(mid)!;
82
+ const cmp = comparator(midValue, value);
83
+
84
+ if (cmp === 0) {
85
+ return mid;
86
+ } else if (cmp < 0) {
87
+ left = mid + 1;
88
+ } else {
89
+ right = mid - 1;
90
+ }
91
+ }
92
+
93
+ return -1;
94
+ }
95
+
96
+ has(value: T): boolean {
97
+ return this.indexOf(value) !== -1;
98
+ }
99
+
100
+ insert(value: T) {
101
+ const index = this.lowerBound(value);
102
+ this.#buffer.setOne(index, value, true);
103
+
104
+ return index;
105
+ }
106
+
107
+ removeOne(index: number) {
108
+ return this.#buffer.removeOne(index);
109
+ }
110
+
111
+ removeFirst(value: T) {
112
+ const index = this.indexOf(value);
113
+ return this.#buffer.removeOne(index);
114
+ }
115
+
116
+ remove(index: number, count: number): this {
117
+ this.#buffer.deallocate(index, count);
118
+
119
+ return this;
120
+ }
121
+
122
+ iter() {
123
+ return this.#buffer.iter();
124
+ }
125
+
126
+ [Symbol.iterator](): Iterator<T> {
127
+ return this.#buffer[Symbol.iterator]();
128
+ }
129
+ }
@@ -117,7 +117,6 @@ export class RingBuffer<T> {
117
117
  return false;
118
118
  }
119
119
 
120
- // Clamp index to valid range, like Array.splice()
121
120
  index = Math.min(index, prevLength);
122
121
 
123
122
  const buffer = this.#buffer;
@@ -258,12 +257,12 @@ export class RingBuffer<T> {
258
257
  }
259
258
  return -1;
260
259
  }
260
+
261
261
  const capacity = buffer.length;
262
262
  const firstSegmentLength = capacity - head;
263
263
 
264
264
  if (index < firstSegmentLength) {
265
- const startOffset = head + index;
266
- const result = buffer.indexOf(value, startOffset);
265
+ const result = buffer.indexOf(value, head + index);
267
266
  if (result !== -1) {
268
267
  return result - head;
269
268
  }
@@ -271,19 +270,12 @@ export class RingBuffer<T> {
271
270
  }
272
271
 
273
272
  if (index < length) {
274
- if (tail > length / 2) {
275
- const result = buffer.indexOf(value);
276
- if (result !== -1 && result < tail) {
277
- return firstSegmentLength + result;
278
- }
279
- } else {
280
- for (let i = 0; i < tail; i++) {
281
- if (buffer[i] === value) {
282
- return firstSegmentLength + i;
283
- }
284
- }
273
+ const result = buffer.indexOf(value, 0);
274
+ if (result !== -1 && result < tail) {
275
+ return firstSegmentLength + result;
285
276
  }
286
277
  }
278
+
287
279
  return -1;
288
280
  }
289
281
 
@@ -468,22 +460,27 @@ export class RingBuffer<T> {
468
460
  }
469
461
 
470
462
  push(value: T) {
471
- const tail = this.getTailOffset(1);
472
- if (tail === this.#head) {
463
+ const nextTail = (this.#tail + 1) & this.#mask;
464
+ if (nextTail === this.#head) {
473
465
  this.grow(this.#mask + 2);
466
+ this.#buffer[this.#tail] = value;
467
+ this.#tail = (this.#tail + 1) & this.#mask;
468
+ } else {
469
+ this.#buffer[this.#tail] = value;
470
+ this.#tail = nextTail;
474
471
  }
475
- this.#buffer[this.#tail] = value;
476
- this.#tail = this.getTailOffset(1);
477
472
  this.#length++;
478
473
  return this;
479
474
  }
480
475
 
481
476
  unshift(value: T): this {
482
- const head = this.getHeadOffset(-1);
483
- if (head === this.#tail) {
477
+ const newHead = (this.#head - 1) & this.#mask;
478
+ if (newHead === this.#tail) {
484
479
  this.grow(this.#mask + 2);
480
+ this.#head = (this.#head - 1) & this.#mask;
481
+ } else {
482
+ this.#head = newHead;
485
483
  }
486
- this.#head = this.getHeadOffset(-1);
487
484
  this.#buffer[this.#head] = value;
488
485
  this.#length++;
489
486
  return this;
@@ -495,7 +492,7 @@ export class RingBuffer<T> {
495
492
  }
496
493
  const value = this.#buffer[this.#head];
497
494
  this.#buffer[this.#head] = undefined;
498
- this.#head = this.getHeadOffset(1);
495
+ this.#head = (this.#head + 1) & this.#mask;
499
496
  this.#length--;
500
497
  return value;
501
498
  }
@@ -504,7 +501,7 @@ export class RingBuffer<T> {
504
501
  if (this.#head === this.#tail) {
505
502
  return undefined;
506
503
  }
507
- this.#tail = this.getTailOffset(-1);
504
+ this.#tail = (this.#tail - 1) & this.#mask;
508
505
  const value = this.#buffer[this.#tail];
509
506
  this.#buffer[this.#tail] = undefined;
510
507
  this.#length--;
@@ -568,14 +565,18 @@ export class RingBuffer<T> {
568
565
 
569
566
  [Symbol.iterator](): Iterator<T, void, unknown> {
570
567
  const buffer = this.#buffer;
568
+ const mask = this.#mask;
569
+ const length = this.#length;
570
+ let count = 0;
571
571
  let idx = this.#head;
572
572
  return {
573
573
  next: (): IteratorResult<T> => {
574
- if (idx >= this.#head + this.#length) {
574
+ if (count >= length) {
575
575
  return { done: true, value: undefined };
576
576
  }
577
- const offset = idx++ & this.#mask;
578
- const value = buffer[offset]!;
577
+ const value = buffer[idx]!;
578
+ idx = (idx + 1) & mask;
579
+ count++;
579
580
  return { done: false, value };
580
581
  },
581
582
  };