Skip to content

Commit 34c1f33

Browse files
committed
Updating tests
1 parent d5bdfe0 commit 34c1f33

9 files changed

Lines changed: 266 additions & 109 deletions

File tree

dist/tiny-lru.cjs

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -201,20 +201,25 @@ class LRU {
201201
* @since 1.0.0
202202
*/
203203
get (key) {
204-
let result;
204+
const item = this.items[key];
205205

206-
if (this.has(key)) {
207-
const item = this.items[key];
206+
if (item !== undefined) {
207+
// Check TTL only if enabled to avoid unnecessary Date.now() calls
208+
if (this.ttl > 0) {
209+
if (item.expiry <= Date.now()) {
210+
this.delete(key);
208211

209-
if (this.ttl > 0 && item.expiry <= Date.now()) {
210-
this.delete(key);
211-
} else {
212-
result = item.value;
213-
this.set(key, result, true);
212+
return undefined;
213+
}
214214
}
215+
216+
// Fast LRU update without full set() overhead
217+
this.moveToEnd(item);
218+
219+
return item.value;
215220
}
216221

217-
return result;
222+
return undefined;
218223
}
219224

220225
/**
@@ -236,6 +241,52 @@ class LRU {
236241
return key in this.items;
237242
}
238243

244+
/**
245+
* Efficiently moves an item to the end of the LRU list (most recently used position).
246+
* This is much faster than calling set() for LRU position updates.
247+
*
248+
* @method moveToEnd
249+
* @memberof LRU
250+
* @param {Object} item - The item to move to the end.
251+
* @private
252+
* @since 11.3.5
253+
*/
254+
moveToEnd (item) {
255+
// If already at the end, nothing to do
256+
if (this.last === item) {
257+
return;
258+
}
259+
260+
// Remove item from current position in the list
261+
if (item.prev !== null) {
262+
item.prev.next = item.next;
263+
}
264+
265+
if (item.next !== null) {
266+
item.next.prev = item.prev;
267+
}
268+
269+
// Update first pointer if this was the first item
270+
if (this.first === item) {
271+
this.first = item.next;
272+
}
273+
274+
// Add item to the end
275+
item.prev = this.last;
276+
item.next = null;
277+
278+
if (this.last !== null) {
279+
this.last.next = item;
280+
}
281+
282+
this.last = item;
283+
284+
// Handle edge case: if this was the only item, it's also first
285+
if (this.first === null) {
286+
this.first = item;
287+
}
288+
}
289+
239290
/**
240291
* Returns an array of all keys in the cache, ordered from least to most recently used.
241292
*
@@ -329,38 +380,20 @@ class LRU {
329380
* @since 1.0.0
330381
*/
331382
set (key, value, bypass = false, resetTtl = this.resetTtl) {
332-
let item;
383+
let item = this.items[key];
333384

334-
if (bypass || this.has(key)) {
335-
item = this.items[key];
385+
if (bypass || item !== undefined) {
386+
// Existing item: update value and position
336387
item.value = value;
337388

338389
if (bypass === false && resetTtl) {
339390
item.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
340391
}
341392

342-
if (this.last !== item) {
343-
const last = this.last,
344-
next = item.next,
345-
prev = item.prev;
346-
347-
if (this.first === item) {
348-
this.first = item.next;
349-
}
350-
351-
item.next = null;
352-
item.prev = this.last;
353-
last.next = item;
354-
355-
if (prev !== null) {
356-
prev.next = next;
357-
}
358-
359-
if (next !== null) {
360-
next.prev = prev;
361-
}
362-
}
393+
// Always move to end, but the bypass parameter affects TTL reset behavior
394+
this.moveToEnd(item);
363395
} else {
396+
// New item: check for eviction and create
364397
if (this.max > 0 && this.size === this.max) {
365398
this.evict(true);
366399
}
@@ -378,9 +411,9 @@ class LRU {
378411
} else {
379412
this.last.next = item;
380413
}
381-
}
382414

383-
this.last = item;
415+
this.last = item;
416+
}
384417

385418
return this;
386419
}

dist/tiny-lru.js

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -199,20 +199,25 @@ class LRU {
199199
* @since 1.0.0
200200
*/
201201
get (key) {
202-
let result;
202+
const item = this.items[key];
203203

204-
if (this.has(key)) {
205-
const item = this.items[key];
204+
if (item !== undefined) {
205+
// Check TTL only if enabled to avoid unnecessary Date.now() calls
206+
if (this.ttl > 0) {
207+
if (item.expiry <= Date.now()) {
208+
this.delete(key);
206209

207-
if (this.ttl > 0 && item.expiry <= Date.now()) {
208-
this.delete(key);
209-
} else {
210-
result = item.value;
211-
this.set(key, result, true);
210+
return undefined;
211+
}
212212
}
213+
214+
// Fast LRU update without full set() overhead
215+
this.moveToEnd(item);
216+
217+
return item.value;
213218
}
214219

215-
return result;
220+
return undefined;
216221
}
217222

218223
/**
@@ -234,6 +239,52 @@ class LRU {
234239
return key in this.items;
235240
}
236241

242+
/**
243+
* Efficiently moves an item to the end of the LRU list (most recently used position).
244+
* This is much faster than calling set() for LRU position updates.
245+
*
246+
* @method moveToEnd
247+
* @memberof LRU
248+
* @param {Object} item - The item to move to the end.
249+
* @private
250+
* @since 11.3.5
251+
*/
252+
moveToEnd (item) {
253+
// If already at the end, nothing to do
254+
if (this.last === item) {
255+
return;
256+
}
257+
258+
// Remove item from current position in the list
259+
if (item.prev !== null) {
260+
item.prev.next = item.next;
261+
}
262+
263+
if (item.next !== null) {
264+
item.next.prev = item.prev;
265+
}
266+
267+
// Update first pointer if this was the first item
268+
if (this.first === item) {
269+
this.first = item.next;
270+
}
271+
272+
// Add item to the end
273+
item.prev = this.last;
274+
item.next = null;
275+
276+
if (this.last !== null) {
277+
this.last.next = item;
278+
}
279+
280+
this.last = item;
281+
282+
// Handle edge case: if this was the only item, it's also first
283+
if (this.first === null) {
284+
this.first = item;
285+
}
286+
}
287+
237288
/**
238289
* Returns an array of all keys in the cache, ordered from least to most recently used.
239290
*
@@ -327,38 +378,20 @@ class LRU {
327378
* @since 1.0.0
328379
*/
329380
set (key, value, bypass = false, resetTtl = this.resetTtl) {
330-
let item;
381+
let item = this.items[key];
331382

332-
if (bypass || this.has(key)) {
333-
item = this.items[key];
383+
if (bypass || item !== undefined) {
384+
// Existing item: update value and position
334385
item.value = value;
335386

336387
if (bypass === false && resetTtl) {
337388
item.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
338389
}
339390

340-
if (this.last !== item) {
341-
const last = this.last,
342-
next = item.next,
343-
prev = item.prev;
344-
345-
if (this.first === item) {
346-
this.first = item.next;
347-
}
348-
349-
item.next = null;
350-
item.prev = this.last;
351-
last.next = item;
352-
353-
if (prev !== null) {
354-
prev.next = next;
355-
}
356-
357-
if (next !== null) {
358-
next.prev = prev;
359-
}
360-
}
391+
// Always move to end, but the bypass parameter affects TTL reset behavior
392+
this.moveToEnd(item);
361393
} else {
394+
// New item: check for eviction and create
362395
if (this.max > 0 && this.size === this.max) {
363396
this.evict(true);
364397
}
@@ -376,9 +409,9 @@ class LRU {
376409
} else {
377410
this.last.next = item;
378411
}
379-
}
380412

381-
this.last = item;
413+
this.last = item;
414+
}
382415

383416
return this;
384417
}

dist/tiny-lru.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)