All files / utils objectPool.ts

100% Statements 18/18
100% Branches 5/5
100% Functions 8/8
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126                                                                                                    13x                     13x 13x                   115x 115x 13x   102x                 111x 100x               1x             13x             1x                     3x 3x 90x   90x    
/**
 * Object Pool Utility
 * 
 * Generic object pooling for reducing garbage collection pressure.
 * Useful for frequently created/destroyed objects like damage numbers,
 * particles, or temporary game objects.
 * 
 * @module utils/objectPool
 * @category Performance
 * @korean 객체 풀
 */
 
/**
 * Interface for poolable objects
 * Objects must implement reset() to be reused
 */
export interface Poolable {
  /**
   * Reset object to initial state for reuse
   */
  reset(...args: unknown[]): void;
}
 
/**
 * Generic object pool
 * 
 * @example
 * ```typescript
 * class DamageNumber implements Poolable {
 *   value = 0;
 *   position = { x: 0, y: 0 };
 *   
 *   reset(value: number, x: number, y: number) {
 *     this.value = value;
 *     this.position.x = x;
 *     this.position.y = y;
 *   }
 * }
 * 
 * const pool = new ObjectPool(() => new DamageNumber(), 50);
 * 
 * // Acquire from pool
 * const damage = pool.acquire();
 * damage.reset(100, 10, 20);
 * 
 * // Return to pool when done
 * pool.release(damage);
 * ```
 */
export class ObjectPool<T extends Poolable> {
  private pool: T[] = [];
  private readonly factory: () => T;
  private readonly maxSize: number;
 
  /**
   * Create a new object pool
   * 
   * @param factory - Function to create new objects
   * @param maxSize - Maximum pool size (default: 100)
   */
  constructor(factory: () => T, maxSize = 100) {
    this.factory = factory;
    this.maxSize = maxSize;
  }
 
  /**
   * Acquire an object from the pool
   * Creates a new object if pool is empty
   * 
   * @returns Object from pool or newly created
   */
  acquire(): T {
    const pooled = this.pool.pop();
    if (pooled) {
      return pooled;
    }
    return this.factory();
  }
 
  /**
   * Return an object to the pool for reuse
   * 
   * @param obj - Object to return to pool
   */
  release(obj: T): void {
    if (this.pool.length < this.maxSize) {
      this.pool.push(obj);
    }
  }
 
  /**
   * Clear all objects from the pool
   */
  clear(): void {
    this.pool = [];
  }
 
  /**
   * Get current pool size
   */
  get size(): number {
    return this.pool.length;
  }
 
  /**
   * Get maximum pool size
   */
  get capacity(): number {
    return this.maxSize;
  }
}
 
/**
 * Pre-populate a pool with objects
 * 
 * @param pool - Object pool to populate
 * @param count - Number of objects to create
 */
export function prewarmPool<T extends Poolable>(pool: ObjectPool<T>, count: number): void {
  const objects: T[] = [];
  for (let i = 0; i < count; i++) {
    objects.push(pool.acquire());
  }
  objects.forEach(obj => pool.release(obj));
}