File

projects/wms-framework/src/lib/decorators/Memoize.ts

Description

Interface of the type of arguments allowed to configure the memoize

Index

Properties

Properties

expireAfter
expireAfter: number
Type : number
Optional

To indicate the value stored can be expired after a number of milliseconds

hashFunction
hashFunction: function
Type : function
Optional

Hash function to use to generate the hashkey using the parameters

returnCallback
returnCallback: function
Type : function
Optional

Callback function to execute before returning the result

interface MemoizeArgs {
  /**
   * To indicate the value stored can be expired after a number of milliseconds
   *
   * @type {number}
   * @memberof MemoizeArgs
   */
  expireAfter?: number;

  /**
   * Hash function to use to generate the hashkey using the parameters
   *
   * @memberof MemoizeArgs
   */
  hashFunction?: (...args: any[]) => any;

  /**
   * Callback function to execute before returning the result
   *
   * @memberof MemoizeArgs
   */
  returnCallback?: (result: any) => any;
}

/**
 * Structure of values being memoized
 *
 * @interface MemoizedEntry
 */
interface MemoizedEntry {
  /**
   * Value being memoized
   *
   * @type {*}
   * @memberof MemoizedEntry
   */
  value: any;

  /**
   * Expiration date (in milliseconds) of the value if defined
   *
   * @type {number}
   * @memberof MemoizedEntry
   */
  expirationDate?: number;
}

/**
 * Decorator to use to do memoize of functions
 *
 * @export
 * @param {MemoizeArgs} [args]
 * @return {*}
 */
export function Memoize(args?: MemoizeArgs) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    if (descriptor.value != null) {
      descriptor.value = configureMemoize(descriptor.value, args);
    } else {
      throw 'Memoize decorator can be used only on methods';
    }
  };
}

function configureMemoize(
  originalMethod: Function,
  memoizeArgs?: MemoizeArgs
): any {
  const undefinedKey = `__undefinedKey__${Date.now()}__`;
  const nullKey = `__nullKey__${Date.now()}__`;
  let buffer: Map<any, any> = new Map<any, any>();

  return function (...args) {
    const key =
      memoizeArgs?.hashFunction?.apply?.(this, args) ??
      (args.length > 0
        ? args
            .map(
              (a) =>
                (a === undefined ? undefinedKey : a === null ? nullKey : a) + ''
            )
            .join('-')
        : originalMethod);

    let memoizedEntry: MemoizedEntry = buffer.get(key);
    if (
      memoizedEntry != null &&
      (memoizedEntry.expirationDate == null ||
        memoizedEntry.expirationDate > Date.now())
    ) {
      return (
        memoizeArgs?.returnCallback?.(memoizedEntry.value) ??
        memoizedEntry.value
      );
    }

    memoizedEntry = { value: originalMethod.apply(this, args) };
    if (memoizeArgs?.expireAfter > 0)
      memoizedEntry.expirationDate = Date.now() + memoizeArgs?.expireAfter;

    buffer.set(key, memoizedEntry);
    return (
      memoizeArgs?.returnCallback?.(memoizedEntry.value) ?? memoizedEntry.value
    );
  };
}

result-matching ""

    No results matching ""