Source: datastructures/ObjectPool.js

(function(global) {
    "use strict";

    var IDS = 0;

    /**
     * @class ObjectPool
     * @author thegoldenmule
     * @desc Creates a preallocated, static pool of objects.
     * @param {Number} size The number of objects to preallocate.
     * @param {Number} factory A Function that returns a new object.
     * @param {Function} onGet (optional) A Function to call when an instance
     * is retrieved from the pool.
     * @param {Function} onPut (optional) A Function to call when an instance
     * is put back in the pool.
     * @returns {ObjectPool}
     * @constructor
     */
    global.ObjectPool = function(size, factory, onGet, onPut) {
        var scope = this,
            _id = "__pool" + (++IDS),
            _instances = [size],
            _availableIndices = [size];

        for (var i = 0; i < size; i++) {
            _availableIndices[i] = i;

            _instances[i] = factory();
            _instances[i][_id] = i;
        }

        /**
         * @function global.ObjectPool#get
         * @desc Retrieves an object or null if none are left in the pool.
         *
         * @returns {Object}
         */
        scope.get = function() {
            if (_availableIndices.length > 0) {
                var index = _availableIndices.pop();
                var instance = _instances[index];
                instance[_id] = index;

                if (undefined !== onGet) {
                    onGet(instance);
                }

                return instance;
            }

            return null;
        };

        /**
         * @function global.ObjectPool#put
         * @desc Puts an object back in the pool.
         * @param {Object} instance The instance to return to the pool. If the
         * object was not originally retrieved from the pool, nothing will
         * happen...
         */
        scope.put = function(instance) {
            if (undefined === instance[_id]) {
                return;
            }

            _availableIndices.push(instance[_id]);

            if (undefined !== onPut) {
                onPut(instance);
            }
        };

        return scope;
    };

})(this);