Файл: Space race/libs/Editor_files/pooled.js
Строк: 469
<?php
/**
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
* pool.js
*/
/**
* @class gamecore.Pool
* Easy (high-performance) object pooling
*
* A pool of objects for use in situations where you want to minimize object life cycling (and
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
* collection for small numbers of objects.
* <p>
* This class maintains mutual an array of objects which are free. If you wish to maintain a list of both
* free and used then see the gamecore.DualPool.
* <p>
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
* <p>
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
* You need to "acquire" one and then reset its state, usually via a static create factory method.
* <p>
* Example:
* <code>
* Point = gamecore.Pooled('Point',
* {
* // Static constructor
* create:function (x, y)
* {
* var n = this._super();
* n.x = x;
* n.y = y;
* return n;
* }
* },
* {
* x:0, y:0, // instance
*
* init: function(x, y)
* {
* this.x = x;
* this.y = y;
* }
* }
* </code>
* To then access the object from the pool, use create, instead of new. Then release it.
* <code>
* var p = Point.create(100, 100);
* // ... do something
* p.release();
* </code>
*
*/
gamecore.Pool = gamecore.Base.extend('gamecore.Pool',
{
INITIAL_POOL_SIZE:1,
pools:new gamecore.Hashtable(), // all your pools belong to us
totalPooled:0,
totalUsed:0,
/**
* Acquire an object from a pool based on the class[name]. Typically this method is
* automatically called from
* @param classType Class of object to create
*/
acquire:function (classType)
{
var pool = this.getPool(classType);
if (pool == undefined || pool == null)
{
// create a pool for this type of class
//this.info('Constructing a new pool for ' + classType.fullName + ' objects.');
pool = new gamecore.Pool(classType, this.INITIAL_POOL_SIZE);
this.pools.put(classType.fullName, pool);
}
return pool.acquire();
},
/**
* Releases an object back into it's corresponding object pool
* @param pooledObj Object to return to the pool
*/
release:function (pooledObj)
{
var pool = this.pools.get(pooledObj.Class.fullName);
if (pool == undefined)
throw "Oops, trying to release an object of type " + pooledObj.Class.fullName +
" but no pool exists. Did you new an object instead of using create.";
pool.release(pooledObj);
},
/**
* Returns the pool associated with the given classType, or null if no pool currently exists
*/
getPool:function (classType)
{
return this.pools.get(classType.fullName);
},
getStats:function ()
{
var s = '';
var keys = this.pools.keys();
for (var i = 0; i < keys.length; i++)
{
var key = keys[i];
var pool = this.pools.get(key);
s += key + ': ' + pool.getStats() + 'n';
}
return s;
}
},
{
freeList:null,
expansion: 1,
traces: null,
/**
* Constructs a pool using a base of objects passed in as an array.
* @param classType Class name of the type of objects in the pool
* @param initial Starting number of objects in the pool
*/
init:function (classType, initial)
{
this._super();
this.classType = classType;
this.freeList = [];
// instantiate the initial objects for the pool
this.expand(initial);
},
startTracing:function ()
{
if (this.tracing) return;
this.tracing = true;
if (this.traces)
this.traces.clear();
else
this.traces = new gamecore.Hashtable();
},
stopTracing:function ()
{
this.tracing = false;
},
/**
* Expand the pool of objects by constructing a bunch of new ones. The pool will
* automatically expand itself by 10% each time it runs out of space, so generally you
* shouldn't need to use this.
* @param howMany Number of new objects you want to add
*/
expand:function (howMany)
{
gamecore.Pool.totalPooled += howMany;
//debug: if you want to track expansion
//this.debug('expanding ' + this.classType.fullName + ' by ' + howMany + ' total=' + gamecore.Pool.totalPooled);
for (var i = 0; i < howMany; i++)
this.freeList.push(new this.classType());
},
getFreeCount: function()
{
return this.freeList.length;
},
/**
* Returns the next free object by moving it from the free pool to the used
* one. If no free objects are available it returns the oldest from the used
* pool.
* access to the object
*/
acquire:function ()
{
// check if we have anymore to give out
if (this.freeList.length <= 0)
{
// create some more space (expand by 20%, minimum 1)
this.expansion = Math.round(this.expansion*1.2)+1;
this.expand(this.expansion);
}
if (this.tracing)
{
var stack = printStackTrace();
var pos = stack.length - 1;
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
pos--;
var count = this.traces.get(stack[pos]);
if (count == null)
this.traces.put(stack[pos], { value:1 });
else
count.value++;
}
return this.freeList.pop();
},
/**
* Releases an object by moving it from the used list back to the free list.
* @param obj {pc.Base} The obj to release back into the pool
*/
release:function (obj)
{
this.freeList.push(obj);
},
getStats:function ()
{
var s = this.Class.fullName + ' stats: ' + this.freeList.length + ' free.n';
if (this.tracing)
{
s += 'TRACINGn';
var traceKeys = this.traces.keys();
for (var k in traceKeys)
s += traceKeys[k] + ' (' + this.traces.get(traceKeys[k]).value + ')n';
}
return s;
},
dump:function (msg)
{
this.info('================== ' + msg + ' ===================');
this.info('FREE');
this.freeList.dump();
},
/**
* Returns the number of objects in the pool
*/
size:function ()
{
return this.freeList.length;
},
/**
* Returns the LinkedList of currently free objects in the pool
*/
getFreeList:function ()
{
return this.freeList;
}
});
/**
* @class gamecore.DualPool
* Easy (high-performance) object pooling
*
* A pool of objects for use in situations where you want to minimize object life cycling (and
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
* collection for small numbers of objects.
* <p>
* This class maintains mutual set of doubly-linked lists in order to differentiate between
* objects that are in use and those that are unallocated from the pool. This allows for much
* faster cycling of only the in-use objects.
* <p>
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
* <p>
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
* You need to "acquire" one and then reset its state, usually via a static create factory method.
* <p>
* Example:
* <code>
* Point = gamecore.Pooled('Point',
* {
* // Static constructor
* create:function (x, y)
* {
* var n = this._super();
* n.x = x;
* n.y = y;
* return n;
* }
* },
* {
* x:0, y:0, // instance
*
* init: function(x, y)
* {
* this.x = x;
* this.y = y;
* }
* }
* </code>
* To then access the object from the pool, use create, instead of new. Then release it.
* <code>
* var p = Point.create(100, 100);
* // ... do something
* p.release();
* </code>
*
*/
gamecore.DualPool = gamecore.Pool.extend('gamecore.DualPool',
{
acquire:function (classType)
{
var pool = this.getPool(classType);
if (pool == undefined || pool == null)
{
pool = new gamecore.DualPool(classType, this.INITIAL_POOL_SIZE);
this.pools.put(classType.fullName, pool);
}
return pool.acquire();
},
getStats:function ()
{
var s = '';
var keys = this.pools.keys();
for (var i = 0; i < keys.length; i++)
{
var key = keys[i];
var pool = this.pools.get(key);
s += key + ' (free: ' + pool.freeList.length() + ' used: ' + pool.usedList.length() + ')n';
}
return s;
}
},
///
/// INSTANCE
///
{
freeList:null,
usedList:null,
/**
* Constructs a pool using a base of objects passed in as an array.
* @param classType Class name of the type of objects in the pool
* @param initial Starting number of objects in the pool
*/
init:function (classType, initial)
{
this.classType = classType;
this.usedList = new gamecore.LinkedList();
this.freeList = new gamecore.LinkedList();
// instantiate the initial objects for the pool
this.expand(initial);
},
/**
* Expand the pool of objects by constructing a bunch of new ones. The pool will
* automatically expand itself by 10% each time it runs out of space, so generally you
* shouldn't need to use this.
* @param howMany Number of new objects you want to add
*/
expand:function (howMany)
{
// this.info('Expanding ' + this.classType.fullName + ' pool from ' + this.size() +
// ' to ' + (this.size() + howMany) + ' objects');
gamecore.Pool.totalPooled += howMany;
for (var i = 0; i < howMany; i++)
this.freeList.add(new this.classType());
},
/**
* Returns the next free object by moving it from the free pool to the used
* one. If no free objects are available it returns the oldest from the used
* pool.
* access to the object
*/
returnObj:null,
acquire:function ()
{
// check if we have anymore to give out
if (this.freeList.first == null)
// create some more space (expand by 20%, minimum 1)
this.expand(Math.round(this.size() / 5) + 1);
this.returnObj = this.freeList.first.obj;
this.freeList.remove(this.returnObj);
this.returnObj.destroyed = false;
this.usedList.add(this.returnObj);
if (this.tracing)
{
var stack = printStackTrace();
var pos = stack.length - 1;
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
pos--;
var count = this.traces.get(stack[pos]);
if (count == null)
this.traces.put(stack[pos], { value:1 });
else
count.value++;
}
return this.returnObj;
},
/**
* Releases an object by moving it from the used list back to the free list.
* @param obj {pc.Base} The obj to release back into the pool
*/
release:function (obj)
{
this.freeList.add(obj);
this.usedList.remove(obj);
},
dump:function (msg)
{
this.info('================== ' + msg + ' ===================');
this.info('FREE');
this.freeList.dump();
this.info('USED');
this.usedList.dump();
},
/**
* Returns the number of objects in the pool
*/
size:function ()
{
return this.freeList.count + this.usedList.count;
},
/**
* Returns the LinkedList of current used objects in the pool
* @return {*}
*/
getUsedList:function ()
{
return this.usedList;
}
});
/**
* @class gamecore.Pooled
* Used as a base class for objects which are life cycle managed in an object pool.
*/
gamecore.Pooled = gamecore.Base('gamecore.Pooled',
///
/// STATICS
///
{
/**
* Static factory method for creating a new object based on its class. This method
* should be called using this._super from the Class.create that derives from this.
* @returns An object from the pool
*/
create:function ()
{
return gamecore.Pool.acquire(this);
},
getPool:function ()
{
return gamecore.Pool.getPool(this);
}
},
///
/// INSTANCE
///
{
destroyed:false,
init:function ()
{
this._super();
},
release:function ()
{
this.onRelease();
gamecore.Pool.release(this);
},
onRelease:function ()
{
}
});
/**
* @class gamecore.DualPooled
* Used as a base class for objects which are life cycle managed in an object pool (the DualPool edition)
*/
gamecore.DualPooled = gamecore.Base('gamecore.DualPooled',
///
/// STATICS
///
{
/**
* Static factory method for creating a new object based on its class. This method
* should be called using this._super from the Class.create that derives from this.
* @returns An object from the pool
*/
create:function ()
{
return gamecore.DualPool.acquire(this);
},
getPool:function ()
{
return gamecore.DualPool.getPool(this);
}
},
///
/// INSTANCE
///
{
destroyed:false,
init:function ()
{
this._super();
},
release:function ()
{
this.onRelease();
gamecore.DualPool.release(this);
},
onRelease:function ()
{
}
});
?>