├── .gitignore ├── .npmignore ├── Gruntfile.js ├── Makefile ├── README.md ├── eslint.yaml ├── package.json ├── src └── cache-lru.js └── tst ├── cache-lru.js └── common.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Cache-LRU -- In-Memory Cache with O(1) Operations and LRU Purging Strategy 3 | ** Copyright (c) 2015-2024 Dr. Ralf S. Engelschall 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be included 14 | ** in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /* global module: true */ 26 | module.exports = function (grunt) { 27 | grunt.loadNpmTasks("grunt-contrib-clean") 28 | grunt.loadNpmTasks("grunt-browserify") 29 | grunt.loadNpmTasks("grunt-mocha-test") 30 | grunt.loadNpmTasks("grunt-eslint") 31 | 32 | grunt.initConfig({ 33 | /* eslint quote-props: off */ 34 | eslint: { 35 | options: { 36 | overrideConfigFile: "eslint.yaml" 37 | }, 38 | "gruntfile": [ "Gruntfile.js" ], 39 | "cache-lru": [ "src/**/*.js" ] 40 | }, 41 | browserify: { 42 | "cache-lru": { 43 | files: { 44 | "lib/cache-lru.js": [ "src/**/*.js" ] 45 | }, 46 | options: { 47 | transform: [ 48 | [ "babelify", { 49 | presets: [ 50 | [ "@babel/preset-env", { 51 | "targets": { 52 | "browsers": "last 2 versions, > 1%, ie 11" 53 | } 54 | } ] 55 | ] 56 | } ], 57 | [ "uglifyify", { sourceMap: false, global: true } ] 58 | ], 59 | plugin: [ 60 | [ "browserify-derequire" ], 61 | [ "browserify-header" ] 62 | ], 63 | browserifyOptions: { 64 | standalone: "CacheLRU", 65 | debug: false 66 | } 67 | } 68 | } 69 | }, 70 | mochaTest: { 71 | "cache-lru": { 72 | src: [ "tst/*.js", "!tst/common.js" ] 73 | }, 74 | options: { 75 | reporter: "spec", 76 | require: "tst/common.js" 77 | } 78 | }, 79 | clean: { 80 | clean: [], 81 | distclean: [ "node_modules" ] 82 | } 83 | }) 84 | 85 | grunt.registerTask("default", [ "eslint", "browserify", "mochaTest" ]) 86 | } 87 | 88 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## Cache-LRU -- In-Memory Cache with O(1) Operations and LRU Purging Strategy 3 | ## Copyright (c) 2015-2024 Dr. Ralf S. Engelschall 4 | ## 5 | ## Permission is hereby granted, free of charge, to any person obtaining 6 | ## a copy of this software and associated documentation files (the 7 | ## "Software"), to deal in the Software without restriction, including 8 | ## without limitation the rights to use, copy, modify, merge, publish, 9 | ## distribute, sublicense, and/or sell copies of the Software, and to 10 | ## permit persons to whom the Software is furnished to do so, subject to 11 | ## the following conditions: 12 | ## 13 | ## The above copyright notice and this permission notice shall be included 14 | ## in all copies or substantial portions of the Software. 15 | ## 16 | ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | ## IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | ## CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | ## TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | ## SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ## 24 | 25 | NPM = npm 26 | GRUNT = ./node_modules/grunt-cli/bin/grunt 27 | 28 | all: build 29 | 30 | bootstrap: 31 | @if [ ! -x $(GRUNT) ]; then $(NPM) install; fi 32 | 33 | build: bootstrap 34 | @$(GRUNT) 35 | 36 | clean: bootstrap 37 | @$(GRUNT) clean:clean 38 | 39 | distclean: bootstrap 40 | @$(GRUNT) clean:clean clean:distclean 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Cache-LRU 3 | ========= 4 | 5 | In-Memory Cache with O(1) Operations and LRU Purging Strategy 6 | 7 |

8 | 9 | 10 |

11 | 12 | 13 | About 14 | ----- 15 | 16 | Cache-LRU is a very small JavaScript library, providing an in-memory 17 | key-indexed object cache data structure with Least-Recently-Used (LRU) 18 | object purging strategy and main operations which all have strict O(1), i.e., 19 | constant and hence independent of the number of cached objects, time 20 | complexity (including the internal LRU purging functionality). 21 | 22 | Installation 23 | ------------ 24 | 25 | ```shell 26 | $ npm install cache-lru 27 | ``` 28 | 29 | Usage 30 | ----- 31 | 32 | ### Main Operations 33 | 34 | - `new CacheLRU(): CacheLRU`: [O(1)]
35 | Create a new cache instance -- with initially no cached objects 36 | and an infinite caching limit. 37 | 38 | - `CacheLRU#limit(max?: Number): Number`: [O(1)]
39 | Set a new or get current maximum number of objects in the cache. On 40 | setting a new maximum, if previously already more than `max` 41 | objects are in the cache, the `length() - max` LRU ojects are 42 | automatically deleted. 43 | 44 | - `CacheLRU#length(): Number`: [O(1)]
45 | Get number of objects in the cache. 46 | 47 | - `CacheLRU#dispose(callback: (key, val, op) => Void): CacheLRU`: [O(1)]
48 | Set a callback which is called once for every object just before it is 49 | disposed off the cache, either because it is replaced by a `set()` 50 | call or deleted by a `del()` call. The parameters to the callback are 51 | the key under which the object was stored, the value of the object which 52 | was stored and the operation (either `set` or `del`) which caused the 53 | object disposal. This is usually used for explicit resource deallocation reasons. 54 | 55 | - `CacheLRU#has(key: String): Boolean`: [O(1)]
56 | Check whether object exists under `key` -- without promoting the 57 | corresponding object to be the new MRU object. 58 | 59 | - `CacheLRU#peek(key: String): Object`: [O(1)]
60 | Get value of object under `key` -- without promoting the 61 | corresponding object to be the new MRU object. If no 62 | object exists under `key` the value `undefined` is returned. 63 | 64 | - `CacheLRU#touch(key: String): CacheLRU`: [O(1)]
65 | Touch object under `key` and this way explicitly promote the 66 | object to be the new MRU object. 67 | If no object exists under `key` an exception is thrown. 68 | 69 | - `CacheLRU#get(key: String): Object`: [O(1)]
70 | Get value of object under `key` -- and promote the 71 | object to be the new MRU object. 72 | If no object exists under `key` the value `undefined` is returned. 73 | 74 | - `CacheLRU#set(key: String, val: Object, expires?: Number): CacheLRU`: [O(1)]
75 | Set value of object under `key`. If there is already an object stored 76 | under `key`, replace it. Else insert as a new object into the cache. 77 | In both cases, promote the affected object to be the new MRU object. 78 | If the optional `expires` parameter is given, it should be the 79 | duration in milliseconds the object should maximally last in the cache (it still 80 | can be disposed earlier because of LRU purging of the cache). By 81 | default this is `Infinity`. 82 | 83 | - `CacheLRU#del(key: String): CacheLRU`: [O(1)]
84 | Delete object under `key`. 85 | If no object exists under `key` an exception is thrown. 86 | 87 | ### Convenience Operations 88 | 89 | - `CacheLRU#clear(): CacheLRU`: [O(n)]
90 | Delete all objects in the cache. 91 | 92 | - `CacheLRU#keys(): String[]`: [O(n)]
93 | Get the list of keys of all objects in the cache, in MRU to LRU order. 94 | 95 | - `CacheLRU#values(): Object[]`: [O(n)]
96 | Get the list of values of all objects in the cache, in MRU to LRU order. 97 | 98 | - `CacheLRU#each(callback: (val: Object, key: String, order: Number) =>, ctx: Object): Object`: [O(n)]
99 | Iterate over all objects in the cache, in MRU to LRU order, and call 100 | the `callback` function for each object. The function receives the 101 | object value, the object key and the iteration order (starting from 102 | zero and steadily increasing). 103 | 104 | Implementation Notice 105 | --------------------- 106 | 107 | Although Cache-LRU is written in ECMAScript 6, it is transpiled to ECMAScript 108 | 5 and this way runs in really all(!) current (as of 2016) JavaScript 109 | environments, of course. 110 | 111 | Internally, Cache-LRU is based on a managing all objects in a two-headed 112 | double-linked list of buckets. This way it can achieve the O(1) time 113 | complexity in all its main operations, including the automatically 114 | happening LRU purging functionality. 115 | 116 | License 117 | ------- 118 | 119 | Copyright (c) 2015-2024 Dr. Ralf S. Engelschall (http://engelschall.com/) 120 | 121 | Permission is hereby granted, free of charge, to any person obtaining 122 | a copy of this software and associated documentation files (the 123 | "Software"), to deal in the Software without restriction, including 124 | without limitation the rights to use, copy, modify, merge, publish, 125 | distribute, sublicense, and/or sell copies of the Software, and to 126 | permit persons to whom the Software is furnished to do so, subject to 127 | the following conditions: 128 | 129 | The above copyright notice and this permission notice shall be included 130 | in all copies or substantial portions of the Software. 131 | 132 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 133 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 134 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 135 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 136 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 137 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 138 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 139 | 140 | -------------------------------------------------------------------------------- /eslint.yaml: -------------------------------------------------------------------------------- 1 | ## 2 | ## Cache-LRU -- In-Memory Cache with O(1) Operations and LRU Purging Strategy 3 | ## Copyright (c) 2015-2024 Dr. Ralf S. Engelschall 4 | ## 5 | ## Permission is hereby granted, free of charge, to any person obtaining 6 | ## a copy of this software and associated documentation files (the 7 | ## "Software"), to deal in the Software without restriction, including 8 | ## without limitation the rights to use, copy, modify, merge, publish, 9 | ## distribute, sublicense, and/or sell copies of the Software, and to 10 | ## permit persons to whom the Software is furnished to do so, subject to 11 | ## the following conditions: 12 | ## 13 | ## The above copyright notice and this permission notice shall be included 14 | ## in all copies or substantial portions of the Software. 15 | ## 16 | ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | ## IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | ## CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | ## TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | ## SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | ## 24 | 25 | --- 26 | 27 | extends: 28 | - eslint:recommended 29 | - eslint-config-standard 30 | 31 | parserOptions: 32 | ecmaVersion: 8 33 | sourceType: module 34 | ecmaFeatures: 35 | jsx: false 36 | 37 | env: 38 | browser: true 39 | node: true 40 | mocha: true 41 | commonjs: true 42 | worker: true 43 | serviceworker: true 44 | 45 | globals: 46 | process: true 47 | 48 | rules: 49 | # modified rules 50 | indent: [ "error", 4, { "SwitchCase": 1 } ] 51 | linebreak-style: [ "error", "unix" ] 52 | semi: [ "error", "never" ] 53 | operator-linebreak: [ "error", "after", { "overrides": { "&&": "before", "||": "before", ":": "before" } } ] 54 | brace-style: [ "error", "stroustrup", { "allowSingleLine": true } ] 55 | quotes: [ "error", "double" ] 56 | 57 | # disabled rules 58 | no-multi-spaces: off 59 | no-multiple-empty-lines: off 60 | key-spacing: off 61 | object-property-newline: off 62 | curly: off 63 | space-in-parens: off 64 | array-bracket-spacing: off 65 | 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cache-lru", 3 | "version": "1.2.0", 4 | "description": "In-Memory Cache with O(1) Operations and LRU Purging Strategy", 5 | "keywords": [ "cache", "lru" ], 6 | "main": "lib/cache-lru.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/rse/cache-lru.git" 10 | }, 11 | "author": { 12 | "name": "Dr. Ralf S. Engelschall", 13 | "email": "rse@engelschall.com", 14 | "url": "http://engelschall.com" 15 | }, 16 | "license": "MIT", 17 | "homepage": "https://github.com/rse/cache-lru", 18 | "bugs": "https://github.com/rse/cache-lru/issues", 19 | "devDependencies": { 20 | "grunt": "1.6.1", 21 | "grunt-cli": "1.4.3", 22 | "grunt-contrib-clean": "2.0.1", 23 | "grunt-browserify": "6.0.0", 24 | "grunt-mocha-test": "0.13.3", 25 | "grunt-eslint": "24.3.0", 26 | "eslint": "8.57.0", 27 | "eslint-config-standard": "17.1.0", 28 | "eslint-plugin-promise": "6.1.1", 29 | "eslint-plugin-import": "2.29.1", 30 | "eslint-plugin-node": "11.1.0", 31 | "mocha": "10.3.0", 32 | "chai": "4.4.1", 33 | "babelify": "10.0.0", 34 | "@babel/core": "7.24.0", 35 | "@babel/preset-env": "7.24.0", 36 | "uglifyify": "5.0.2", 37 | "browserify-header": "1.1.0", 38 | "browserify-derequire": "1.1.1" 39 | }, 40 | "scripts": { 41 | "prepublishOnly": "grunt default", 42 | "build": "grunt default" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/cache-lru.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Cache-LRU -- In-Memory Cache with O(1) Operations and LRU Purging Strategy 3 | ** Copyright (c) 2015-2024 Dr. Ralf S. Engelschall 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be included 14 | ** in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | class CacheLRU { 26 | /* create LRU cache instance */ 27 | constructor () { 28 | this._index = {} 29 | this._LRU = { newer: null } 30 | this._MRU = { older: null } 31 | this._LRU.newer = this._MRU 32 | this._MRU.older = this._LRU 33 | this._cur = 0 34 | this._max = Infinity 35 | this._dispose = (/* key, val, op */) => {} 36 | return this 37 | } 38 | 39 | /* get or set the cache limit */ 40 | limit (max) { 41 | const maxOld = this._max 42 | if (arguments.length > 0) { 43 | this._max = max 44 | this._purge() 45 | } 46 | return maxOld 47 | } 48 | 49 | /* configure function to be called before item is disposed */ 50 | dispose (cb) { 51 | this._dispose = cb 52 | return this 53 | } 54 | 55 | /* get number of items */ 56 | length () { 57 | return this._cur 58 | } 59 | 60 | /* get keys of all items in order */ 61 | keys () { 62 | return this.each(function (val, key) { this.push(key) }, []) 63 | } 64 | 65 | /* get values of all items in order */ 66 | values () { 67 | return this.each(function (val /*, key */) { this.push(val) }, []) 68 | } 69 | 70 | /* iterate over all items in order */ 71 | each (cb, ctx) { 72 | if (arguments < 2) 73 | ctx = this 74 | let i = 0 75 | let bucket = this._MRU.older 76 | while (bucket !== this._LRU) { 77 | cb.call(ctx, bucket.val, bucket.key, i++) 78 | bucket = bucket.older 79 | } 80 | return ctx 81 | } 82 | 83 | /* check whether item exists under key */ 84 | has (key) { 85 | const bucket = this._index[key] 86 | return (bucket !== undefined && bucket.expires >= Date.now()) 87 | } 88 | 89 | /* get value under key without promoting item */ 90 | peek (key) { 91 | const bucket = this._index[key] 92 | if (bucket === undefined) 93 | return undefined 94 | if (bucket.expires < Date.now()) { 95 | this.del(bucket.key) 96 | return undefined 97 | } 98 | return bucket.val 99 | } 100 | 101 | /* explicity promote item under key */ 102 | touch (key) { 103 | const bucket = this._index[key] 104 | if (bucket === undefined) 105 | throw new Error("touch: no such item") 106 | this._promote(bucket) 107 | return this 108 | } 109 | 110 | /* get value under key */ 111 | get (key) { 112 | const bucket = this._index[key] 113 | if (bucket === undefined) 114 | return undefined 115 | if (bucket.expires < Date.now()) { 116 | this.del(bucket.key) 117 | return undefined 118 | } 119 | this._promote(bucket) 120 | return bucket.val 121 | } 122 | 123 | /* set value under key */ 124 | set (key, val, expires) { 125 | if (arguments.length < 3) 126 | expires = Infinity 127 | expires += Date.now() 128 | let bucket = this._index[key] 129 | if (bucket === undefined) { 130 | /* insert new bucket */ 131 | bucket = { 132 | older: null, 133 | newer: null, 134 | key, 135 | val, 136 | expires 137 | } 138 | this._index[key] = bucket 139 | this._attach(bucket) 140 | this._cur++ 141 | this._purge() 142 | } 143 | else { 144 | /* replace existing bucket */ 145 | const valOld = bucket.val 146 | bucket.val = val 147 | this._promote(bucket) 148 | this._dispose.call(undefined, bucket.key, valOld, "set") 149 | } 150 | return this 151 | } 152 | 153 | /* delete item under key */ 154 | del (key) { 155 | const bucket = this._index[key] 156 | if (bucket === undefined) 157 | throw new Error("del: no such item") 158 | delete this._index[key] 159 | this._detach(bucket) 160 | this._cur-- 161 | this._dispose.call(undefined, key, bucket.val, "del") 162 | return this 163 | } 164 | 165 | /* delete all items */ 166 | clear () { 167 | while (this._cur > 0) 168 | this.del(this._LRU.newer.key) 169 | return this 170 | } 171 | 172 | /* INTERNAL: purge all LRU items above limit */ 173 | _purge () { 174 | while (this._cur > this._max) 175 | this.del(this._LRU.newer.key) 176 | } 177 | 178 | /* INTERNAL: promote item */ 179 | _promote (bucket) { 180 | /* promote bucket to be MRU bucket */ 181 | this._detach(bucket) 182 | this._attach(bucket) 183 | } 184 | 185 | /* INTERNAL: detach bucket from list */ 186 | _detach (bucket) { 187 | bucket.older.newer = bucket.newer 188 | bucket.newer.older = bucket.older 189 | bucket.older = null 190 | bucket.newer = null 191 | } 192 | 193 | /* INTERNAL: attach bucket to list as MRU bucket */ 194 | _attach (bucket) { 195 | bucket.older = this._MRU.older 196 | bucket.newer = this._MRU 197 | bucket.newer.older = bucket 198 | bucket.older.newer = bucket 199 | } 200 | } 201 | 202 | module.exports = CacheLRU 203 | 204 | -------------------------------------------------------------------------------- /tst/cache-lru.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Cache-LRU -- In-Memory Cache with O(1) Operations and LRU Purging Strategy 3 | ** Copyright (c) 2015-2024 Dr. Ralf S. Engelschall 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be included 14 | ** in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | var CacheLRU = require("../lib/cache-lru.js") 26 | 27 | describe("Cache-LRU Library", function () { 28 | it("should expose the official API", function () { 29 | var cache = new CacheLRU(); 30 | expect(cache).to.be.a("object") 31 | expect(cache).to.respondTo("limit") 32 | expect(cache).to.respondTo("dispose") 33 | expect(cache).to.respondTo("length") 34 | expect(cache).to.respondTo("keys") 35 | expect(cache).to.respondTo("values") 36 | expect(cache).to.respondTo("each") 37 | expect(cache).to.respondTo("has") 38 | expect(cache).to.respondTo("peek") 39 | expect(cache).to.respondTo("touch") 40 | expect(cache).to.respondTo("get") 41 | expect(cache).to.respondTo("set") 42 | expect(cache).to.respondTo("del") 43 | expect(cache).to.respondTo("clear") 44 | }) 45 | it("should provide the expected set/get functionality", function () { 46 | var cache = new CacheLRU(); 47 | cache.set("foo", true); 48 | cache.set("bar", "baz"); 49 | cache.set("quux", 42); 50 | expect(cache.get("foo")).to.be.a("boolean").and.to.be.true 51 | expect(cache.get("bar")).to.be.a("string").and.to.be.equal("baz") 52 | expect(cache.get("quux")).to.be.a("number").and.to.be.equal(42) 53 | }) 54 | it("should provide the expected LRU semantics", function () { 55 | var cache = new CacheLRU(); 56 | cache.limit(0); 57 | cache.set("foo", true); 58 | expect(cache.get("foo")).to.be.equal(undefined) 59 | cache.limit(1); 60 | cache.set("foo", true); 61 | expect(cache.get("foo")).to.be.a("boolean").and.to.be.true 62 | cache.limit(2); 63 | cache.set("foo", true); 64 | cache.set("bar", "baz"); 65 | expect(cache.get("foo")).to.be.a("boolean").and.to.be.true 66 | expect(cache.get("bar")).to.be.a("string").and.to.be.equal("baz") 67 | cache.set("quux", 42); 68 | expect(cache.get("foo")).to.be.equal(undefined) 69 | }) 70 | }) 71 | 72 | -------------------------------------------------------------------------------- /tst/common.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** Cache-LRU -- In-Memory Cache with O(1) Operations and LRU Purging Strategy 3 | ** Copyright (c) 2015-2024 Dr. Ralf S. Engelschall 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining 6 | ** a copy of this software and associated documentation files (the 7 | ** "Software"), to deal in the Software without restriction, including 8 | ** without limitation the rights to use, copy, modify, merge, publish, 9 | ** distribute, sublicense, and/or sell copies of the Software, and to 10 | ** permit persons to whom the Software is furnished to do so, subject to 11 | ** the following conditions: 12 | ** 13 | ** The above copyright notice and this permission notice shall be included 14 | ** in all copies or substantial portions of the Software. 15 | ** 16 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /* switch to strict mode */ 26 | "use strict"; 27 | 28 | /* provide exception swallowing */ 29 | global.swallow = function (thrower) { try { thrower(); } catch (e) {} }; 30 | 31 | /* provide assertion functionality (base features) */ 32 | global.chai = require("chai"); 33 | global.should = require("chai").should(); 34 | global.expect = require("chai").expect; 35 | global.assert = require("chai").assert; 36 | 37 | /* print stack traces on assertion failures */ 38 | chai.config.includeStack = true; 39 | 40 | --------------------------------------------------------------------------------