diff options
Diffstat (limited to 'ext/mixed/js')
| -rw-r--r-- | ext/mixed/js/audio-system.js | 2 | ||||
| -rw-r--r-- | ext/mixed/js/cache-map.js | 172 | 
2 files changed, 49 insertions, 125 deletions
| diff --git a/ext/mixed/js/audio-system.js b/ext/mixed/js/audio-system.js index f42fd657..584da2b1 100644 --- a/ext/mixed/js/audio-system.js +++ b/ext/mixed/js/audio-system.js @@ -37,7 +37,7 @@ class AudioSystem {      }      async createExpressionAudio(sources, expression, reading, details) { -        const key = [expression, reading]; +        const key = JSON.stringify([expression, reading]);          const cacheValue = this._cache.get(key);          if (typeof cacheValue !== 'undefined') { diff --git a/ext/mixed/js/cache-map.js b/ext/mixed/js/cache-map.js index 57430848..c7d72e6b 100644 --- a/ext/mixed/js/cache-map.js +++ b/ext/mixed/js/cache-map.js @@ -16,29 +16,24 @@   */  /** - * Class which caches a map of values using an arbitrary length path, - * keeping the most recently accessed values. + * Class which caches a map of values, keeping the most recently accessed values.   */  class CacheMap {      /**       * Creates a new CacheMap. -     * @param maxCount The maximum number of entries able to be stored in the cache. -     * @param create A function to create a value for the corresponding path. -     *   The signature is: create(path) +     * @param maxSize The maximum number of entries able to be stored in the cache.       */ -    constructor(maxCount, create) { +    constructor(maxSize) {          if (!( -            typeof maxCount === 'number' && -            Number.isFinite(maxCount) && -            maxCount >= 0 && -            Math.floor(maxCount) === maxCount +            typeof maxSize === 'number' && +            Number.isFinite(maxSize) && +            maxSize >= 0 && +            Math.floor(maxSize) === maxSize          )) {              throw new Error('Invalid maxCount');          } -        this._maxCount = maxCount; -        this._create = create; -        this._count = 0; +        this._maxSize = maxSize;          this._map = new Map();          this._listFirst = this._createNode(null, null);          this._listLast = this._createNode(null, null); @@ -48,54 +43,62 @@ class CacheMap {      /**       * Returns the number of items in the cache.       */ -    get count() { -        return this._count; +    get size() { +        return this._map.size;      }      /**       * Returns the maximum number of items that can be added to the cache.       */ -    get maxCount() { -        return this._maxCount; +    get maxSize() { +        return this._maxSize;      }      /** -     * Returns whether or not an item exists at the given path. -     * @param path Array corresponding to the key of the cache. -     * @returns A boolean indicating whether ot not the item exists. +     * Returns whether or not an element exists at the given key. +     * @param key The key of the element. +     * @returns `true` if an element with the specified key exists, `false` otherwise.       */ -    has(path) { -        const node = this._accessNode(false, false, null, false, path); -        return (node !== null); +    has(key) { +        return this._map.has(key);      }      /** -     * Gets an item at the given path, if it exists. Otherwise, returns undefined. -     * @param path Array corresponding to the key of the cache. -     * @returns The existing value at the path, if any; otherwise, undefined. +     * Gets an element at the given key, if it exists. Otherwise, returns undefined. +     * @param key The key of the element. +     * @returns The existing value at the key, if any; `undefined` otherwise.       */ -    get(path) { -        const node = this._accessNode(false, false, null, true, path); -        return (node !== null ? node.value : void 0); +    get(key) { +        const node = this._map.get(key); +        if (typeof node === 'undefined') { return void 0; } +        this._updateRecency(node); +        return node.value;      }      /** -     * Gets an item at the given path, if it exists. Otherwise, creates a new item -     * and adds it to the cache. If the count exceeds the maximum count, items will be removed. -     * @param path Array corresponding to the key of the cache. -     * @returns The existing value at the path, if any; otherwise, a newly created value. -     */ -    getOrCreate(path) { -        return this._accessNode(true, false, null, true, path).value; -    } - -    /** -     * Sets a value at a given path. -     * @param path Array corresponding to the key of the cache. +     * Sets a value at a given key. +     * @param key The key of the element.       * @param value The value to store in the cache.       */ -    set(path, value) { -        this._accessNode(false, true, value, true, path); +    set(key, value) { +        let node = this._map.get(key); +        if (typeof node !== 'undefined') { +            this._updateRecency(node); +            node.value = value; +        } else { +            if (this._maxSize <= 0) { return; } + +            node = this._createNode(key, value); +            this._addNode(node, this._listFirst); +            this._map.set(key, node); + +            // Remove +            for (let removeCount = this._map.size - this._maxSize; removeCount > 0; --removeCount) { +                node = this._listLast.previous; +                this._removeNode(node); +                this._map.delete(node.key); +            } +        }      }      /** @@ -103,73 +106,18 @@ class CacheMap {       */      clear() {          this._map.clear(); -        this._count = 0;          this._resetEndNodes();      }      // Private -    _accessNode(create, set, value, updateRecency, path) { -        let ii = path.length; -        if (ii === 0) { throw new Error('Invalid path'); } - -        let map = this._map; -        let i = 0; -        for (; i < ii; ++i) { -            const map2 = map.get(path[i]); -            if (typeof map2 === 'undefined') { break; } -            map = map2; -        } - -        if (i === ii) { -            // Found (map should now be a node) -            if (updateRecency) { this._updateRecency(map); } -            if (set) { map.value = value; } -            return map; -        } - -        // Create new -        if (create) { -            value = this._create(path); -        } else if (!set) { -            return null; -        } - -        // Create mapping -        --ii; -        for (; i < ii; ++i) { -            const map2 = new Map(); -            map.set(path[i], map2); -            map = map2; -        } - -        // Assign -        const node = this._createNode(value, path); -        this._addNode(node, this._listFirst); -        map.set(path[ii], node); -        ++this._count; - -        this._updateCount(); - -        return node; -    } -      _updateRecency(node) {          this._removeNode(node);          this._addNode(node, this._listFirst);      } -    _updateCount() { -        for (let removeCount = this._count - this._maxCount; removeCount > 0; --removeCount) { -            const node = this._listLast.previous; -            this._removeNode(node); -            this._removeMapping(node.path); -            --this._count; -        } -    } - -    _createNode(value, path) { -        return {value, path, previous: null, next: null}; +    _createNode(key, value) { +        return {key, value, previous: null, next: null};      }      _addNode(node, previous) { @@ -185,30 +133,6 @@ class CacheMap {          node.previous.next = node.next;      } -    _removeMapping(path) { -        const ii = path.length - 1; -        let i = 0; -        const maps = []; -        let map = this._map; -        for (; i < ii; ++i) { -            const map2 = map.get(path[i]); -            if (typeof map2 === 'undefined') { return; } -            maps.push([map, map2]); -            map = map2; -        } - -        // Delete node -        map.delete(path[ii]); - -        // Clear empty paths -        for (i = ii - 1; i >= 0; --i) { -            let map2; -            [map, map2] = maps[i]; -            if (map2.size > 0) { return; } -            map.delete(path[i]); -        } -    } -      _resetEndNodes() {          this._listFirst.next = this._listLast;          this._listLast.previous = this._listFirst; |