Source: caches.js

'use strict'

/**
 * @module caches
 */
export const caches = {};

/**
 * A very minimal cache. When the maximum size is reached, the oldest entry is removed from the cache.
 *
 * @param {number} maxSize the maximum number of entries to keep.
 * @memberOf module:caches
 * @constructor
 * @struct
 * @final
 */
caches.Cache = function (maxSize) {

  const maxSize_ = maxSize ? maxSize : 100;
  let queue_ = [];
  let map_ = {};

  /**
   * Returns the number of cached objects.
   *
   * @return {number} the number of cached objects.
   */
  this.size = function () {
    return Object.keys(map_).length;
  }

  /**
   * Check if a key has already been added to the cache.
   *
   * @param {string} key the key to check.
   * @return {boolean} true iif the key already exists, false otherwise.
   */
  this.contains = function (key) {
    return map_.hasOwnProperty(key);
  }

  /**
   * Adds a single cache entry.
   *
   * @param {string} key the entry key.
   * @param {*} value the entry value.
   * @return {*|null} the values previously associated with the given key.
   */
  this.put = function (key, value) {
    const prev = this.get(key);
    if (queue_.length >= maxSize_) {
      this.remove(queue_[0].key);
    }
    map_[key] = value;
    queue_.push({key: key, value: value});
    return prev;
  }

  /**
   * Returns a single cache entry.
   *
   * @param {string} key the key to get.
   * @return {*|null} the value associated with the given key.
   */
  this.get = function (key) {
    return this.contains(key) ? map_[key] : null;
  }

  /**
   * Returns a single cache entry or a default value if the cache key does not belong to the cache.
   *
   * @param {string} key the key to get.
   * @param {*|null} defaultValue the default value to return.
   */
  this.getOrDefault = function (key, defaultValue) {
    return this.contains(key) ? this.get(key) : defaultValue;
  }

  /**
   * Returns a single cache entry or add a new one if the cache key does not belong to the cache.
   *
   * @param key the key to get.
   * @param defaultValue the default to add to the cache.
   * @return {*|null}
   */
  this.getOrPut = function (key, defaultValue) {
    if (!this.contains(key)) {
      this.put(key, defaultValue);
    }
    return this.get(key);
  }

  /**
   * Removes a single cache entry.
   *
   * @param {string} key the key to evict.
   * @return {*|null} the value previously associated with the given key.
   */
  this.remove = function (key) {
    if (this.contains(key)) {
      const prev = this.get(key);
      queue_ = queue_.filter(entry => entry.key !== key);
      delete map_[key];
      return prev;
    }
    return null;
  }

  /**
   * Removes all cache entries.
   */
  this.invalidate = function () {
    map_ = {};
    queue_ = [];
  }
}