node-ctypes 0.1.7 → 1.0.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.
Potentially problematic release.
This version of node-ctypes might be problematic. Click here for more details.
- package/README.md +13 -8
- package/build/Release/ctypes-darwin-arm64.node +0 -0
- package/build/Release/ctypes-darwin-x64.node +0 -0
- package/build/Release/ctypes-linux-arm64.node +0 -0
- package/build/Release/ctypes-linux-x64.node +0 -0
- package/build/Release/ctypes-win32-arm64.node +0 -0
- package/build/Release/ctypes-win32-x64.node +0 -0
- package/lib/core/Library.js +312 -0
- package/lib/core/callback.js +275 -0
- package/lib/core/types.js +140 -0
- package/lib/index.d.ts +71 -124
- package/lib/index.js +215 -3096
- package/lib/memory/buffer.js +404 -0
- package/lib/memory/operations.js +295 -0
- package/lib/memory/pointer.js +358 -0
- package/lib/platform/constants.js +110 -0
- package/lib/platform/errors.js +403 -0
- package/lib/structures/Structure.js +414 -0
- package/lib/structures/Union.js +102 -0
- package/lib/structures/helpers/array.js +261 -0
- package/lib/structures/helpers/bitfield.js +147 -0
- package/lib/structures/helpers/common.js +129 -0
- package/lib/structures/helpers/struct.js +925 -0
- package/lib/structures/helpers/union.js +465 -0
- package/lib/types/SimpleCData.js +193 -0
- package/lib/types/primitives.js +392 -0
- package/lib/utils/cache.js +142 -0
- package/package.json +1 -1
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file primitives.js
|
|
3
|
+
* @module types/primitives
|
|
4
|
+
* @description Primitive C type definitions (integers, floats, chars, pointers).
|
|
5
|
+
*
|
|
6
|
+
* This module provides all primitive C types that extend SimpleCData. Each type
|
|
7
|
+
* defines its size, type name, and read/write functions for buffer operations.
|
|
8
|
+
*
|
|
9
|
+
* **Python ctypes Compatibility**:
|
|
10
|
+
* All types are compatible with Python's ctypes module equivalents.
|
|
11
|
+
*
|
|
12
|
+
* @example Using integer types
|
|
13
|
+
* ```javascript
|
|
14
|
+
* import { c_int32, c_uint64 } from 'node-ctypes';
|
|
15
|
+
*
|
|
16
|
+
* const x = new c_int32(42);
|
|
17
|
+
* console.log(x.value); // 42
|
|
18
|
+
* x.value = -100;
|
|
19
|
+
*
|
|
20
|
+
* const big = new c_uint64(9007199254740991n);
|
|
21
|
+
* console.log(big.value); // 9007199254740991n
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example Using float types
|
|
25
|
+
* ```javascript
|
|
26
|
+
* import { c_float, c_double } from 'node-ctypes';
|
|
27
|
+
*
|
|
28
|
+
* const pi = new c_float(3.14159);
|
|
29
|
+
* console.log(pi.value); // ~3.1415898799896240 (float precision)
|
|
30
|
+
*
|
|
31
|
+
* const precise = new c_double(3.141592653589793);
|
|
32
|
+
* console.log(precise.value); // 3.141592653589793
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example Using character types
|
|
36
|
+
* ```javascript
|
|
37
|
+
* import { c_char, c_wchar } from 'node-ctypes';
|
|
38
|
+
*
|
|
39
|
+
* const ch = new c_char('A'.charCodeAt(0));
|
|
40
|
+
* console.log(ch.value); // 65
|
|
41
|
+
*
|
|
42
|
+
* const wide = new c_wchar(0x4E2D); // Chinese character
|
|
43
|
+
* console.log(wide.value); // 20013
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @example Using pointer types
|
|
47
|
+
* ```javascript
|
|
48
|
+
* import { c_void_p, c_char_p } from 'node-ctypes';
|
|
49
|
+
*
|
|
50
|
+
* const ptr = new c_void_p(0x1234n);
|
|
51
|
+
* console.log(ptr.value); // 4660n
|
|
52
|
+
*
|
|
53
|
+
* const str = new c_char_p("Hello");
|
|
54
|
+
* console.log(str.value); // "Hello"
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates all primitive type classes with required dependencies injected.
|
|
60
|
+
*
|
|
61
|
+
* @param {Class} SimpleCData - SimpleCData base class
|
|
62
|
+
* @param {Object} native - Native module with POINTER_SIZE
|
|
63
|
+
* @param {Function} addressOf - addressOf function for pointers
|
|
64
|
+
* @param {Function} cstring - cstring function for c_char_p
|
|
65
|
+
* @param {Function} wstring - wstring function for c_wchar_p
|
|
66
|
+
* @param {Function} readCString - readCString function for c_char_p
|
|
67
|
+
* @param {Function} readWString - readWString function for c_wchar_p
|
|
68
|
+
* @returns {Object} Object containing all primitive type classes
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
export function createPrimitiveTypes(SimpleCData, native, addressOf, cstring, wstring, readCString, readWString) {
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// Void type
|
|
74
|
+
// ============================================================================
|
|
75
|
+
|
|
76
|
+
class c_void extends SimpleCData {
|
|
77
|
+
static _size = 0;
|
|
78
|
+
static _type = "void";
|
|
79
|
+
static _reader = (buf, off) => undefined;
|
|
80
|
+
static _writer = (buf, off, val) => {};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Integer types - signed
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
class c_int8 extends SimpleCData {
|
|
88
|
+
static _size = 1;
|
|
89
|
+
static _type = "int8";
|
|
90
|
+
static _reader = (buf, off) => buf.readInt8(off);
|
|
91
|
+
static _writer = (buf, off, val) => buf.writeInt8(val, off);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
class c_int16 extends SimpleCData {
|
|
95
|
+
static _size = 2;
|
|
96
|
+
static _type = "int16";
|
|
97
|
+
static _reader = (buf, off) => buf.readInt16LE(off);
|
|
98
|
+
static _writer = (buf, off, val) => buf.writeInt16LE(val, off);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
class c_int32 extends SimpleCData {
|
|
102
|
+
static _size = 4;
|
|
103
|
+
static _type = "int32";
|
|
104
|
+
static _reader = (buf, off) => buf.readInt32LE(off);
|
|
105
|
+
static _writer = (buf, off, val) => {
|
|
106
|
+
const v = Number(val) | 0; // coerce to signed 32-bit
|
|
107
|
+
return buf.writeInt32LE(v, off);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
class c_int64 extends SimpleCData {
|
|
112
|
+
static _size = 8;
|
|
113
|
+
static _type = "int64";
|
|
114
|
+
static _reader = (buf, off) => buf.readBigInt64LE(off);
|
|
115
|
+
static _writer = (buf, off, val) => buf.writeBigInt64LE(BigInt(val), off);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// Integer types - unsigned
|
|
120
|
+
// ============================================================================
|
|
121
|
+
|
|
122
|
+
class c_uint8 extends SimpleCData {
|
|
123
|
+
static _size = 1;
|
|
124
|
+
static _type = "uint8";
|
|
125
|
+
static _reader = (buf, off) => buf.readUInt8(off);
|
|
126
|
+
static _writer = (buf, off, val) => buf.writeUInt8(val, off);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
class c_uint16 extends SimpleCData {
|
|
130
|
+
static _size = 2;
|
|
131
|
+
static _type = "uint16";
|
|
132
|
+
static _reader = (buf, off) => buf.readUInt16LE(off);
|
|
133
|
+
static _writer = (buf, off, val) => buf.writeUInt16LE(val, off);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
class c_uint32 extends SimpleCData {
|
|
137
|
+
static _size = 4;
|
|
138
|
+
static _type = "uint32";
|
|
139
|
+
static _reader = (buf, off) => buf.readUInt32LE(off);
|
|
140
|
+
static _writer = (buf, off, val) => {
|
|
141
|
+
const v = Number(val) >>> 0; // coerce to unsigned 32-bit
|
|
142
|
+
return buf.writeUInt32LE(v, off);
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
class c_uint64 extends SimpleCData {
|
|
147
|
+
static _size = 8;
|
|
148
|
+
static _type = "uint64";
|
|
149
|
+
static _reader = (buf, off) => buf.readBigUInt64LE(off);
|
|
150
|
+
static _writer = (buf, off, val) => buf.writeBigUInt64LE(BigInt(val), off);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ============================================================================
|
|
154
|
+
// Floating point types
|
|
155
|
+
// ============================================================================
|
|
156
|
+
|
|
157
|
+
class c_float extends SimpleCData {
|
|
158
|
+
static _size = 4;
|
|
159
|
+
static _type = "float";
|
|
160
|
+
static _reader = (buf, off) => buf.readFloatLE(off);
|
|
161
|
+
static _writer = (buf, off, val) => buf.writeFloatLE(val, off);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
class c_double extends SimpleCData {
|
|
165
|
+
static _size = 8;
|
|
166
|
+
static _type = "double";
|
|
167
|
+
static _reader = (buf, off) => buf.readDoubleLE(off);
|
|
168
|
+
static _writer = (buf, off, val) => buf.writeDoubleLE(val, off);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ============================================================================
|
|
172
|
+
// Boolean type
|
|
173
|
+
// ============================================================================
|
|
174
|
+
|
|
175
|
+
class c_bool extends SimpleCData {
|
|
176
|
+
static _size = 1;
|
|
177
|
+
static _type = "bool";
|
|
178
|
+
static _reader = (buf, off) => buf.readUInt8(off) !== 0;
|
|
179
|
+
static _writer = (buf, off, val) => buf.writeUInt8(val ? 1 : 0, off);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Character types
|
|
184
|
+
// ============================================================================
|
|
185
|
+
|
|
186
|
+
class c_char extends SimpleCData {
|
|
187
|
+
static _size = 1;
|
|
188
|
+
static _type = "char";
|
|
189
|
+
static _reader = (buf, off) => buf.readInt8(off);
|
|
190
|
+
static _writer = (buf, off, val) => {
|
|
191
|
+
if (typeof val === "string") val = val.charCodeAt(0);
|
|
192
|
+
buf.writeInt8(val, off);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
class c_wchar extends SimpleCData {
|
|
197
|
+
static _size = native.WCHAR_SIZE || 4;
|
|
198
|
+
static _type = "wchar";
|
|
199
|
+
static _reader = (buf, off) => {
|
|
200
|
+
return this._size === 2 ? buf.readUInt16LE(off) : buf.readUInt32LE(off);
|
|
201
|
+
};
|
|
202
|
+
static _writer = (buf, off, val) => {
|
|
203
|
+
if (typeof val === "string") val = val.charCodeAt(0);
|
|
204
|
+
if (this._size === 2) {
|
|
205
|
+
buf.writeUInt16LE(val, off);
|
|
206
|
+
} else {
|
|
207
|
+
buf.writeUInt32LE(val, off);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ============================================================================
|
|
213
|
+
// Pointer types
|
|
214
|
+
// ============================================================================
|
|
215
|
+
|
|
216
|
+
class c_void_p extends SimpleCData {
|
|
217
|
+
static _size = native.POINTER_SIZE;
|
|
218
|
+
static _type = "pointer";
|
|
219
|
+
static _reader = (buf, off) => {
|
|
220
|
+
return native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
221
|
+
};
|
|
222
|
+
static _writer = (buf, off, val) => {
|
|
223
|
+
const v = typeof val === "bigint" ? val : BigInt(val || 0);
|
|
224
|
+
if (native.POINTER_SIZE === 8) {
|
|
225
|
+
buf.writeBigUInt64LE(v, off);
|
|
226
|
+
} else {
|
|
227
|
+
buf.writeUInt32LE(Number(v), off);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ============================================================================
|
|
233
|
+
// Platform-specific types
|
|
234
|
+
// ============================================================================
|
|
235
|
+
|
|
236
|
+
class c_size_t extends SimpleCData {
|
|
237
|
+
static _size = native.POINTER_SIZE;
|
|
238
|
+
static _type = "size_t";
|
|
239
|
+
static _reader = (buf, off) => {
|
|
240
|
+
return native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : buf.readUInt32LE(off);
|
|
241
|
+
};
|
|
242
|
+
static _writer = (buf, off, val) => {
|
|
243
|
+
if (native.POINTER_SIZE === 8) {
|
|
244
|
+
buf.writeBigUInt64LE(BigInt(val), off);
|
|
245
|
+
} else {
|
|
246
|
+
buf.writeUInt32LE(Number(val), off);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
class c_long extends SimpleCData {
|
|
252
|
+
static _size = native.POINTER_SIZE;
|
|
253
|
+
static _type = "long";
|
|
254
|
+
static _reader = c_size_t._reader;
|
|
255
|
+
static _writer = c_size_t._writer;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
class c_ulong extends SimpleCData {
|
|
259
|
+
static _size = native.POINTER_SIZE;
|
|
260
|
+
static _type = "ulong";
|
|
261
|
+
static _reader = (buf, off) => {
|
|
262
|
+
return native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : buf.readUInt32LE(off);
|
|
263
|
+
};
|
|
264
|
+
static _writer = (buf, off, val) => {
|
|
265
|
+
if (native.POINTER_SIZE === 8) {
|
|
266
|
+
buf.writeBigUInt64LE(BigInt(val), off);
|
|
267
|
+
} else {
|
|
268
|
+
buf.writeUInt32LE(Number(val), off);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ============================================================================
|
|
274
|
+
// String pointer types (special handling)
|
|
275
|
+
// ============================================================================
|
|
276
|
+
|
|
277
|
+
class c_char_p extends SimpleCData {
|
|
278
|
+
static _size = native.POINTER_SIZE;
|
|
279
|
+
static _type = "char_p";
|
|
280
|
+
static _reader = (buf, off) => {
|
|
281
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
282
|
+
if (!ptr) return null;
|
|
283
|
+
return readCString(ptr);
|
|
284
|
+
};
|
|
285
|
+
static _writer = (buf, off, val) => {
|
|
286
|
+
if (typeof val === "string") {
|
|
287
|
+
val = cstring(val);
|
|
288
|
+
}
|
|
289
|
+
if (Buffer.isBuffer(val)) {
|
|
290
|
+
const addr = addressOf(val);
|
|
291
|
+
const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
|
|
292
|
+
if (native.POINTER_SIZE === 8) {
|
|
293
|
+
buf.writeBigUInt64LE(v, off);
|
|
294
|
+
} else {
|
|
295
|
+
buf.writeUInt32LE(Number(v), off);
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
const v = typeof val === "bigint" ? val : BigInt(val || 0);
|
|
299
|
+
if (native.POINTER_SIZE === 8) {
|
|
300
|
+
buf.writeBigUInt64LE(v, off);
|
|
301
|
+
} else {
|
|
302
|
+
buf.writeUInt32LE(Number(v), off);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
class c_wchar_p extends SimpleCData {
|
|
309
|
+
static _size = native.POINTER_SIZE;
|
|
310
|
+
static _type = "wchar_p";
|
|
311
|
+
static _reader = (buf, off) => {
|
|
312
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
313
|
+
if (!ptr) return null;
|
|
314
|
+
return readWString(ptr);
|
|
315
|
+
};
|
|
316
|
+
static _writer = (buf, off, val) => {
|
|
317
|
+
if (typeof val === "string") {
|
|
318
|
+
val = wstring(val);
|
|
319
|
+
}
|
|
320
|
+
if (Buffer.isBuffer(val)) {
|
|
321
|
+
const addr = addressOf(val);
|
|
322
|
+
const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
|
|
323
|
+
if (native.POINTER_SIZE === 8) {
|
|
324
|
+
buf.writeBigUInt64LE(v, off);
|
|
325
|
+
} else {
|
|
326
|
+
buf.writeUInt32LE(Number(v), off);
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
const v = typeof val === "bigint" ? val : BigInt(val || 0);
|
|
330
|
+
if (native.POINTER_SIZE === 8) {
|
|
331
|
+
buf.writeBigUInt64LE(v, off);
|
|
332
|
+
} else {
|
|
333
|
+
buf.writeUInt32LE(Number(v), off);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// ============================================================================
|
|
340
|
+
// Python-compatible aliases
|
|
341
|
+
// ============================================================================
|
|
342
|
+
|
|
343
|
+
const c_byte = c_int8;
|
|
344
|
+
const c_ubyte = c_uint8;
|
|
345
|
+
const c_short = c_int16;
|
|
346
|
+
const c_ushort = c_uint16;
|
|
347
|
+
const c_int = c_int32;
|
|
348
|
+
const c_uint = c_uint32;
|
|
349
|
+
const c_longlong = c_int64;
|
|
350
|
+
const c_ulonglong = c_uint64;
|
|
351
|
+
|
|
352
|
+
// Return all types
|
|
353
|
+
return {
|
|
354
|
+
// Void
|
|
355
|
+
c_void,
|
|
356
|
+
// Signed integers
|
|
357
|
+
c_int8,
|
|
358
|
+
c_int16,
|
|
359
|
+
c_int32,
|
|
360
|
+
c_int64,
|
|
361
|
+
// Unsigned integers
|
|
362
|
+
c_uint8,
|
|
363
|
+
c_uint16,
|
|
364
|
+
c_uint32,
|
|
365
|
+
c_uint64,
|
|
366
|
+
// Floating point
|
|
367
|
+
c_float,
|
|
368
|
+
c_double,
|
|
369
|
+
// Boolean
|
|
370
|
+
c_bool,
|
|
371
|
+
// Characters
|
|
372
|
+
c_char,
|
|
373
|
+
c_wchar,
|
|
374
|
+
// Pointers
|
|
375
|
+
c_void_p,
|
|
376
|
+
c_char_p,
|
|
377
|
+
c_wchar_p,
|
|
378
|
+
// Platform-specific
|
|
379
|
+
c_size_t,
|
|
380
|
+
c_long,
|
|
381
|
+
c_ulong,
|
|
382
|
+
// Python-compatible aliases
|
|
383
|
+
c_byte,
|
|
384
|
+
c_ubyte,
|
|
385
|
+
c_short,
|
|
386
|
+
c_ushort,
|
|
387
|
+
c_int,
|
|
388
|
+
c_uint,
|
|
389
|
+
c_longlong,
|
|
390
|
+
c_ulonglong,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file cache.js
|
|
3
|
+
* @module utils/cache
|
|
4
|
+
* @description Simple LRU (Least Recently Used) cache implementation for function caching.
|
|
5
|
+
* Prevents unbounded memory growth in long-running applications.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { LRUCache } from './utils/cache.js';
|
|
9
|
+
*
|
|
10
|
+
* const cache = new LRUCache(1000); // Max 1000 entries
|
|
11
|
+
* cache.set('key1', 'value1');
|
|
12
|
+
* const value = cache.get('key1'); // 'value1'
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* LRU Cache implementation using Map for O(1) operations.
|
|
17
|
+
* When the cache reaches maxSize, the least recently used item is evicted.
|
|
18
|
+
*
|
|
19
|
+
* @class LRUCache
|
|
20
|
+
* @example
|
|
21
|
+
* const cache = new LRUCache(100);
|
|
22
|
+
* cache.set('user:1', { name: 'John' });
|
|
23
|
+
* cache.get('user:1'); // { name: 'John' }
|
|
24
|
+
* cache.has('user:1'); // true
|
|
25
|
+
* cache.size; // 1
|
|
26
|
+
*/
|
|
27
|
+
export class LRUCache {
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new LRU cache instance
|
|
30
|
+
* @param {number} [maxSize=1000] - Maximum number of entries before eviction
|
|
31
|
+
*/
|
|
32
|
+
constructor(maxSize = 1000) {
|
|
33
|
+
/**
|
|
34
|
+
* Maximum cache size before LRU eviction
|
|
35
|
+
* @type {number}
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
this.maxSize = maxSize;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Internal Map storage for cache entries
|
|
42
|
+
* Map maintains insertion order, which we use for LRU tracking
|
|
43
|
+
* @type {Map<string, any>}
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
46
|
+
this.cache = new Map();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Retrieves a value from the cache and marks it as recently used.
|
|
51
|
+
* Moves the entry to the end of the Map (most recently used position).
|
|
52
|
+
*
|
|
53
|
+
* @param {string} key - Cache key to retrieve
|
|
54
|
+
* @returns {any|undefined} The cached value, or undefined if not found
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* cache.set('key', 'value');
|
|
58
|
+
* cache.get('key'); // 'value'
|
|
59
|
+
* cache.get('missing'); // undefined
|
|
60
|
+
*/
|
|
61
|
+
get(key) {
|
|
62
|
+
if (!this.cache.has(key)) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Move to end (most recently used) by deleting and re-inserting
|
|
67
|
+
const value = this.cache.get(key);
|
|
68
|
+
this.cache.delete(key);
|
|
69
|
+
this.cache.set(key, value);
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Adds or updates a value in the cache.
|
|
75
|
+
* If the key exists, it's moved to the most recently used position.
|
|
76
|
+
* If the cache is full, the least recently used entry is evicted.
|
|
77
|
+
*
|
|
78
|
+
* @param {string} key - Cache key
|
|
79
|
+
* @param {any} value - Value to store
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* cache.set('user:1', { name: 'John' });
|
|
83
|
+
* cache.set('user:1', { name: 'Jane' }); // Updates existing entry
|
|
84
|
+
*/
|
|
85
|
+
set(key, value) {
|
|
86
|
+
// If key exists, remove it first (will re-add at end)
|
|
87
|
+
if (this.cache.has(key)) {
|
|
88
|
+
this.cache.delete(key);
|
|
89
|
+
}
|
|
90
|
+
// If at capacity, evict oldest entry (first in Map)
|
|
91
|
+
else if (this.cache.size >= this.maxSize) {
|
|
92
|
+
const firstKey = this.cache.keys().next().value;
|
|
93
|
+
this.cache.delete(firstKey);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Add to end (most recently used position)
|
|
97
|
+
this.cache.set(key, value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Checks if a key exists in the cache.
|
|
102
|
+
* Does NOT update the LRU position.
|
|
103
|
+
*
|
|
104
|
+
* @param {string} key - Cache key to check
|
|
105
|
+
* @returns {boolean} True if the key exists
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* cache.set('key', 'value');
|
|
109
|
+
* cache.has('key'); // true
|
|
110
|
+
* cache.has('missing'); // false
|
|
111
|
+
*/
|
|
112
|
+
has(key) {
|
|
113
|
+
return this.cache.has(key);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Removes all entries from the cache.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* cache.set('key1', 'value1');
|
|
121
|
+
* cache.set('key2', 'value2');
|
|
122
|
+
* cache.clear();
|
|
123
|
+
* cache.size; // 0
|
|
124
|
+
*/
|
|
125
|
+
clear() {
|
|
126
|
+
this.cache.clear();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Returns the current number of entries in the cache.
|
|
131
|
+
*
|
|
132
|
+
* @returns {number} Number of cached entries
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* cache.set('key1', 'value1');
|
|
136
|
+
* cache.set('key2', 'value2');
|
|
137
|
+
* cache.size; // 2
|
|
138
|
+
*/
|
|
139
|
+
get size() {
|
|
140
|
+
return this.cache.size;
|
|
141
|
+
}
|
|
142
|
+
}
|