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.
- package/dist/cjs/index.cjs +91 -224
- package/dist/esm/index.mjs +91 -224
- package/dist/types/BPTreeAsync.d.ts +1 -1
- package/dist/types/BPTreeSync.d.ts +1 -1
- package/dist/types/base/BPTree.d.ts +5 -8
- package/dist/types/index.d.ts +1 -1
- package/package.json +9 -9
package/dist/cjs/index.cjs
CHANGED
|
@@ -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
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
205
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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.
|
|
153
|
+
return this.map.size;
|
|
282
154
|
}
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
|
|
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
|
-
|
|
178
|
+
capacity,
|
|
302
179
|
beforeUpdateHook
|
|
303
180
|
} = option;
|
|
304
181
|
this.creation = creation;
|
|
305
182
|
this.beforeUpdateHook = beforeUpdateHook ?? (() => {
|
|
306
183
|
});
|
|
307
|
-
this.
|
|
184
|
+
this.capacity = capacity ?? 100;
|
|
308
185
|
this.assignments = [];
|
|
309
|
-
this.caches = new
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1180
|
+
capacity: this.option.capacity ?? 1e3
|
|
1314
1181
|
});
|
|
1315
1182
|
}
|
|
1316
1183
|
async getPairsRightToLeft(value, startNode, endNode, comparator) {
|
package/dist/esm/index.mjs
CHANGED
|
@@ -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
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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.
|
|
93
|
+
return this.map.has(key);
|
|
209
94
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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.
|
|
119
|
+
return this.map.size;
|
|
248
120
|
}
|
|
249
|
-
|
|
250
|
-
|
|
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
|
-
|
|
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
|
-
|
|
144
|
+
capacity,
|
|
268
145
|
beforeUpdateHook
|
|
269
146
|
} = option;
|
|
270
147
|
this.creation = creation;
|
|
271
148
|
this.beforeUpdateHook = beforeUpdateHook ?? (() => {
|
|
272
149
|
});
|
|
273
|
-
this.
|
|
150
|
+
this.capacity = capacity ?? 100;
|
|
274
151
|
this.assignments = [];
|
|
275
|
-
this.caches = new
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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<
|
|
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<
|
|
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
|
|
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
|
|
31
|
-
* This value is used to determine how
|
|
32
|
-
* If
|
|
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
|
-
|
|
34
|
+
capacity?: number;
|
|
38
35
|
}
|
|
39
36
|
export interface BPTreeNode<K, V> {
|
|
40
37
|
id: string;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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.
|
|
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
|
|
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": "^
|
|
40
|
-
"esbuild": "^0.
|
|
41
|
-
"jest": "^
|
|
42
|
-
"ts-jest": "^29.4.
|
|
43
|
-
"typescript": "^5.
|
|
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.
|
|
46
|
+
"cache-entanglement": "^1.7.0"
|
|
47
47
|
}
|
|
48
|
-
}
|
|
48
|
+
}
|