Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mamayaya1
GitHub Repository: mamayaya1/game
Path: blob/main/projects/HexGL/libs/Editor_files/pooled.js
4627 views
1
/**
2
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
3
* pool.js
4
*/
5
6
/**
7
* @class gamecore.Pool
8
* Easy (high-performance) object pooling
9
*
10
* A pool of objects for use in situations where you want to minimize object life cycling (and
11
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
12
* collection for small numbers of objects.
13
* <p>
14
* This class maintains mutual an array of objects which are free. If you wish to maintain a list of both
15
* free and used then see the gamecore.DualPool.
16
* <p>
17
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
18
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
19
* <p>
20
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
21
* You need to "acquire" one and then reset its state, usually via a static create factory method.
22
* <p>
23
* Example:
24
* <code>
25
* Point = gamecore.Pooled('Point',
26
* {
27
* // Static constructor
28
* create:function (x, y)
29
* {
30
* var n = this._super();
31
* n.x = x;
32
* n.y = y;
33
* return n;
34
* }
35
* },
36
* {
37
* x:0, y:0, // instance
38
*
39
* init: function(x, y)
40
* {
41
* this.x = x;
42
* this.y = y;
43
* }
44
* }
45
* </code>
46
* To then access the object from the pool, use create, instead of new. Then release it.
47
* <code>
48
* var p = Point.create(100, 100);
49
* // ... do something
50
* p.release();
51
* </code>
52
*
53
*/
54
55
gamecore.Pool = gamecore.Base.extend('gamecore.Pool',
56
{
57
INITIAL_POOL_SIZE:1,
58
59
pools:new gamecore.Hashtable(), // all your pools belong to us
60
totalPooled:0,
61
totalUsed:0,
62
63
/**
64
* Acquire an object from a pool based on the class[name]. Typically this method is
65
* automatically called from
66
* @param classType Class of object to create
67
*/
68
acquire:function (classType)
69
{
70
var pool = this.getPool(classType);
71
if (pool == undefined || pool == null)
72
{
73
// create a pool for this type of class
74
//this.info('Constructing a new pool for ' + classType.fullName + ' objects.');
75
pool = new gamecore.Pool(classType, this.INITIAL_POOL_SIZE);
76
this.pools.put(classType.fullName, pool);
77
}
78
79
return pool.acquire();
80
},
81
82
/**
83
* Releases an object back into it's corresponding object pool
84
* @param pooledObj Object to return to the pool
85
*/
86
release:function (pooledObj)
87
{
88
var pool = this.pools.get(pooledObj.Class.fullName);
89
if (pool == undefined)
90
throw "Oops, trying to release an object of type " + pooledObj.Class.fullName +
91
" but no pool exists. Did you new an object instead of using create.";
92
93
pool.release(pooledObj);
94
},
95
96
/**
97
* Returns the pool associated with the given classType, or null if no pool currently exists
98
*/
99
getPool:function (classType)
100
{
101
return this.pools.get(classType.fullName);
102
},
103
104
getStats:function ()
105
{
106
var s = '';
107
108
var keys = this.pools.keys();
109
for (var i = 0; i < keys.length; i++)
110
{
111
var key = keys[i];
112
var pool = this.pools.get(key);
113
s += key + ': ' + pool.getStats() + '\n';
114
}
115
116
return s;
117
}
118
119
},
120
{
121
freeList:null,
122
expansion: 1,
123
traces: null,
124
125
/**
126
* Constructs a pool using a base of objects passed in as an array.
127
* @param classType Class name of the type of objects in the pool
128
* @param initial Starting number of objects in the pool
129
*/
130
init:function (classType, initial)
131
{
132
this._super();
133
this.classType = classType;
134
this.freeList = [];
135
136
// instantiate the initial objects for the pool
137
this.expand(initial);
138
},
139
140
141
startTracing:function ()
142
{
143
if (this.tracing) return;
144
this.tracing = true;
145
if (this.traces)
146
this.traces.clear();
147
else
148
this.traces = new gamecore.Hashtable();
149
},
150
151
stopTracing:function ()
152
{
153
this.tracing = false;
154
},
155
156
/**
157
* Expand the pool of objects by constructing a bunch of new ones. The pool will
158
* automatically expand itself by 10% each time it runs out of space, so generally you
159
* shouldn't need to use this.
160
* @param howMany Number of new objects you want to add
161
*/
162
expand:function (howMany)
163
{
164
gamecore.Pool.totalPooled += howMany;
165
166
//debug: if you want to track expansion
167
//this.debug('expanding ' + this.classType.fullName + ' by ' + howMany + ' total=' + gamecore.Pool.totalPooled);
168
169
for (var i = 0; i < howMany; i++)
170
this.freeList.push(new this.classType());
171
},
172
173
getFreeCount: function()
174
{
175
return this.freeList.length;
176
},
177
178
/**
179
* Returns the next free object by moving it from the free pool to the used
180
* one. If no free objects are available it returns the oldest from the used
181
* pool.
182
* access to the object
183
*/
184
acquire:function ()
185
{
186
// check if we have anymore to give out
187
if (this.freeList.length <= 0)
188
{
189
// create some more space (expand by 20%, minimum 1)
190
this.expansion = Math.round(this.expansion*1.2)+1;
191
this.expand(this.expansion);
192
}
193
194
if (this.tracing)
195
{
196
var stack = printStackTrace();
197
var pos = stack.length - 1;
198
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
199
pos--;
200
var count = this.traces.get(stack[pos]);
201
if (count == null)
202
this.traces.put(stack[pos], { value:1 });
203
else
204
count.value++;
205
}
206
207
return this.freeList.pop();
208
},
209
210
/**
211
* Releases an object by moving it from the used list back to the free list.
212
* @param obj {pc.Base} The obj to release back into the pool
213
*/
214
release:function (obj)
215
{
216
this.freeList.push(obj);
217
},
218
219
getStats:function ()
220
{
221
var s = this.Class.fullName + ' stats: ' + this.freeList.length + ' free.\n';
222
223
if (this.tracing)
224
{
225
s += 'TRACING\n';
226
var traceKeys = this.traces.keys();
227
for (var k in traceKeys)
228
s += traceKeys[k] + ' (' + this.traces.get(traceKeys[k]).value + ')\n';
229
}
230
return s;
231
},
232
233
dump:function (msg)
234
{
235
this.info('================== ' + msg + ' ===================');
236
this.info('FREE');
237
this.freeList.dump();
238
},
239
240
/**
241
* Returns the number of objects in the pool
242
*/
243
size:function ()
244
{
245
return this.freeList.length;
246
},
247
248
/**
249
* Returns the LinkedList of currently free objects in the pool
250
*/
251
getFreeList:function ()
252
{
253
return this.freeList;
254
}
255
256
});
257
258
/**
259
* @class gamecore.DualPool
260
* Easy (high-performance) object pooling
261
*
262
* A pool of objects for use in situations where you want to minimize object life cycling (and
263
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
264
* collection for small numbers of objects.
265
* <p>
266
* This class maintains mutual set of doubly-linked lists in order to differentiate between
267
* objects that are in use and those that are unallocated from the pool. This allows for much
268
* faster cycling of only the in-use objects.
269
* <p>
270
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
271
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
272
* <p>
273
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
274
* You need to "acquire" one and then reset its state, usually via a static create factory method.
275
* <p>
276
* Example:
277
* <code>
278
* Point = gamecore.Pooled('Point',
279
* {
280
* // Static constructor
281
* create:function (x, y)
282
* {
283
* var n = this._super();
284
* n.x = x;
285
* n.y = y;
286
* return n;
287
* }
288
* },
289
* {
290
* x:0, y:0, // instance
291
*
292
* init: function(x, y)
293
* {
294
* this.x = x;
295
* this.y = y;
296
* }
297
* }
298
* </code>
299
* To then access the object from the pool, use create, instead of new. Then release it.
300
* <code>
301
* var p = Point.create(100, 100);
302
* // ... do something
303
* p.release();
304
* </code>
305
*
306
*/
307
308
gamecore.DualPool = gamecore.Pool.extend('gamecore.DualPool',
309
{
310
acquire:function (classType)
311
{
312
var pool = this.getPool(classType);
313
if (pool == undefined || pool == null)
314
{
315
pool = new gamecore.DualPool(classType, this.INITIAL_POOL_SIZE);
316
this.pools.put(classType.fullName, pool);
317
}
318
319
return pool.acquire();
320
},
321
322
getStats:function ()
323
{
324
var s = '';
325
326
var keys = this.pools.keys();
327
for (var i = 0; i < keys.length; i++)
328
{
329
var key = keys[i];
330
var pool = this.pools.get(key);
331
s += key + ' (free: ' + pool.freeList.length() + ' used: ' + pool.usedList.length() + ')\n';
332
}
333
return s;
334
}
335
},
336
///
337
/// INSTANCE
338
///
339
{
340
freeList:null,
341
usedList:null,
342
343
/**
344
* Constructs a pool using a base of objects passed in as an array.
345
* @param classType Class name of the type of objects in the pool
346
* @param initial Starting number of objects in the pool
347
*/
348
init:function (classType, initial)
349
{
350
this.classType = classType;
351
this.usedList = new gamecore.LinkedList();
352
this.freeList = new gamecore.LinkedList();
353
354
// instantiate the initial objects for the pool
355
this.expand(initial);
356
},
357
358
/**
359
* Expand the pool of objects by constructing a bunch of new ones. The pool will
360
* automatically expand itself by 10% each time it runs out of space, so generally you
361
* shouldn't need to use this.
362
* @param howMany Number of new objects you want to add
363
*/
364
expand:function (howMany)
365
{
366
// this.info('Expanding ' + this.classType.fullName + ' pool from ' + this.size() +
367
// ' to ' + (this.size() + howMany) + ' objects');
368
gamecore.Pool.totalPooled += howMany;
369
for (var i = 0; i < howMany; i++)
370
this.freeList.add(new this.classType());
371
},
372
373
/**
374
* Returns the next free object by moving it from the free pool to the used
375
* one. If no free objects are available it returns the oldest from the used
376
* pool.
377
* access to the object
378
*/
379
returnObj:null,
380
381
acquire:function ()
382
{
383
// check if we have anymore to give out
384
if (this.freeList.first == null)
385
// create some more space (expand by 20%, minimum 1)
386
this.expand(Math.round(this.size() / 5) + 1);
387
388
this.returnObj = this.freeList.first.obj;
389
this.freeList.remove(this.returnObj);
390
this.returnObj.destroyed = false;
391
this.usedList.add(this.returnObj);
392
393
if (this.tracing)
394
{
395
var stack = printStackTrace();
396
var pos = stack.length - 1;
397
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
398
pos--;
399
var count = this.traces.get(stack[pos]);
400
if (count == null)
401
this.traces.put(stack[pos], { value:1 });
402
else
403
count.value++;
404
}
405
406
return this.returnObj;
407
},
408
409
/**
410
* Releases an object by moving it from the used list back to the free list.
411
* @param obj {pc.Base} The obj to release back into the pool
412
*/
413
release:function (obj)
414
{
415
this.freeList.add(obj);
416
this.usedList.remove(obj);
417
},
418
419
dump:function (msg)
420
{
421
this.info('================== ' + msg + ' ===================');
422
this.info('FREE');
423
this.freeList.dump();
424
this.info('USED');
425
this.usedList.dump();
426
},
427
428
/**
429
* Returns the number of objects in the pool
430
*/
431
size:function ()
432
{
433
return this.freeList.count + this.usedList.count;
434
},
435
436
/**
437
* Returns the LinkedList of current used objects in the pool
438
* @return {*}
439
*/
440
getUsedList:function ()
441
{
442
return this.usedList;
443
}
444
});
445
446
447
/**
448
* @class gamecore.Pooled
449
* Used as a base class for objects which are life cycle managed in an object pool.
450
*/
451
gamecore.Pooled = gamecore.Base('gamecore.Pooled',
452
///
453
/// STATICS
454
///
455
{
456
/**
457
* Static factory method for creating a new object based on its class. This method
458
* should be called using this._super from the Class.create that derives from this.
459
* @returns An object from the pool
460
*/
461
create:function ()
462
{
463
return gamecore.Pool.acquire(this);
464
},
465
466
getPool:function ()
467
{
468
return gamecore.Pool.getPool(this);
469
}
470
471
},
472
///
473
/// INSTANCE
474
///
475
{
476
destroyed:false,
477
478
init:function ()
479
{
480
this._super();
481
},
482
483
release:function ()
484
{
485
this.onRelease();
486
gamecore.Pool.release(this);
487
},
488
489
onRelease:function ()
490
{
491
}
492
493
});
494
495
496
/**
497
* @class gamecore.DualPooled
498
* Used as a base class for objects which are life cycle managed in an object pool (the DualPool edition)
499
*/
500
gamecore.DualPooled = gamecore.Base('gamecore.DualPooled',
501
///
502
/// STATICS
503
///
504
{
505
/**
506
* Static factory method for creating a new object based on its class. This method
507
* should be called using this._super from the Class.create that derives from this.
508
* @returns An object from the pool
509
*/
510
create:function ()
511
{
512
return gamecore.DualPool.acquire(this);
513
},
514
515
getPool:function ()
516
{
517
return gamecore.DualPool.getPool(this);
518
}
519
520
},
521
///
522
/// INSTANCE
523
///
524
{
525
destroyed:false,
526
527
init:function ()
528
{
529
this._super();
530
},
531
532
release:function ()
533
{
534
this.onRelease();
535
gamecore.DualPool.release(this);
536
},
537
538
onRelease:function ()
539
{
540
}
541
542
});
543
544