serializable-bptree 5.1.6 → 5.2.0

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.
@@ -62,232 +62,109 @@ var StringComparator = class extends ValueComparator {
62
62
  };
63
63
 
64
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 });
65
+ var LRUMap = class {
66
+ capacity;
67
+ map;
68
+ head = null;
69
+ tail = null;
70
+ constructor(capacity) {
71
+ this.capacity = capacity;
72
+ this.map = /* @__PURE__ */ new Map();
73
+ }
74
+ // 내부 유틸리티: 노드를 헤드로 이동 (가장 최근 사용됨 표시)
75
+ promote(node) {
76
+ this.extract(node);
77
+ this.prepend(node);
78
+ }
79
+ // 내부 유틸리티: 리스트에서 노드 연결 끊기
80
+ extract(node) {
81
+ if (node.prev) node.prev.next = node.next;
82
+ else this.head = node.next;
83
+ if (node.next) node.next.prev = node.prev;
84
+ else this.tail = node.prev;
85
+ node.prev = null;
86
+ node.next = null;
87
+ }
88
+ // 내부 유틸리티: 리스트 맨 앞에 노드 삽입
89
+ prepend(node) {
90
+ node.next = this.head;
91
+ if (this.head) this.head.prev = node;
92
+ this.head = node;
93
+ if (!this.tail) this.tail = node;
79
94
  }
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";
95
+ /**
96
+ * 데이터를 저장하거나 업데이트합니다.
97
+ * 용량 초과 가장 오래된 항목(tail) 제거합니다.
98
+ */
99
+ set(key, value) {
100
+ const existing = this.map.get(key);
101
+ if (existing) {
102
+ existing.value = value;
103
+ this.promote(existing);
104
+ return;
197
105
  }
198
- function plural(ms2, msAbs, n, name) {
199
- var isPlural = msAbs >= n * 1.5;
200
- return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
106
+ const newNode = { key, value, prev: null, next: null };
107
+ this.map.set(key, newNode);
108
+ this.prepend(newNode);
109
+ if (this.map.size > this.capacity && this.tail) {
110
+ this.map.delete(this.tail.key);
111
+ this.extract(this.tail);
201
112
  }
202
113
  }
203
- });
204
- var import_ms = __toESM(require_ms());
205
- var InvertedWeakMap = class {
206
- _map;
207
- _keepAlive;
208
- _timeouts;
209
- _registry;
210
- _lifespan;
211
- constructor(option) {
212
- const { lifespan } = option;
213
- this._lifespan = lifespan;
214
- this._map = /* @__PURE__ */ new Map();
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
- });
221
- }
222
- clear() {
223
- this._keepAlive.clear();
224
- this._map.clear();
225
- }
226
- delete(key) {
227
- const ref = this._map.get(key);
228
- if (ref) {
229
- const raw = ref.deref();
230
- if (raw !== void 0) {
231
- this._registry.unregister(raw);
232
- }
233
- }
234
- this._stopExpire(key, true);
235
- this._keepAlive.delete(key);
236
- return this._map.delete(key);
237
- }
114
+ /**
115
+ * 데이터를 가져옵니다. 접근한 데이터는 "최근 사용됨"으로 갱신됩니다.
116
+ */
238
117
  get(key) {
239
- return this._map.get(key)?.deref();
118
+ const node = this.map.get(key);
119
+ if (!node) return void 0;
120
+ this.promote(node);
121
+ return node.value;
240
122
  }
123
+ /**
124
+ * 키의 존재 여부를 확인합니다. (순서는 변경하지 않는 것이 일반적입니다)
125
+ */
241
126
  has(key) {
242
- return this._map.has(key) && this.get(key) !== void 0;
243
- }
244
- set(key, value) {
245
- this._map.set(key, new WeakRef(value));
246
- this._registry.register(value, key);
247
- if (this._lifespan > 0) {
248
- this._stopExpire(key, true);
249
- this._startExpire(key, value);
250
- }
251
- return this;
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));
127
+ return this.map.has(key);
262
128
  }
263
- _startExpire(key, value) {
264
- this._keepAlive.set(key, value);
265
- this._timeouts.set(key, setTimeout(() => {
266
- this._keepAlive.delete(key);
267
- }, this._lifespan));
129
+ /**
130
+ * 특정 키와 데이터를 캐시에서 완전히 제거합니다.
131
+ */
132
+ delete(key) {
133
+ const node = this.map.get(key);
134
+ if (!node) return false;
135
+ this.extract(node);
136
+ this.map.delete(key);
137
+ return true;
268
138
  }
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);
139
+ /**
140
+ * 현재 캐시된 키들을 최근 사용된 순서대로 반환합니다.
141
+ */
142
+ *keys() {
143
+ let current = this.head;
144
+ while (current) {
145
+ yield current.key;
146
+ current = current.next;
278
147
  }
279
148
  }
149
+ /**
150
+ * 현재 캐시된 아이템의 개수를 반환합니다.
151
+ */
280
152
  get size() {
281
- return this._map.size;
153
+ return this.map.size;
282
154
  }
283
- keys() {
284
- return this._map.keys();
155
+ /**
156
+ * 캐시를 완전히 비웁니다.
157
+ */
158
+ clear() {
159
+ this.map.clear();
160
+ this.head = null;
161
+ this.tail = null;
285
162
  }
286
163
  };
287
164
  var CacheEntanglement = class {
288
165
  creation;
289
166
  beforeUpdateHook;
290
- lifespan;
167
+ capacity;
291
168
  dependencies;
292
169
  caches;
293
170
  parameters;
@@ -298,15 +175,15 @@ var CacheEntanglement = class {
298
175
  option = option ?? {};
299
176
  const {
300
177
  dependencies,
301
- lifespan,
178
+ capacity,
302
179
  beforeUpdateHook
303
180
  } = option;
304
181
  this.creation = creation;
305
182
  this.beforeUpdateHook = beforeUpdateHook ?? (() => {
306
183
  });
307
- this.lifespan = this._normalizeMs(lifespan ?? 0);
184
+ this.capacity = capacity ?? 100;
308
185
  this.assignments = [];
309
- this.caches = new InvertedWeakMap({ lifespan: this.lifespan });
186
+ this.caches = new LRUMap(this.capacity);
310
187
  this.parameters = /* @__PURE__ */ new Map();
311
188
  this.dependencies = dependencies ?? {};
312
189
  this.dependencyProperties = Object.keys(this.dependencies);
@@ -318,12 +195,6 @@ var CacheEntanglement = class {
318
195
  }
319
196
  }
320
197
  }
321
- _normalizeMs(time) {
322
- if (typeof time === "string") {
323
- return (0, import_ms.default)(time);
324
- }
325
- return time;
326
- }
327
198
  bubbleUpdateSignal(key) {
328
199
  this.updateRequirements.add(key);
329
200
  for (let i = 0, len = this.assignments.length; i < len; i++) {
@@ -480,8 +351,6 @@ var CacheEntanglementSync = class extends CacheEntanglement {
480
351
  cache(key, ...parameter) {
481
352
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
482
353
  this.resolve(key, ...parameter);
483
- } else {
484
- this.caches.extendExpire(key);
485
354
  }
486
355
  return this.caches.get(key);
487
356
  }
@@ -536,8 +405,6 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
536
405
  async cache(key, ...parameter) {
537
406
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
538
407
  await this.update(key, ...parameter);
539
- } else {
540
- this.caches.extendExpire(key);
541
408
  }
542
409
  return this.caches.get(key);
543
410
  }
@@ -625,7 +492,7 @@ var BPTree = class {
625
492
  const regexp = new RegExp(`^${pattern}$`, "i");
626
493
  return regexp;
627
494
  }, {
628
- lifespan: this.option.lifespan ?? "3m"
495
+ capacity: this.option.capacity ?? 1e3
629
496
  });
630
497
  }
631
498
  ensureValues(v) {
@@ -718,7 +585,7 @@ var BPTreeSync = class extends BPTree {
718
585
  return new CacheEntanglementSync((key) => {
719
586
  return this.strategy.read(key);
720
587
  }, {
721
- lifespan: this.option.lifespan ?? "3m"
588
+ capacity: this.option.capacity ?? 1e3
722
589
  });
723
590
  }
724
591
  getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -1310,7 +1177,7 @@ var BPTreeAsync = class extends BPTree {
1310
1177
  return new CacheEntanglementAsync(async (key) => {
1311
1178
  return await this.strategy.read(key);
1312
1179
  }, {
1313
- lifespan: this.option.lifespan ?? "3m"
1180
+ capacity: this.option.capacity ?? 1e3
1314
1181
  });
1315
1182
  }
1316
1183
  async getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -28,232 +28,109 @@ var StringComparator = class extends ValueComparator {
28
28
  };
29
29
 
30
30
  // node_modules/cache-entanglement/dist/esm/index.mjs
31
- var __create = Object.create;
32
- var __defProp = Object.defineProperty;
33
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
34
- var __getOwnPropNames = Object.getOwnPropertyNames;
35
- var __getProtoOf = Object.getPrototypeOf;
36
- var __hasOwnProp = Object.prototype.hasOwnProperty;
37
- var __commonJS = (cb, mod) => function __require() {
38
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
39
- };
40
- var __copyProps = (to, from, except, desc) => {
41
- if (from && typeof from === "object" || typeof from === "function") {
42
- for (let key of __getOwnPropNames(from))
43
- if (!__hasOwnProp.call(to, key) && key !== except)
44
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
31
+ var LRUMap = class {
32
+ capacity;
33
+ map;
34
+ head = null;
35
+ tail = null;
36
+ constructor(capacity) {
37
+ this.capacity = capacity;
38
+ this.map = /* @__PURE__ */ new Map();
39
+ }
40
+ // 내부 유틸리티: 노드를 헤드로 이동 (가장 최근 사용됨 표시)
41
+ promote(node) {
42
+ this.extract(node);
43
+ this.prepend(node);
44
+ }
45
+ // 내부 유틸리티: 리스트에서 노드 연결 끊기
46
+ extract(node) {
47
+ if (node.prev) node.prev.next = node.next;
48
+ else this.head = node.next;
49
+ if (node.next) node.next.prev = node.prev;
50
+ else this.tail = node.prev;
51
+ node.prev = null;
52
+ node.next = null;
53
+ }
54
+ // 내부 유틸리티: 리스트 맨 앞에 노드 삽입
55
+ prepend(node) {
56
+ node.next = this.head;
57
+ if (this.head) this.head.prev = node;
58
+ this.head = node;
59
+ if (!this.tail) this.tail = node;
45
60
  }
46
- return to;
47
- };
48
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
49
- // If the importer is in node compatibility mode or this is not an ESM
50
- // file that has been converted to a CommonJS file using a Babel-
51
- // compatible transform (i.e. "__esModule" has not been set), then set
52
- // "default" to the CommonJS "module.exports" for node compatibility.
53
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
54
- mod
55
- ));
56
- var require_ms = __commonJS({
57
- "node_modules/ms/index.js"(exports, module) {
58
- var s = 1e3;
59
- var m = s * 60;
60
- var h = m * 60;
61
- var d = h * 24;
62
- var w = d * 7;
63
- var y = d * 365.25;
64
- module.exports = function(val, options) {
65
- options = options || {};
66
- var type = typeof val;
67
- if (type === "string" && val.length > 0) {
68
- return parse(val);
69
- } else if (type === "number" && isFinite(val)) {
70
- return options.long ? fmtLong(val) : fmtShort(val);
71
- }
72
- throw new Error(
73
- "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
74
- );
75
- };
76
- function parse(str) {
77
- str = String(str);
78
- if (str.length > 100) {
79
- return;
80
- }
81
- 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(
82
- str
83
- );
84
- if (!match) {
85
- return;
86
- }
87
- var n = parseFloat(match[1]);
88
- var type = (match[2] || "ms").toLowerCase();
89
- switch (type) {
90
- case "years":
91
- case "year":
92
- case "yrs":
93
- case "yr":
94
- case "y":
95
- return n * y;
96
- case "weeks":
97
- case "week":
98
- case "w":
99
- return n * w;
100
- case "days":
101
- case "day":
102
- case "d":
103
- return n * d;
104
- case "hours":
105
- case "hour":
106
- case "hrs":
107
- case "hr":
108
- case "h":
109
- return n * h;
110
- case "minutes":
111
- case "minute":
112
- case "mins":
113
- case "min":
114
- case "m":
115
- return n * m;
116
- case "seconds":
117
- case "second":
118
- case "secs":
119
- case "sec":
120
- case "s":
121
- return n * s;
122
- case "milliseconds":
123
- case "millisecond":
124
- case "msecs":
125
- case "msec":
126
- case "ms":
127
- return n;
128
- default:
129
- return void 0;
130
- }
131
- }
132
- function fmtShort(ms2) {
133
- var msAbs = Math.abs(ms2);
134
- if (msAbs >= d) {
135
- return Math.round(ms2 / d) + "d";
136
- }
137
- if (msAbs >= h) {
138
- return Math.round(ms2 / h) + "h";
139
- }
140
- if (msAbs >= m) {
141
- return Math.round(ms2 / m) + "m";
142
- }
143
- if (msAbs >= s) {
144
- return Math.round(ms2 / s) + "s";
145
- }
146
- return ms2 + "ms";
61
+ /**
62
+ * 데이터를 저장하거나 업데이트합니다.
63
+ * 용량 초과 가장 오래된 항목(tail) 제거합니다.
64
+ */
65
+ set(key, value) {
66
+ const existing = this.map.get(key);
67
+ if (existing) {
68
+ existing.value = value;
69
+ this.promote(existing);
70
+ return;
147
71
  }
148
- function fmtLong(ms2) {
149
- var msAbs = Math.abs(ms2);
150
- if (msAbs >= d) {
151
- return plural(ms2, msAbs, d, "day");
152
- }
153
- if (msAbs >= h) {
154
- return plural(ms2, msAbs, h, "hour");
155
- }
156
- if (msAbs >= m) {
157
- return plural(ms2, msAbs, m, "minute");
158
- }
159
- if (msAbs >= s) {
160
- return plural(ms2, msAbs, s, "second");
161
- }
162
- return ms2 + " ms";
163
- }
164
- function plural(ms2, msAbs, n, name) {
165
- var isPlural = msAbs >= n * 1.5;
166
- return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
167
- }
168
- }
169
- });
170
- var import_ms = __toESM(require_ms());
171
- var InvertedWeakMap = class {
172
- _map;
173
- _keepAlive;
174
- _timeouts;
175
- _registry;
176
- _lifespan;
177
- constructor(option) {
178
- const { lifespan } = option;
179
- this._lifespan = lifespan;
180
- this._map = /* @__PURE__ */ new Map();
181
- this._keepAlive = /* @__PURE__ */ new Map();
182
- this._timeouts = /* @__PURE__ */ new Map();
183
- this._registry = new FinalizationRegistry((key) => {
184
- this._stopExpire(key, true);
185
- this._map.delete(key);
186
- });
187
- }
188
- clear() {
189
- this._keepAlive.clear();
190
- this._map.clear();
191
- }
192
- delete(key) {
193
- const ref = this._map.get(key);
194
- if (ref) {
195
- const raw = ref.deref();
196
- if (raw !== void 0) {
197
- this._registry.unregister(raw);
198
- }
72
+ const newNode = { key, value, prev: null, next: null };
73
+ this.map.set(key, newNode);
74
+ this.prepend(newNode);
75
+ if (this.map.size > this.capacity && this.tail) {
76
+ this.map.delete(this.tail.key);
77
+ this.extract(this.tail);
199
78
  }
200
- this._stopExpire(key, true);
201
- this._keepAlive.delete(key);
202
- return this._map.delete(key);
203
79
  }
80
+ /**
81
+ * 데이터를 가져옵니다. 접근한 데이터는 "최근 사용됨"으로 갱신됩니다.
82
+ */
204
83
  get(key) {
205
- return this._map.get(key)?.deref();
84
+ const node = this.map.get(key);
85
+ if (!node) return void 0;
86
+ this.promote(node);
87
+ return node.value;
206
88
  }
89
+ /**
90
+ * 키의 존재 여부를 확인합니다. (순서는 변경하지 않는 것이 일반적입니다)
91
+ */
207
92
  has(key) {
208
- return this._map.has(key) && this.get(key) !== void 0;
93
+ return this.map.has(key);
209
94
  }
210
- set(key, value) {
211
- this._map.set(key, new WeakRef(value));
212
- this._registry.register(value, key);
213
- if (this._lifespan > 0) {
214
- this._stopExpire(key, true);
215
- this._startExpire(key, value);
216
- }
217
- return this;
218
- }
219
- extendExpire(key) {
220
- if (!(this._lifespan > 0)) {
221
- return;
222
- }
223
- if (!this._keepAlive.has(key)) {
224
- return;
225
- }
226
- this._stopExpire(key, false);
227
- this._startExpire(key, this._keepAlive.get(key));
228
- }
229
- _startExpire(key, value) {
230
- this._keepAlive.set(key, value);
231
- this._timeouts.set(key, setTimeout(() => {
232
- this._keepAlive.delete(key);
233
- }, this._lifespan));
95
+ /**
96
+ * 특정 키와 데이터를 캐시에서 완전히 제거합니다.
97
+ */
98
+ delete(key) {
99
+ const node = this.map.get(key);
100
+ if (!node) return false;
101
+ this.extract(node);
102
+ this.map.delete(key);
103
+ return true;
234
104
  }
235
- _stopExpire(key, removeKeepAlive) {
236
- if (!this._timeouts.has(key)) {
237
- return;
238
- }
239
- const timeout = this._timeouts.get(key);
240
- this._timeouts.delete(key);
241
- clearTimeout(timeout);
242
- if (removeKeepAlive) {
243
- this._keepAlive.delete(key);
105
+ /**
106
+ * 현재 캐시된 키들을 최근 사용된 순서대로 반환합니다.
107
+ */
108
+ *keys() {
109
+ let current = this.head;
110
+ while (current) {
111
+ yield current.key;
112
+ current = current.next;
244
113
  }
245
114
  }
115
+ /**
116
+ * 현재 캐시된 아이템의 개수를 반환합니다.
117
+ */
246
118
  get size() {
247
- return this._map.size;
119
+ return this.map.size;
248
120
  }
249
- keys() {
250
- return this._map.keys();
121
+ /**
122
+ * 캐시를 완전히 비웁니다.
123
+ */
124
+ clear() {
125
+ this.map.clear();
126
+ this.head = null;
127
+ this.tail = null;
251
128
  }
252
129
  };
253
130
  var CacheEntanglement = class {
254
131
  creation;
255
132
  beforeUpdateHook;
256
- lifespan;
133
+ capacity;
257
134
  dependencies;
258
135
  caches;
259
136
  parameters;
@@ -264,15 +141,15 @@ var CacheEntanglement = class {
264
141
  option = option ?? {};
265
142
  const {
266
143
  dependencies,
267
- lifespan,
144
+ capacity,
268
145
  beforeUpdateHook
269
146
  } = option;
270
147
  this.creation = creation;
271
148
  this.beforeUpdateHook = beforeUpdateHook ?? (() => {
272
149
  });
273
- this.lifespan = this._normalizeMs(lifespan ?? 0);
150
+ this.capacity = capacity ?? 100;
274
151
  this.assignments = [];
275
- this.caches = new InvertedWeakMap({ lifespan: this.lifespan });
152
+ this.caches = new LRUMap(this.capacity);
276
153
  this.parameters = /* @__PURE__ */ new Map();
277
154
  this.dependencies = dependencies ?? {};
278
155
  this.dependencyProperties = Object.keys(this.dependencies);
@@ -284,12 +161,6 @@ var CacheEntanglement = class {
284
161
  }
285
162
  }
286
163
  }
287
- _normalizeMs(time) {
288
- if (typeof time === "string") {
289
- return (0, import_ms.default)(time);
290
- }
291
- return time;
292
- }
293
164
  bubbleUpdateSignal(key) {
294
165
  this.updateRequirements.add(key);
295
166
  for (let i = 0, len = this.assignments.length; i < len; i++) {
@@ -446,8 +317,6 @@ var CacheEntanglementSync = class extends CacheEntanglement {
446
317
  cache(key, ...parameter) {
447
318
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
448
319
  this.resolve(key, ...parameter);
449
- } else {
450
- this.caches.extendExpire(key);
451
320
  }
452
321
  return this.caches.get(key);
453
322
  }
@@ -502,8 +371,6 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
502
371
  async cache(key, ...parameter) {
503
372
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
504
373
  await this.update(key, ...parameter);
505
- } else {
506
- this.caches.extendExpire(key);
507
374
  }
508
375
  return this.caches.get(key);
509
376
  }
@@ -591,7 +458,7 @@ var BPTree = class {
591
458
  const regexp = new RegExp(`^${pattern}$`, "i");
592
459
  return regexp;
593
460
  }, {
594
- lifespan: this.option.lifespan ?? "3m"
461
+ capacity: this.option.capacity ?? 1e3
595
462
  });
596
463
  }
597
464
  ensureValues(v) {
@@ -684,7 +551,7 @@ var BPTreeSync = class extends BPTree {
684
551
  return new CacheEntanglementSync((key) => {
685
552
  return this.strategy.read(key);
686
553
  }, {
687
- lifespan: this.option.lifespan ?? "3m"
554
+ capacity: this.option.capacity ?? 1e3
688
555
  });
689
556
  }
690
557
  getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -1276,7 +1143,7 @@ var BPTreeAsync = class extends BPTree {
1276
1143
  return new CacheEntanglementAsync(async (key) => {
1277
1144
  return await this.strategy.read(key);
1278
1145
  }, {
1279
- lifespan: this.option.lifespan ?? "3m"
1146
+ capacity: this.option.capacity ?? 1e3
1280
1147
  });
1281
1148
  }
1282
1149
  async getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -4,7 +4,7 @@ import { ValueComparator } from './base/ValueComparator';
4
4
  import { SerializableData } from './base/SerializeStrategy';
5
5
  export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
6
6
  protected readonly strategy: SerializeStrategyAsync<K, V>;
7
- protected readonly nodes: ReturnType<BPTreeAsync<K, V>['_createCachedNode']>;
7
+ protected readonly nodes: ReturnType<typeof this._createCachedNode>;
8
8
  constructor(strategy: SerializeStrategyAsync<K, V>, comparator: ValueComparator<V>, option?: BPTreeConstructorOption);
9
9
  private _createCachedNode;
10
10
  protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
@@ -4,7 +4,7 @@ import { ValueComparator } from './base/ValueComparator';
4
4
  import { SerializableData } from './base/SerializeStrategy';
5
5
  export declare class BPTreeSync<K, V> extends BPTree<K, V> {
6
6
  protected readonly strategy: SerializeStrategySync<K, V>;
7
- protected readonly nodes: ReturnType<BPTreeSync<K, V>['_createCachedNode']>;
7
+ protected readonly nodes: ReturnType<typeof this._createCachedNode>;
8
8
  constructor(strategy: SerializeStrategySync<K, V>, comparator: ValueComparator<V>, option?: BPTreeConstructorOption);
9
9
  private _createCachedNode;
10
10
  protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>;
@@ -1,4 +1,4 @@
1
- import { CacheEntanglementSync, CacheEntanglementAsync, type StringValue } from 'cache-entanglement';
1
+ import { CacheEntanglementSync, CacheEntanglementAsync } from 'cache-entanglement';
2
2
  import { ValueComparator } from './ValueComparator';
3
3
  import { SerializableData, SerializeStrategy } from './SerializeStrategy';
4
4
  type Sync<T> = T;
@@ -27,14 +27,11 @@ export type BPTreePair<K, V> = Map<K, V>;
27
27
  export type BPTreeUnknownNode<K, V> = BPTreeInternalNode<K, V> | BPTreeLeafNode<K, V>;
28
28
  export interface BPTreeConstructorOption {
29
29
  /**
30
- * The lifespan of the cached node.
31
- * This value is used to determine how long a cached node should be kept in memory.
32
- * If the lifespan is set to a positive number, the cached node will expire after the specified number of milliseconds.
33
- * If the lifespan is set to `0` or a negative number, the cache will not prevent garbage collection.
34
- * If the lifespan is set to a string, the string will be parsed as a time duration.
35
- * For example, '1m' means 1 minute, '1h' means 1 hour, '1d' means 1 day, '1w' means 1 week.
30
+ * The capacity of the cache.
31
+ * This value is used to determine how many nodes can be cached.
32
+ * If not specified, the default value is 1000.
36
33
  */
37
- lifespan?: StringValue | number;
34
+ capacity?: number;
38
35
  }
39
36
  export interface BPTreeNode<K, V> {
40
37
  id: string;
@@ -1,4 +1,4 @@
1
- export type { BPTreeNode, BPTreeCondition } from './base/BPTree';
1
+ export type { BPTreeNode, BPTreeInternalNode, BPTreeLeafNode, BPTreeNodeKey, BPTreePair, BPTreeUnknownNode, BPTreeCondition } from './base/BPTree';
2
2
  export type { SerializeStrategyHead, SerializableData } from './base/SerializeStrategy';
3
3
  export { ValueComparator, NumericComparator, StringComparator } from './base/ValueComparator';
4
4
  export { BPTreeSync } from './BPTreeSync';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serializable-bptree",
3
- "version": "5.1.6",
3
+ "version": "5.2.0",
4
4
  "description": "Store the B+tree flexibly, not only in-memory.",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "main": "./dist/cjs/index.cjs",
@@ -16,7 +16,7 @@
16
16
  "dist/**/*"
17
17
  ],
18
18
  "scripts": {
19
- "test": "jest -t",
19
+ "test": "jest",
20
20
  "build": "node build/index.js && tsc"
21
21
  },
22
22
  "author": "izure <admin@izure.org>",
@@ -36,13 +36,13 @@
36
36
  },
37
37
  "license": "MIT",
38
38
  "devDependencies": {
39
- "@types/jest": "^29.5.14",
40
- "esbuild": "^0.25.5",
41
- "jest": "^29.7.0",
42
- "ts-jest": "^29.4.0",
43
- "typescript": "^5.8.3"
39
+ "@types/jest": "^30.0.0",
40
+ "esbuild": "^0.27.2",
41
+ "jest": "^30.2.0",
42
+ "ts-jest": "^29.4.6",
43
+ "typescript": "^5.9.3"
44
44
  },
45
45
  "dependencies": {
46
- "cache-entanglement": "^1.6.0"
46
+ "cache-entanglement": "^1.7.0"
47
47
  }
48
- }
48
+ }