Path: blob/main/projects/HexGL/libs/Editor_files/pooled.js
4627 views
/**1* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)2* pool.js3*/45/**6* @class gamecore.Pool7* Easy (high-performance) object pooling8*9* A pool of objects for use in situations where you want to minimize object life cycling (and10* subsequently garbage collection). It also serves as a very high speed, minimal overhead11* collection for small numbers of objects.12* <p>13* This class maintains mutual an array of objects which are free. If you wish to maintain a list of both14* free and used then see the gamecore.DualPool.15* <p>16* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool17* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.18* <p>19* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.20* You need to "acquire" one and then reset its state, usually via a static create factory method.21* <p>22* Example:23* <code>24* Point = gamecore.Pooled('Point',25* {26* // Static constructor27* create:function (x, y)28* {29* var n = this._super();30* n.x = x;31* n.y = y;32* return n;33* }34* },35* {36* x:0, y:0, // instance37*38* init: function(x, y)39* {40* this.x = x;41* this.y = y;42* }43* }44* </code>45* To then access the object from the pool, use create, instead of new. Then release it.46* <code>47* var p = Point.create(100, 100);48* // ... do something49* p.release();50* </code>51*52*/5354gamecore.Pool = gamecore.Base.extend('gamecore.Pool',55{56INITIAL_POOL_SIZE:1,5758pools:new gamecore.Hashtable(), // all your pools belong to us59totalPooled:0,60totalUsed:0,6162/**63* Acquire an object from a pool based on the class[name]. Typically this method is64* automatically called from65* @param classType Class of object to create66*/67acquire:function (classType)68{69var pool = this.getPool(classType);70if (pool == undefined || pool == null)71{72// create a pool for this type of class73//this.info('Constructing a new pool for ' + classType.fullName + ' objects.');74pool = new gamecore.Pool(classType, this.INITIAL_POOL_SIZE);75this.pools.put(classType.fullName, pool);76}7778return pool.acquire();79},8081/**82* Releases an object back into it's corresponding object pool83* @param pooledObj Object to return to the pool84*/85release:function (pooledObj)86{87var pool = this.pools.get(pooledObj.Class.fullName);88if (pool == undefined)89throw "Oops, trying to release an object of type " + pooledObj.Class.fullName +90" but no pool exists. Did you new an object instead of using create.";9192pool.release(pooledObj);93},9495/**96* Returns the pool associated with the given classType, or null if no pool currently exists97*/98getPool:function (classType)99{100return this.pools.get(classType.fullName);101},102103getStats:function ()104{105var s = '';106107var keys = this.pools.keys();108for (var i = 0; i < keys.length; i++)109{110var key = keys[i];111var pool = this.pools.get(key);112s += key + ': ' + pool.getStats() + '\n';113}114115return s;116}117118},119{120freeList:null,121expansion: 1,122traces: null,123124/**125* Constructs a pool using a base of objects passed in as an array.126* @param classType Class name of the type of objects in the pool127* @param initial Starting number of objects in the pool128*/129init:function (classType, initial)130{131this._super();132this.classType = classType;133this.freeList = [];134135// instantiate the initial objects for the pool136this.expand(initial);137},138139140startTracing:function ()141{142if (this.tracing) return;143this.tracing = true;144if (this.traces)145this.traces.clear();146else147this.traces = new gamecore.Hashtable();148},149150stopTracing:function ()151{152this.tracing = false;153},154155/**156* Expand the pool of objects by constructing a bunch of new ones. The pool will157* automatically expand itself by 10% each time it runs out of space, so generally you158* shouldn't need to use this.159* @param howMany Number of new objects you want to add160*/161expand:function (howMany)162{163gamecore.Pool.totalPooled += howMany;164165//debug: if you want to track expansion166//this.debug('expanding ' + this.classType.fullName + ' by ' + howMany + ' total=' + gamecore.Pool.totalPooled);167168for (var i = 0; i < howMany; i++)169this.freeList.push(new this.classType());170},171172getFreeCount: function()173{174return this.freeList.length;175},176177/**178* Returns the next free object by moving it from the free pool to the used179* one. If no free objects are available it returns the oldest from the used180* pool.181* access to the object182*/183acquire:function ()184{185// check if we have anymore to give out186if (this.freeList.length <= 0)187{188// create some more space (expand by 20%, minimum 1)189this.expansion = Math.round(this.expansion*1.2)+1;190this.expand(this.expansion);191}192193if (this.tracing)194{195var stack = printStackTrace();196var pos = stack.length - 1;197while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)198pos--;199var count = this.traces.get(stack[pos]);200if (count == null)201this.traces.put(stack[pos], { value:1 });202else203count.value++;204}205206return this.freeList.pop();207},208209/**210* Releases an object by moving it from the used list back to the free list.211* @param obj {pc.Base} The obj to release back into the pool212*/213release:function (obj)214{215this.freeList.push(obj);216},217218getStats:function ()219{220var s = this.Class.fullName + ' stats: ' + this.freeList.length + ' free.\n';221222if (this.tracing)223{224s += 'TRACING\n';225var traceKeys = this.traces.keys();226for (var k in traceKeys)227s += traceKeys[k] + ' (' + this.traces.get(traceKeys[k]).value + ')\n';228}229return s;230},231232dump:function (msg)233{234this.info('================== ' + msg + ' ===================');235this.info('FREE');236this.freeList.dump();237},238239/**240* Returns the number of objects in the pool241*/242size:function ()243{244return this.freeList.length;245},246247/**248* Returns the LinkedList of currently free objects in the pool249*/250getFreeList:function ()251{252return this.freeList;253}254255});256257/**258* @class gamecore.DualPool259* Easy (high-performance) object pooling260*261* A pool of objects for use in situations where you want to minimize object life cycling (and262* subsequently garbage collection). It also serves as a very high speed, minimal overhead263* collection for small numbers of objects.264* <p>265* This class maintains mutual set of doubly-linked lists in order to differentiate between266* objects that are in use and those that are unallocated from the pool. This allows for much267* faster cycling of only the in-use objects.268* <p>269* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool270* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.271* <p>272* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.273* You need to "acquire" one and then reset its state, usually via a static create factory method.274* <p>275* Example:276* <code>277* Point = gamecore.Pooled('Point',278* {279* // Static constructor280* create:function (x, y)281* {282* var n = this._super();283* n.x = x;284* n.y = y;285* return n;286* }287* },288* {289* x:0, y:0, // instance290*291* init: function(x, y)292* {293* this.x = x;294* this.y = y;295* }296* }297* </code>298* To then access the object from the pool, use create, instead of new. Then release it.299* <code>300* var p = Point.create(100, 100);301* // ... do something302* p.release();303* </code>304*305*/306307gamecore.DualPool = gamecore.Pool.extend('gamecore.DualPool',308{309acquire:function (classType)310{311var pool = this.getPool(classType);312if (pool == undefined || pool == null)313{314pool = new gamecore.DualPool(classType, this.INITIAL_POOL_SIZE);315this.pools.put(classType.fullName, pool);316}317318return pool.acquire();319},320321getStats:function ()322{323var s = '';324325var keys = this.pools.keys();326for (var i = 0; i < keys.length; i++)327{328var key = keys[i];329var pool = this.pools.get(key);330s += key + ' (free: ' + pool.freeList.length() + ' used: ' + pool.usedList.length() + ')\n';331}332return s;333}334},335///336/// INSTANCE337///338{339freeList:null,340usedList:null,341342/**343* Constructs a pool using a base of objects passed in as an array.344* @param classType Class name of the type of objects in the pool345* @param initial Starting number of objects in the pool346*/347init:function (classType, initial)348{349this.classType = classType;350this.usedList = new gamecore.LinkedList();351this.freeList = new gamecore.LinkedList();352353// instantiate the initial objects for the pool354this.expand(initial);355},356357/**358* Expand the pool of objects by constructing a bunch of new ones. The pool will359* automatically expand itself by 10% each time it runs out of space, so generally you360* shouldn't need to use this.361* @param howMany Number of new objects you want to add362*/363expand:function (howMany)364{365// this.info('Expanding ' + this.classType.fullName + ' pool from ' + this.size() +366// ' to ' + (this.size() + howMany) + ' objects');367gamecore.Pool.totalPooled += howMany;368for (var i = 0; i < howMany; i++)369this.freeList.add(new this.classType());370},371372/**373* Returns the next free object by moving it from the free pool to the used374* one. If no free objects are available it returns the oldest from the used375* pool.376* access to the object377*/378returnObj:null,379380acquire:function ()381{382// check if we have anymore to give out383if (this.freeList.first == null)384// create some more space (expand by 20%, minimum 1)385this.expand(Math.round(this.size() / 5) + 1);386387this.returnObj = this.freeList.first.obj;388this.freeList.remove(this.returnObj);389this.returnObj.destroyed = false;390this.usedList.add(this.returnObj);391392if (this.tracing)393{394var stack = printStackTrace();395var pos = stack.length - 1;396while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)397pos--;398var count = this.traces.get(stack[pos]);399if (count == null)400this.traces.put(stack[pos], { value:1 });401else402count.value++;403}404405return this.returnObj;406},407408/**409* Releases an object by moving it from the used list back to the free list.410* @param obj {pc.Base} The obj to release back into the pool411*/412release:function (obj)413{414this.freeList.add(obj);415this.usedList.remove(obj);416},417418dump:function (msg)419{420this.info('================== ' + msg + ' ===================');421this.info('FREE');422this.freeList.dump();423this.info('USED');424this.usedList.dump();425},426427/**428* Returns the number of objects in the pool429*/430size:function ()431{432return this.freeList.count + this.usedList.count;433},434435/**436* Returns the LinkedList of current used objects in the pool437* @return {*}438*/439getUsedList:function ()440{441return this.usedList;442}443});444445446/**447* @class gamecore.Pooled448* Used as a base class for objects which are life cycle managed in an object pool.449*/450gamecore.Pooled = gamecore.Base('gamecore.Pooled',451///452/// STATICS453///454{455/**456* Static factory method for creating a new object based on its class. This method457* should be called using this._super from the Class.create that derives from this.458* @returns An object from the pool459*/460create:function ()461{462return gamecore.Pool.acquire(this);463},464465getPool:function ()466{467return gamecore.Pool.getPool(this);468}469470},471///472/// INSTANCE473///474{475destroyed:false,476477init:function ()478{479this._super();480},481482release:function ()483{484this.onRelease();485gamecore.Pool.release(this);486},487488onRelease:function ()489{490}491492});493494495/**496* @class gamecore.DualPooled497* Used as a base class for objects which are life cycle managed in an object pool (the DualPool edition)498*/499gamecore.DualPooled = gamecore.Base('gamecore.DualPooled',500///501/// STATICS502///503{504/**505* Static factory method for creating a new object based on its class. This method506* should be called using this._super from the Class.create that derives from this.507* @returns An object from the pool508*/509create:function ()510{511return gamecore.DualPool.acquire(this);512},513514getPool:function ()515{516return gamecore.DualPool.getPool(this);517}518519},520///521/// INSTANCE522///523{524destroyed:false,525526init:function ()527{528this._super();529},530531release:function ()532{533this.onRelease();534gamecore.DualPool.release(this);535},536537onRelease:function ()538{539}540541});542543544