serializable-bptree 5.0.5 → 5.1.1

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.
@@ -61,16 +61,167 @@ var StringComparator = class extends ValueComparator {
61
61
  }
62
62
  };
63
63
 
64
- // src/utils/InvertedWeakMap.ts
64
+ // node_modules/cache-entanglement/dist/esm/index.mjs
65
+ var __create = Object.create;
66
+ var __defProp2 = Object.defineProperty;
67
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
68
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
69
+ var __getProtoOf = Object.getPrototypeOf;
70
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
71
+ var __commonJS = (cb, mod) => function __require() {
72
+ return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
73
+ };
74
+ var __copyProps2 = (to, from, except, desc) => {
75
+ if (from && typeof from === "object" || typeof from === "function") {
76
+ for (let key of __getOwnPropNames2(from))
77
+ if (!__hasOwnProp2.call(to, key) && key !== except)
78
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
79
+ }
80
+ return to;
81
+ };
82
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps2(
83
+ // If the importer is in node compatibility mode or this is not an ESM
84
+ // file that has been converted to a CommonJS file using a Babel-
85
+ // compatible transform (i.e. "__esModule" has not been set), then set
86
+ // "default" to the CommonJS "module.exports" for node compatibility.
87
+ isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
88
+ mod
89
+ ));
90
+ var require_ms = __commonJS({
91
+ "node_modules/ms/index.js"(exports, module2) {
92
+ var s = 1e3;
93
+ var m = s * 60;
94
+ var h = m * 60;
95
+ var d = h * 24;
96
+ var w = d * 7;
97
+ var y = d * 365.25;
98
+ module2.exports = function(val, options) {
99
+ options = options || {};
100
+ var type = typeof val;
101
+ if (type === "string" && val.length > 0) {
102
+ return parse(val);
103
+ } else if (type === "number" && isFinite(val)) {
104
+ return options.long ? fmtLong(val) : fmtShort(val);
105
+ }
106
+ throw new Error(
107
+ "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
108
+ );
109
+ };
110
+ function parse(str) {
111
+ str = String(str);
112
+ if (str.length > 100) {
113
+ return;
114
+ }
115
+ var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
116
+ str
117
+ );
118
+ if (!match) {
119
+ return;
120
+ }
121
+ var n = parseFloat(match[1]);
122
+ var type = (match[2] || "ms").toLowerCase();
123
+ switch (type) {
124
+ case "years":
125
+ case "year":
126
+ case "yrs":
127
+ case "yr":
128
+ case "y":
129
+ return n * y;
130
+ case "weeks":
131
+ case "week":
132
+ case "w":
133
+ return n * w;
134
+ case "days":
135
+ case "day":
136
+ case "d":
137
+ return n * d;
138
+ case "hours":
139
+ case "hour":
140
+ case "hrs":
141
+ case "hr":
142
+ case "h":
143
+ return n * h;
144
+ case "minutes":
145
+ case "minute":
146
+ case "mins":
147
+ case "min":
148
+ case "m":
149
+ return n * m;
150
+ case "seconds":
151
+ case "second":
152
+ case "secs":
153
+ case "sec":
154
+ case "s":
155
+ return n * s;
156
+ case "milliseconds":
157
+ case "millisecond":
158
+ case "msecs":
159
+ case "msec":
160
+ case "ms":
161
+ return n;
162
+ default:
163
+ return void 0;
164
+ }
165
+ }
166
+ function fmtShort(ms2) {
167
+ var msAbs = Math.abs(ms2);
168
+ if (msAbs >= d) {
169
+ return Math.round(ms2 / d) + "d";
170
+ }
171
+ if (msAbs >= h) {
172
+ return Math.round(ms2 / h) + "h";
173
+ }
174
+ if (msAbs >= m) {
175
+ return Math.round(ms2 / m) + "m";
176
+ }
177
+ if (msAbs >= s) {
178
+ return Math.round(ms2 / s) + "s";
179
+ }
180
+ return ms2 + "ms";
181
+ }
182
+ function fmtLong(ms2) {
183
+ var msAbs = Math.abs(ms2);
184
+ if (msAbs >= d) {
185
+ return plural(ms2, msAbs, d, "day");
186
+ }
187
+ if (msAbs >= h) {
188
+ return plural(ms2, msAbs, h, "hour");
189
+ }
190
+ if (msAbs >= m) {
191
+ return plural(ms2, msAbs, m, "minute");
192
+ }
193
+ if (msAbs >= s) {
194
+ return plural(ms2, msAbs, s, "second");
195
+ }
196
+ return ms2 + " ms";
197
+ }
198
+ function plural(ms2, msAbs, n, name) {
199
+ var isPlural = msAbs >= n * 1.5;
200
+ return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
201
+ }
202
+ }
203
+ });
204
+ var import_ms = __toESM(require_ms());
65
205
  var InvertedWeakMap = class {
66
206
  _map;
207
+ _keepAlive;
208
+ _timeouts;
67
209
  _registry;
68
- constructor() {
210
+ _lifespan;
211
+ constructor(option) {
212
+ const { lifespan } = option;
213
+ this._lifespan = lifespan;
69
214
  this._map = /* @__PURE__ */ new Map();
70
- this._registry = new FinalizationRegistry((key) => this._map.delete(key));
215
+ this._keepAlive = /* @__PURE__ */ new Map();
216
+ this._timeouts = /* @__PURE__ */ new Map();
217
+ this._registry = new FinalizationRegistry((key) => {
218
+ this._stopExpire(key, true);
219
+ this._map.delete(key);
220
+ });
71
221
  }
72
222
  clear() {
73
- return this._map.clear();
223
+ this._keepAlive.clear();
224
+ this._map.clear();
74
225
  }
75
226
  delete(key) {
76
227
  const ref = this._map.get(key);
@@ -80,6 +231,8 @@ var InvertedWeakMap = class {
80
231
  this._registry.unregister(raw);
81
232
  }
82
233
  }
234
+ this._stopExpire(key, true);
235
+ this._keepAlive.delete(key);
83
236
  return this._map.delete(key);
84
237
  }
85
238
  get(key) {
@@ -91,8 +244,39 @@ var InvertedWeakMap = class {
91
244
  set(key, value) {
92
245
  this._map.set(key, new WeakRef(value));
93
246
  this._registry.register(value, key);
247
+ if (this._lifespan > 0) {
248
+ this._stopExpire(key, true);
249
+ this._startExpire(key, value);
250
+ }
94
251
  return this;
95
252
  }
253
+ extendExpire(key) {
254
+ if (!(this._lifespan > 0)) {
255
+ return;
256
+ }
257
+ if (!this._keepAlive.has(key)) {
258
+ return;
259
+ }
260
+ this._stopExpire(key, false);
261
+ this._startExpire(key, this._keepAlive.get(key));
262
+ }
263
+ _startExpire(key, value) {
264
+ this._keepAlive.set(key, value);
265
+ this._timeouts.set(key, setTimeout(() => {
266
+ this._keepAlive.delete(key);
267
+ }, this._lifespan));
268
+ }
269
+ _stopExpire(key, removeKeepAlive) {
270
+ if (!this._timeouts.has(key)) {
271
+ return;
272
+ }
273
+ const timeout = this._timeouts.get(key);
274
+ this._timeouts.delete(key);
275
+ clearTimeout(timeout);
276
+ if (removeKeepAlive) {
277
+ this._keepAlive.delete(key);
278
+ }
279
+ }
96
280
  get size() {
97
281
  return this._map.size;
98
282
  }
@@ -100,13 +284,226 @@ var InvertedWeakMap = class {
100
284
  return this._map.keys();
101
285
  }
102
286
  };
287
+ var CacheEntanglement = class {
288
+ creation;
289
+ beforeUpdateHook;
290
+ lifespan;
291
+ dependencies;
292
+ caches;
293
+ assignments;
294
+ parameters;
295
+ constructor(creation, option) {
296
+ option = option ?? {};
297
+ const {
298
+ dependencies,
299
+ lifespan,
300
+ beforeUpdateHook
301
+ } = option;
302
+ this.creation = creation;
303
+ this.beforeUpdateHook = beforeUpdateHook ?? (() => {
304
+ });
305
+ this.lifespan = this._normalizeMs(lifespan ?? 0);
306
+ this.assignments = [];
307
+ this.caches = new InvertedWeakMap({ lifespan: this.lifespan });
308
+ this.dependencies = dependencies ?? {};
309
+ this.parameters = {};
310
+ for (const name in this.dependencies) {
311
+ const dependency = this.dependencies[name];
312
+ if (!dependency.assignments.includes(this)) {
313
+ dependency.assignments.push(this);
314
+ }
315
+ }
316
+ }
317
+ _normalizeMs(time) {
318
+ if (typeof time === "string") {
319
+ return (0, import_ms.default)(time);
320
+ }
321
+ return time;
322
+ }
323
+ dependencyKey(key) {
324
+ const tokens = key.split("/");
325
+ tokens.pop();
326
+ return tokens.join("/");
327
+ }
328
+ /**
329
+ * Returns all keys stored in the instance.
330
+ */
331
+ keys() {
332
+ return this.caches.keys();
333
+ }
334
+ /**
335
+ * Deletes all cache values stored in the instance.
336
+ */
337
+ clear() {
338
+ for (const key of this.keys()) {
339
+ this.delete(key);
340
+ }
341
+ }
342
+ /**
343
+ * Checks if there is a cache value stored in the key within the instance.
344
+ * @param key The key to search.
345
+ */
346
+ exists(key) {
347
+ return this.caches.has(key);
348
+ }
349
+ /**
350
+ * Returns the cache value stored in the key within the instance. If the cached value is not present, an error is thrown.
351
+ * @param key The key to search.
352
+ */
353
+ get(key) {
354
+ if (!this.caches.has(key)) {
355
+ throw new Error(`Cache value not found: ${key}`);
356
+ }
357
+ return this.caches.get(key);
358
+ }
359
+ /**
360
+ * Deletes the cache value stored in the key within the instance.
361
+ * @param key The key to delete.
362
+ */
363
+ delete(key) {
364
+ this.caches.delete(key);
365
+ }
366
+ };
367
+ var CacheData = class _CacheData {
368
+ static StructuredClone = globalThis.structuredClone.bind(globalThis);
369
+ _value;
370
+ constructor(value) {
371
+ this._value = value;
372
+ }
373
+ /**
374
+ * This is cached data.
375
+ * It was generated at the time of caching, so there is a risk of modification if it's an object due to shallow copying.
376
+ * Therefore, if it's not a primitive type, please avoid using this value directly and use the `clone` method to use a copied version of the data.
377
+ */
378
+ get raw() {
379
+ return this._value;
380
+ }
381
+ /**
382
+ * The method returns a copied value of the cached data.
383
+ * You can pass a function as a parameter to copy the value. This parameter function should return the copied value.
384
+ *
385
+ * If no parameter is passed, it defaults to using Javascript's or \@ungap/structured-clone's `structuredClone` function to copy the value.
386
+ * If you prefer shallow copying instead of deep copying,
387
+ * you can use the default options `array-shallow-copy`, `object-shallow-copy` and `deep-copy`,
388
+ * which are replaced with functions to shallow copy arrays and objects, respectively. This is a syntactic sugar.
389
+ * @param strategy The function that returns the copied value.
390
+ * If you want to perform a shallow copy, simply pass the strings `array-shallow-copy` or `object-shallow-copy` for easy use.
391
+ * The default is `structuredClone`.
392
+ */
393
+ clone(strategy = "deep-copy") {
394
+ if (strategy && typeof strategy !== "string") {
395
+ return strategy(this.raw);
396
+ }
397
+ switch (strategy) {
398
+ case "array-shallow-copy":
399
+ return [].concat(this.raw);
400
+ case "object-shallow-copy":
401
+ return Object.assign({}, this.raw);
402
+ case "deep-copy":
403
+ default:
404
+ return _CacheData.StructuredClone(this.raw);
405
+ }
406
+ }
407
+ };
408
+ var CacheEntanglementSync = class extends CacheEntanglement {
409
+ constructor(creation, option) {
410
+ super(creation, option);
411
+ }
412
+ resolve(key, ...parameter) {
413
+ const resolved = {};
414
+ const dependencyKey = this.dependencyKey(key);
415
+ this.beforeUpdateHook(key, dependencyKey, ...parameter);
416
+ for (const name in this.dependencies) {
417
+ const dependency = this.dependencies[name];
418
+ if (!dependency.caches.has(key) && !dependency.caches.has(dependencyKey)) {
419
+ throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name}'.`, {
420
+ cause: {
421
+ from: this
422
+ }
423
+ });
424
+ }
425
+ const dependencyValue = dependency.caches.get(key) ?? dependency.caches.get(dependencyKey);
426
+ resolved[name] = dependencyValue;
427
+ }
428
+ this.parameters[key] = parameter;
429
+ const value = new CacheData(this.creation(key, resolved, ...parameter));
430
+ this.caches.set(key, value);
431
+ return value;
432
+ }
433
+ cache(key, ...parameter) {
434
+ if (!this.caches.has(key)) {
435
+ this.resolve(key, ...parameter);
436
+ } else {
437
+ this.caches.extendExpire(key);
438
+ }
439
+ return this.caches.get(key);
440
+ }
441
+ update(key, ...parameter) {
442
+ this.resolve(key, ...parameter);
443
+ for (const t of this.assignments) {
444
+ const instance = t;
445
+ for (const cacheKey of instance.caches.keys()) {
446
+ if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
447
+ instance.update(cacheKey, ...instance.parameters[cacheKey]);
448
+ }
449
+ }
450
+ }
451
+ return this.caches.get(key);
452
+ }
453
+ };
454
+ var CacheEntanglementAsync = class extends CacheEntanglement {
455
+ constructor(creation, option) {
456
+ super(creation, option);
457
+ }
458
+ async resolve(key, ...parameter) {
459
+ const resolved = {};
460
+ const dependencyKey = this.dependencyKey(key);
461
+ await this.beforeUpdateHook(key, dependencyKey, ...parameter);
462
+ for (const name in this.dependencies) {
463
+ const dependency = this.dependencies[name];
464
+ if (!dependency.caches.has(key) && !dependency.caches.has(dependencyKey)) {
465
+ throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name}'.`, {
466
+ cause: {
467
+ from: this
468
+ }
469
+ });
470
+ }
471
+ const dependencyValue = dependency.caches.get(key) ?? dependency.caches.get(dependencyKey);
472
+ resolved[name] = dependencyValue;
473
+ }
474
+ this.parameters[key] = parameter;
475
+ const value = new CacheData(await this.creation(key, resolved, ...parameter));
476
+ this.caches.set(key, value);
477
+ return value;
478
+ }
479
+ async cache(key, ...parameter) {
480
+ if (!this.caches.has(key)) {
481
+ await this.resolve(key, ...parameter);
482
+ } else {
483
+ this.caches.extendExpire(key);
484
+ }
485
+ return this.caches.get(key);
486
+ }
487
+ async update(key, ...parameter) {
488
+ await this.resolve(key, ...parameter);
489
+ for (const t of this.assignments) {
490
+ const instance = t;
491
+ for (const cacheKey of instance.caches.keys()) {
492
+ if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
493
+ await instance.update(cacheKey, ...instance.parameters[cacheKey]);
494
+ }
495
+ }
496
+ }
497
+ return this.caches.get(key);
498
+ }
499
+ };
103
500
 
104
501
  // src/base/BPTree.ts
105
502
  var BPTree = class {
106
503
  _cachedRegexp;
107
504
  strategy;
108
505
  comparator;
109
- nodes;
506
+ option;
110
507
  order;
111
508
  root;
112
509
  _strategyDirty;
@@ -120,15 +517,12 @@ var BPTree = class {
120
517
  lte: (nv, v) => this.comparator.isLower(nv, v) || this.comparator.isSame(nv, v),
121
518
  equal: (nv, v) => this.comparator.isSame(nv, v),
122
519
  notEqual: (nv, v) => this.comparator.isSame(nv, v) === false,
520
+ or: (nv, v) => this.ensureValues(v).some((v2) => this.comparator.isSame(nv, v2)),
123
521
  like: (nv, v) => {
124
522
  const nodeValue = this.comparator.match(nv);
125
523
  const value = this.comparator.match(v);
126
- if (!this._cachedRegexp.has(value)) {
127
- const pattern = value.replace(/%/g, ".*").replace(/_/g, ".");
128
- const regexp2 = new RegExp(`^${pattern}$`, "i");
129
- this._cachedRegexp.set(value, regexp2);
130
- }
131
- const regexp = this._cachedRegexp.get(value);
524
+ const cache = this._cachedRegexp.cache(value);
525
+ const regexp = cache.raw;
132
526
  return regexp.test(nodeValue);
133
527
  }
134
528
  };
@@ -139,8 +533,22 @@ var BPTree = class {
139
533
  lte: (v) => this.insertableNode(v),
140
534
  equal: (v) => this.insertableNode(v),
141
535
  notEqual: (v) => this.leftestNode(),
536
+ or: (v) => this.insertableNode(this.lowestValue(this.ensureValues(v))),
142
537
  like: (v) => this.leftestNode()
143
538
  };
539
+ verifierEndNode = {
540
+ gt: (v) => null,
541
+ gte: (v) => null,
542
+ lt: (v) => null,
543
+ lte: (v) => null,
544
+ equal: (v) => this.insertableEndNode(v, this.verifierDirection.equal),
545
+ notEqual: (v) => null,
546
+ or: (v) => this.insertableEndNode(
547
+ this.highestValue(this.ensureValues(v)),
548
+ this.verifierDirection.or
549
+ ),
550
+ like: (v) => null
551
+ };
144
552
  verifierDirection = {
145
553
  gt: 1,
146
554
  gte: 1,
@@ -148,26 +556,41 @@ var BPTree = class {
148
556
  lte: -1,
149
557
  equal: 1,
150
558
  notEqual: 1,
559
+ or: 1,
151
560
  like: 1
152
561
  };
153
- verifierFullScan = {
154
- gt: false,
155
- gte: false,
156
- lt: false,
157
- lte: false,
158
- equal: false,
159
- notEqual: true,
160
- like: true
161
- };
162
- constructor(strategy, comparator) {
562
+ constructor(strategy, comparator, option) {
563
+ this.strategy = strategy;
564
+ this.comparator = comparator;
565
+ this.option = option ?? {};
163
566
  this._strategyDirty = false;
164
- this._cachedRegexp = new InvertedWeakMap();
165
567
  this._nodeCreateBuffer = /* @__PURE__ */ new Map();
166
568
  this._nodeUpdateBuffer = /* @__PURE__ */ new Map();
167
569
  this._nodeDeleteBuffer = /* @__PURE__ */ new Map();
168
- this.nodes = new InvertedWeakMap();
169
- this.strategy = strategy;
170
- this.comparator = comparator;
570
+ this._cachedRegexp = this._createCachedRegexp();
571
+ }
572
+ _createCachedRegexp() {
573
+ return new CacheEntanglementSync((key) => {
574
+ const pattern = key.replace(/%/g, ".*").replace(/_/g, ".");
575
+ const regexp = new RegExp(`^${pattern}$`, "i");
576
+ return regexp;
577
+ }, {
578
+ lifespan: this.option.lifespan ?? "3m"
579
+ });
580
+ }
581
+ ensureValues(v) {
582
+ if (!Array.isArray(v)) {
583
+ v = [v];
584
+ }
585
+ return v;
586
+ }
587
+ lowestValue(v) {
588
+ const i = 0;
589
+ return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
590
+ }
591
+ highestValue(v) {
592
+ const i = v.length - 1;
593
+ return [...v].sort((a, b) => this.comparator.asc(a, b))[i];
171
594
  }
172
595
  _insertAtLeaf(node, key, value) {
173
596
  if (node.values.length) {
@@ -175,6 +598,11 @@ var BPTree = class {
175
598
  const nValue = node.values[i];
176
599
  if (this.comparator.isSame(value, nValue)) {
177
600
  const keys = node.keys[i];
601
+ if (keys.includes(key)) {
602
+ throw new Error("The key already exists.", {
603
+ cause: { key, value }
604
+ });
605
+ }
178
606
  keys.push(key);
179
607
  this.bufferForNodeUpdate(node);
180
608
  break;
@@ -222,32 +650,47 @@ var BPTree = class {
222
650
  getHeadData() {
223
651
  return this.strategy.head.data;
224
652
  }
653
+ /**
654
+ * Clears all cached nodes.
655
+ * This method is useful for freeing up memory when the tree is no longer needed.
656
+ */
657
+ clear() {
658
+ this._cachedRegexp.clear();
659
+ this.nodes.clear();
660
+ }
225
661
  };
226
662
 
227
663
  // src/BPTreeSync.ts
228
664
  var BPTreeSync = class extends BPTree {
229
- constructor(strategy, comparator) {
230
- super(strategy, comparator);
231
- }
232
- getPairsRightToLeft(value, startNode, fullScan, comparator) {
665
+ constructor(strategy, comparator, option) {
666
+ super(strategy, comparator, option);
667
+ this.nodes = this._createCachedNode();
668
+ }
669
+ _createCachedNode() {
670
+ return new CacheEntanglementSync((key) => {
671
+ return this.strategy.read(key);
672
+ }, {
673
+ lifespan: this.option.lifespan ?? "3m"
674
+ });
675
+ }
676
+ getPairsRightToLeft(value, startNode, endNode, comparator) {
233
677
  const pairs = [];
234
678
  let node = startNode;
235
679
  let done = false;
236
- let found = false;
237
680
  while (!done) {
681
+ if (endNode && node.id === endNode.id) {
682
+ done = true;
683
+ break;
684
+ }
238
685
  let i = node.values.length;
239
686
  while (i--) {
240
687
  const nValue = node.values[i];
241
688
  const keys = node.keys[i];
242
689
  if (comparator(nValue, value)) {
243
- found = true;
244
690
  let j = keys.length;
245
691
  while (j--) {
246
692
  pairs.push([keys[j], nValue]);
247
693
  }
248
- } else if (found && !fullScan) {
249
- done = true;
250
- break;
251
694
  }
252
695
  }
253
696
  if (!node.prev) {
@@ -258,24 +701,23 @@ var BPTreeSync = class extends BPTree {
258
701
  }
259
702
  return new Map(pairs.reverse());
260
703
  }
261
- getPairsLeftToRight(value, startNode, fullScan, comparator) {
704
+ getPairsLeftToRight(value, startNode, endNode, comparator) {
262
705
  const pairs = [];
263
706
  let node = startNode;
264
707
  let done = false;
265
- let found = false;
266
708
  while (!done) {
709
+ if (endNode && node.id === endNode.id) {
710
+ done = true;
711
+ break;
712
+ }
267
713
  for (let i = 0, len = node.values.length; i < len; i++) {
268
714
  const nValue = node.values[i];
269
715
  const keys = node.keys[i];
270
716
  if (comparator(nValue, value)) {
271
- found = true;
272
717
  for (let j = 0, len2 = keys.length; j < len2; j++) {
273
718
  const key = keys[j];
274
719
  pairs.push([key, nValue]);
275
720
  }
276
- } else if (found && !fullScan) {
277
- done = true;
278
- break;
279
721
  }
280
722
  }
281
723
  if (!node.next) {
@@ -286,12 +728,12 @@ var BPTreeSync = class extends BPTree {
286
728
  }
287
729
  return new Map(pairs);
288
730
  }
289
- getPairs(value, startNode, fullScan, comparator, direction) {
731
+ getPairs(value, startNode, endNode, comparator, direction) {
290
732
  switch (direction) {
291
733
  case -1:
292
- return this.getPairsRightToLeft(value, startNode, fullScan, comparator);
734
+ return this.getPairsRightToLeft(value, startNode, endNode, comparator);
293
735
  case 1:
294
- return this.getPairsLeftToRight(value, startNode, fullScan, comparator);
736
+ return this.getPairsLeftToRight(value, startNode, endNode, comparator);
295
737
  default:
296
738
  throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
297
739
  }
@@ -314,7 +756,7 @@ var BPTreeSync = class extends BPTree {
314
756
  next,
315
757
  prev
316
758
  };
317
- this.nodes.set(id, node);
759
+ this._nodeCreateBuffer.set(id, node);
318
760
  return node;
319
761
  }
320
762
  _deleteEntry(node, key, value) {
@@ -528,7 +970,6 @@ var BPTreeSync = class extends BPTree {
528
970
  this.strategy.head.root = root.id;
529
971
  node.parent = root.id;
530
972
  pointer.parent = root.id;
531
- this.bufferForNodeCreate(root);
532
973
  this.bufferForNodeUpdate(node);
533
974
  this.bufferForNodeUpdate(pointer);
534
975
  return;
@@ -564,7 +1005,6 @@ var BPTreeSync = class extends BPTree {
564
1005
  this.bufferForNodeUpdate(node2);
565
1006
  }
566
1007
  this._insertInParent(parentNode, midValue, parentPointer);
567
- this.bufferForNodeCreate(parentPointer);
568
1008
  this.bufferForNodeUpdate(parentNode);
569
1009
  }
570
1010
  }
@@ -576,7 +1016,6 @@ var BPTreeSync = class extends BPTree {
576
1016
  this.order = this.strategy.order;
577
1017
  this.root = this._createNode(true, [], [], true);
578
1018
  this.strategy.head.root = this.root.id;
579
- this.bufferForNodeCreate(this.root);
580
1019
  this.commitHeadBuffer();
581
1020
  this.commitNodeCreateBuffer();
582
1021
  } else {
@@ -590,10 +1029,11 @@ var BPTreeSync = class extends BPTree {
590
1029
  }
591
1030
  }
592
1031
  getNode(id) {
593
- if (!this.nodes.has(id)) {
594
- this.nodes.set(id, this.strategy.read(id));
1032
+ if (this._nodeCreateBuffer.has(id)) {
1033
+ return this._nodeCreateBuffer.get(id);
595
1034
  }
596
- return this.nodes.get(id);
1035
+ const cache = this.nodes.cache(id);
1036
+ return cache.raw;
597
1037
  }
598
1038
  insertableNode(value) {
599
1039
  let node = this.root;
@@ -615,6 +1055,25 @@ var BPTreeSync = class extends BPTree {
615
1055
  }
616
1056
  return node;
617
1057
  }
1058
+ insertableEndNode(value, direction) {
1059
+ const insertableNode = this.insertableNode(value);
1060
+ let key;
1061
+ switch (direction) {
1062
+ case -1:
1063
+ key = "prev";
1064
+ break;
1065
+ case 1:
1066
+ key = "next";
1067
+ break;
1068
+ default:
1069
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
1070
+ }
1071
+ const guessNode = insertableNode[key];
1072
+ if (!guessNode) {
1073
+ return null;
1074
+ }
1075
+ return this.getNode(guessNode);
1076
+ }
618
1077
  leftestNode() {
619
1078
  let node = this.root;
620
1079
  while (!node.leaf) {
@@ -623,6 +1082,14 @@ var BPTreeSync = class extends BPTree {
623
1082
  }
624
1083
  return node;
625
1084
  }
1085
+ rightestNode() {
1086
+ let node = this.root;
1087
+ while (!node.leaf) {
1088
+ const keys = node.keys;
1089
+ node = this.getNode(keys[keys.length - 1]);
1090
+ }
1091
+ return node;
1092
+ }
626
1093
  commitHeadBuffer() {
627
1094
  if (!this._strategyDirty) {
628
1095
  return;
@@ -653,10 +1120,10 @@ var BPTreeSync = class extends BPTree {
653
1120
  const key = k;
654
1121
  const value = condition[key];
655
1122
  const startNode = this.verifierStartNode[key](value);
1123
+ const endNode = this.verifierEndNode[key](value);
656
1124
  const direction = this.verifierDirection[key];
657
- const fullScan = this.verifierFullScan[key];
658
1125
  const comparator = this.verifierMap[key];
659
- const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
1126
+ const pairs = this.getPairs(value, startNode, endNode, comparator, direction);
660
1127
  if (!filterValues) {
661
1128
  filterValues = new Set(pairs.keys());
662
1129
  } else {
@@ -678,10 +1145,10 @@ var BPTreeSync = class extends BPTree {
678
1145
  const key = k;
679
1146
  const value = condition[key];
680
1147
  const startNode = this.verifierStartNode[key](value);
1148
+ const endNode = this.verifierEndNode[key](value);
681
1149
  const direction = this.verifierDirection[key];
682
- const fullScan = this.verifierFullScan[key];
683
1150
  const comparator = this.verifierMap[key];
684
- const pairs = this.getPairs(value, startNode, fullScan, comparator, direction);
1151
+ const pairs = this.getPairs(value, startNode, endNode, comparator, direction);
685
1152
  if (result === null) {
686
1153
  result = pairs;
687
1154
  } else {
@@ -722,7 +1189,6 @@ var BPTreeSync = class extends BPTree {
722
1189
  this.bufferForNodeUpdate(node);
723
1190
  }
724
1191
  this._insertInParent(before, after.values[0], after);
725
- this.bufferForNodeCreate(after);
726
1192
  this.bufferForNodeUpdate(before);
727
1193
  }
728
1194
  this.commitHeadBuffer();
@@ -788,28 +1254,35 @@ var BPTreeSync = class extends BPTree {
788
1254
 
789
1255
  // src/BPTreeAsync.ts
790
1256
  var BPTreeAsync = class extends BPTree {
791
- constructor(strategy, comparator) {
792
- super(strategy, comparator);
793
- }
794
- async getPairsRightToLeft(value, startNode, fullScan, comparator) {
1257
+ constructor(strategy, comparator, option) {
1258
+ super(strategy, comparator, option);
1259
+ this.nodes = this._createCachedNode();
1260
+ }
1261
+ _createCachedNode() {
1262
+ return new CacheEntanglementAsync(async (key) => {
1263
+ return await this.strategy.read(key);
1264
+ }, {
1265
+ lifespan: this.option.lifespan ?? "3m"
1266
+ });
1267
+ }
1268
+ async getPairsRightToLeft(value, startNode, endNode, comparator) {
795
1269
  const pairs = [];
796
1270
  let node = startNode;
797
1271
  let done = false;
798
- let found = false;
799
1272
  while (!done) {
1273
+ if (endNode && node.id === endNode.id) {
1274
+ done = true;
1275
+ break;
1276
+ }
800
1277
  let i = node.values.length;
801
1278
  while (i--) {
802
1279
  const nValue = node.values[i];
803
1280
  const keys = node.keys[i];
804
1281
  if (comparator(nValue, value)) {
805
- found = true;
806
1282
  let j = keys.length;
807
1283
  while (j--) {
808
1284
  pairs.push([keys[j], nValue]);
809
1285
  }
810
- } else if (found && !fullScan) {
811
- done = true;
812
- break;
813
1286
  }
814
1287
  }
815
1288
  if (!node.prev) {
@@ -820,24 +1293,23 @@ var BPTreeAsync = class extends BPTree {
820
1293
  }
821
1294
  return new Map(pairs.reverse());
822
1295
  }
823
- async getPairsLeftToRight(value, startNode, fullScan, comparator) {
1296
+ async getPairsLeftToRight(value, startNode, endNode, comparator) {
824
1297
  const pairs = [];
825
1298
  let node = startNode;
826
1299
  let done = false;
827
- let found = false;
828
1300
  while (!done) {
1301
+ if (endNode && node.id === endNode.id) {
1302
+ done = true;
1303
+ break;
1304
+ }
829
1305
  for (let i = 0, len = node.values.length; i < len; i++) {
830
1306
  const nValue = node.values[i];
831
1307
  const keys = node.keys[i];
832
1308
  if (comparator(nValue, value)) {
833
- found = true;
834
1309
  for (let j = 0, len2 = keys.length; j < len2; j++) {
835
1310
  const key = keys[j];
836
1311
  pairs.push([key, nValue]);
837
1312
  }
838
- } else if (found && !fullScan) {
839
- done = true;
840
- break;
841
1313
  }
842
1314
  }
843
1315
  if (!node.next) {
@@ -848,12 +1320,12 @@ var BPTreeAsync = class extends BPTree {
848
1320
  }
849
1321
  return new Map(pairs);
850
1322
  }
851
- async getPairs(value, startNode, fullScan, comparator, direction) {
1323
+ async getPairs(value, startNode, endNode, comparator, direction) {
852
1324
  switch (direction) {
853
1325
  case -1:
854
- return await this.getPairsRightToLeft(value, startNode, fullScan, comparator);
1326
+ return await this.getPairsRightToLeft(value, startNode, endNode, comparator);
855
1327
  case 1:
856
- return await this.getPairsLeftToRight(value, startNode, fullScan, comparator);
1328
+ return await this.getPairsLeftToRight(value, startNode, endNode, comparator);
857
1329
  default:
858
1330
  throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
859
1331
  }
@@ -876,7 +1348,7 @@ var BPTreeAsync = class extends BPTree {
876
1348
  next,
877
1349
  prev
878
1350
  };
879
- this.nodes.set(id, node);
1351
+ this._nodeCreateBuffer.set(id, node);
880
1352
  return node;
881
1353
  }
882
1354
  async _deleteEntry(node, key, value) {
@@ -1090,7 +1562,6 @@ var BPTreeAsync = class extends BPTree {
1090
1562
  this.strategy.head.root = root.id;
1091
1563
  node.parent = root.id;
1092
1564
  pointer.parent = root.id;
1093
- this.bufferForNodeCreate(root);
1094
1565
  this.bufferForNodeUpdate(node);
1095
1566
  this.bufferForNodeUpdate(pointer);
1096
1567
  return;
@@ -1126,7 +1597,6 @@ var BPTreeAsync = class extends BPTree {
1126
1597
  this.bufferForNodeUpdate(node2);
1127
1598
  }
1128
1599
  await this._insertInParent(parentNode, midValue, parentPointer);
1129
- this.bufferForNodeCreate(parentPointer);
1130
1600
  this.bufferForNodeUpdate(parentNode);
1131
1601
  }
1132
1602
  }
@@ -1138,7 +1608,6 @@ var BPTreeAsync = class extends BPTree {
1138
1608
  this.order = this.strategy.order;
1139
1609
  this.root = await this._createNode(true, [], [], true);
1140
1610
  this.strategy.head.root = this.root.id;
1141
- this.bufferForNodeCreate(this.root);
1142
1611
  await this.commitHeadBuffer();
1143
1612
  await this.commitNodeCreateBuffer();
1144
1613
  } else {
@@ -1152,10 +1621,11 @@ var BPTreeAsync = class extends BPTree {
1152
1621
  }
1153
1622
  }
1154
1623
  async getNode(id) {
1155
- if (!this.nodes.has(id)) {
1156
- this.nodes.set(id, await this.strategy.read(id));
1624
+ if (this._nodeCreateBuffer.has(id)) {
1625
+ return this._nodeCreateBuffer.get(id);
1157
1626
  }
1158
- return this.nodes.get(id);
1627
+ const cache = await this.nodes.cache(id);
1628
+ return cache.raw;
1159
1629
  }
1160
1630
  async insertableNode(value) {
1161
1631
  let node = this.root;
@@ -1177,6 +1647,25 @@ var BPTreeAsync = class extends BPTree {
1177
1647
  }
1178
1648
  return node;
1179
1649
  }
1650
+ async insertableEndNode(value, direction) {
1651
+ const insertableNode = await this.insertableNode(value);
1652
+ let key;
1653
+ switch (direction) {
1654
+ case -1:
1655
+ key = "prev";
1656
+ break;
1657
+ case 1:
1658
+ key = "next";
1659
+ break;
1660
+ default:
1661
+ throw new Error(`Direction must be -1 or 1. but got a ${direction}`);
1662
+ }
1663
+ const guessNode = insertableNode[key];
1664
+ if (!guessNode) {
1665
+ return null;
1666
+ }
1667
+ return await this.getNode(guessNode);
1668
+ }
1180
1669
  async leftestNode() {
1181
1670
  let node = this.root;
1182
1671
  while (!node.leaf) {
@@ -1185,6 +1674,14 @@ var BPTreeAsync = class extends BPTree {
1185
1674
  }
1186
1675
  return node;
1187
1676
  }
1677
+ async rightestNode() {
1678
+ let node = this.root;
1679
+ while (!node.leaf) {
1680
+ const keys = node.keys;
1681
+ node = await this.getNode(keys[keys.length - 1]);
1682
+ }
1683
+ return node;
1684
+ }
1188
1685
  async commitHeadBuffer() {
1189
1686
  if (!this._strategyDirty) {
1190
1687
  return;
@@ -1215,10 +1712,10 @@ var BPTreeAsync = class extends BPTree {
1215
1712
  const key = k;
1216
1713
  const value = condition[key];
1217
1714
  const startNode = await this.verifierStartNode[key](value);
1715
+ const endNode = await this.verifierEndNode[key](value);
1218
1716
  const direction = this.verifierDirection[key];
1219
- const fullScan = this.verifierFullScan[key];
1220
1717
  const comparator = this.verifierMap[key];
1221
- const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
1718
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1222
1719
  if (!filterValues) {
1223
1720
  filterValues = new Set(pairs.keys());
1224
1721
  } else {
@@ -1240,10 +1737,10 @@ var BPTreeAsync = class extends BPTree {
1240
1737
  const key = k;
1241
1738
  const value = condition[key];
1242
1739
  const startNode = await this.verifierStartNode[key](value);
1740
+ const endNode = await this.verifierEndNode[key](value);
1243
1741
  const direction = this.verifierDirection[key];
1244
- const fullScan = this.verifierFullScan[key];
1245
1742
  const comparator = this.verifierMap[key];
1246
- const pairs = await this.getPairs(value, startNode, fullScan, comparator, direction);
1743
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1247
1744
  if (result === null) {
1248
1745
  result = pairs;
1249
1746
  } else {
@@ -1284,7 +1781,6 @@ var BPTreeAsync = class extends BPTree {
1284
1781
  this.bufferForNodeUpdate(node);
1285
1782
  }
1286
1783
  await this._insertInParent(before, after.values[0], after);
1287
- this.bufferForNodeCreate(after);
1288
1784
  this.bufferForNodeUpdate(before);
1289
1785
  }
1290
1786
  await this.commitHeadBuffer();