diff --git a/classes/range.js b/classes/range.js index 7e7c4141..5ec7daf0 100644 --- a/classes/range.js +++ b/classes/range.js @@ -198,8 +198,8 @@ class Range { module.exports = Range -const LRU = require('lru-cache') -const cache = new LRU({ max: 1000 }) +const LRU = require('../internal/lrucache') +const cache = new LRU() const parseOptions = require('../internal/parse-options') const Comparator = require('./comparator') diff --git a/internal/lrucache.js b/internal/lrucache.js new file mode 100644 index 00000000..f4a97f2e --- /dev/null +++ b/internal/lrucache.js @@ -0,0 +1,45 @@ +class LRUCache { + constructor () { + this.max = 1000 + this.map = new Map() + } + + get (key) { + const value = this.map.get(key) + if (value === undefined) { + return undefined + } else { + // Remove the key from the map and add it to the end + this.map.delete(key) + this.map.set(key, value) + return value + } + } + + delete (key) { + if (this.map.has(key)) { + this.map.delete(key) + return true + } else { + return false + } + } + + set (key, value) { + const deleted = this.delete(key) + + if (!deleted && value !== undefined) { + // If cache is full, delete the least recently used item + if (this.map.size >= this.max) { + const firstKey = this.map.keys().next().value + this.delete(firstKey) + } + + this.map.set(key, value) + } + + return this + } +} + +module.exports = LRUCache diff --git a/package.json b/package.json index 0209284a..147c328f 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,9 @@ "engines": { "node": ">=10" }, + "dependencies": { + "lru-cache": "^6.0.0" + }, "author": "GitHub Inc.", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", diff --git a/test/classes/range.js b/test/classes/range.js index 24686adf..9547e23a 100644 --- a/test/classes/range.js +++ b/test/classes/range.js @@ -105,3 +105,13 @@ test('missing range parameter in range intersect', (t) => { 'throws type error') t.end() }) + +test('cache', (t) => { + const cached = Symbol('cached') + const r1 = new Range('1.0.0') + r1.set[0][cached] = true + const r2 = new Range('1.0.0') + t.equal(r1.set[0][cached], true) + t.equal(r2.set[0][cached], true) // Will be true, showing it's cached. + t.end() +}) diff --git a/test/internal/lrucache.js b/test/internal/lrucache.js new file mode 100644 index 00000000..83a0e797 --- /dev/null +++ b/test/internal/lrucache.js @@ -0,0 +1,19 @@ +const { test } = require('tap') +const LRUCache = require('../../internal/lrucache') + +test('basic cache operation', t => { + const c = new LRUCache() + const max = 1000 + + for (let i = 0; i < max; i++) { + t.equal(c.set(i, i), c) + } + for (let i = 0; i < max; i++) { + t.equal(c.get(i), i) + } + c.set(1001, 1001) + // lru item should be gone + t.equal(c.get(0), undefined) + c.set(42, undefined) + t.end() +})