UNPKG

10.6 kBJavaScriptView Raw
1/*!
2 * @pixi-essentials/object-pool - v0.0.1-alpha.23
3 * Compiled Sat, 18 Apr 2020 16:37:59 UTC
4 *
5 * @pixi-essentials/object-pool is licensed under the MIT License.
6 * http://www.opensource.org/licenses/mit-license
7 */
8import { Ticker, UPDATE_PRIORITY } from '@pixi/ticker';
9
10/*! *****************************************************************************
11Copyright (c) Microsoft Corporation. All rights reserved.
12Licensed under the Apache License, Version 2.0 (the "License"); you may not use
13this file except in compliance with the License. You may obtain a copy of the
14License at http://www.apache.org/licenses/LICENSE-2.0
15
16THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
18WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
19MERCHANTABLITY OR NON-INFRINGEMENT.
20
21See the Apache Version 2.0 License for specific language governing permissions
22and limitations under the License.
23***************************************************************************** */
24/* global Reflect, Promise */
25
26var extendStatics = function(d, b) {
27 extendStatics = Object.setPrototypeOf ||
28 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
29 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
30 return extendStatics(d, b);
31};
32
33function __extends(d, b) {
34 extendStatics(d, b);
35 function __() { this.constructor = d; }
36 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
37}
38
39/**
40 * Provides the exponential moving average of a sequence.
41 *
42 * Ignored because not directly exposed.
43 *
44 * @internal
45 * @ignore
46 * @class
47 */
48var AverageProvider = /** @class */ (function () {
49 /**
50 * @ignore
51 * @param {number} windowSize - no. of inputs used to calculate window
52 * @param {number} decayRatio - quantifies the weight of previous values (b/w 0 and 1)
53 */
54 function AverageProvider(windowSize, decayRatio) {
55 this._history = new Array(windowSize);
56 this._decayRatio = decayRatio;
57 this._currentIndex = 0;
58 for (var i = 0; i < windowSize; i++) {
59 this._history[i] = 0;
60 }
61 }
62 /**
63 * @ignore
64 * @param {number} input - the next value in the sequence
65 * @returns {number} - the moving average
66 */
67 AverageProvider.prototype.next = function (input) {
68 var _a = this, history = _a._history, decayRatio = _a._decayRatio;
69 var historyLength = history.length;
70 this._currentIndex = this._currentIndex < historyLength - 1 ? this._currentIndex + 1 : 0;
71 history[this._currentIndex] = input;
72 var weightedSum = 0;
73 var weight = 0;
74 for (var i = this._currentIndex + 1; i < historyLength; i++) {
75 weightedSum = (weightedSum + history[i]) * decayRatio;
76 weight = (weight + 1) * decayRatio;
77 }
78 for (var i = 0; i <= this._currentIndex; i++) {
79 weightedSum = (weightedSum + history[i]) * decayRatio;
80 weight = (weight + 1) * decayRatio;
81 }
82 this._average = weightedSum / weight;
83 return this._average;
84 };
85 AverageProvider.prototype.absDev = function () {
86 var errSum = 0;
87 for (var i = 0, j = this._history.length; i < j; i++) {
88 errSum += Math.abs(this._history[i] - this._average);
89 }
90 return errSum / this._history.length;
91 };
92 return AverageProvider;
93}());
94
95/**
96 * `ObjectPool` provides the framework necessary for pooling minus the object instantiation
97 * method. You can use `ObjectPoolFactory` for objects that can be created using a default
98 * constructor.
99 *
100 * @template T
101 * @class
102 * @public
103 */
104var ObjectPool = /** @class */ (function () {
105 /**
106 * @param {IObjectPoolOptions} options
107 */
108 function ObjectPool(options) {
109 var _this = this;
110 if (options === void 0) { options = {}; }
111 this._gcTick = function () {
112 _this._borrowRateAverage = _this._borrowRateAverageProvider.next(_this._borrowRate);
113 _this._marginAverage = _this._marginAverageProvider.next(_this._freeCount - _this._borrowRate);
114 var absDev = _this._borrowRateAverageProvider.absDev();
115 _this._flowRate = 0;
116 _this._borrowRate = 0;
117 _this._returnRate = 0;
118 var poolSize = _this._freeCount;
119 var poolCapacity = _this._freeList.length;
120 // If the pool is small enough, it shouldn't really matter
121 if (poolSize < 128 && _this._borrowRateAverage < 128 && poolCapacity < 128) {
122 return;
123 }
124 // If pool is say, 2x, larger than borrowing rate on average (adjusted for variance/abs-dev), then downsize.
125 var threshold = Math.max(_this._borrowRateAverage * (_this._capacityRatio - 1), _this._reserveCount);
126 if (_this._freeCount > threshold + absDev) {
127 var newCap = threshold + absDev;
128 _this.capacity = Math.min(_this._freeList.length, Math.ceil(newCap));
129 _this._freeCount = _this._freeList.length;
130 }
131 };
132 /**
133 * Supply pool of objects that can be used to immediately lend.
134 *
135 * @member {Array<T>}
136 * @protected
137 */
138 this._freeList = [];
139 /**
140 * Number of objects in the pool. This is less than or equal to `_pool.length`.
141 *
142 * @member {number}
143 * @protected
144 */
145 this._freeCount = 0;
146 this._borrowRate = 0;
147 this._returnRate = 0;
148 this._flowRate = 0;
149 this._borrowRateAverage = 0;
150 this._reserveCount = options.reserve || 0;
151 this._capacityRatio = options.capacityRatio || 1.2;
152 this._decayRatio = options.decayRatio || 0.67;
153 this._marginAverage = 0;
154 this._borrowRateAverageProvider = new AverageProvider(128, this._decayRatio);
155 this._marginAverageProvider = new AverageProvider(128, this._decayRatio);
156 }
157 Object.defineProperty(ObjectPool.prototype, "capacity", {
158 // TODO: Support object destruction. It might not be so good for perf tho.
159 // /**
160 // * Destroys the object before discarding it.
161 // *
162 // * @param {T} object
163 // */
164 // abstract destroyObject(object: T): void;
165 /**
166 * The number of objects that can be stored in the pool without allocating more space.
167 *
168 * @member {number}
169 */
170 get: function () {
171 return this._freeList.length;
172 },
173 set: function (cp) {
174 this._freeList.length = Math.ceil(cp);
175 },
176 enumerable: true,
177 configurable: true
178 });
179 /**
180 * Obtains an instance from this pool.
181 *
182 * @returns {T}
183 */
184 ObjectPool.prototype.allocate = function () {
185 ++this._borrowRate;
186 ++this._flowRate;
187 if (this._freeCount > 0) {
188 return this._freeList[--this._freeCount];
189 }
190 return this.create();
191 };
192 /**
193 * Returns the object to the pool.
194 *
195 * @param {T} object
196 */
197 ObjectPool.prototype.release = function (object) {
198 ++this._returnRate;
199 --this._flowRate;
200 if (this._freeCount === this.capacity) {
201 this.capacity *= this._capacityRatio;
202 }
203 this._freeList[this._freeCount] = object;
204 ++this._freeCount;
205 };
206 /**
207 * Preallocates objects so that the pool size is at least `count`.
208 *
209 * @param {number} count
210 */
211 ObjectPool.prototype.reserve = function (count) {
212 this._reserveCount = count;
213 if (this._freeCount < count) {
214 var diff = this._freeCount - count;
215 for (var i = 0; i < diff; i++) {
216 this._freeList[this._freeCount] = this.create();
217 ++this._freeCount;
218 }
219 }
220 };
221 /**
222 * Dereferences objects for the GC to collect and brings the pool size down to `count`.
223 *
224 * @param {number} count
225 */
226 ObjectPool.prototype.limit = function (count) {
227 if (this._freeCount > count) {
228 var oldCapacity = this.capacity;
229 if (oldCapacity > count * this._capacityRatio) {
230 this.capacity = count * this._capacityRatio;
231 }
232 var excessBound = Math.min(this._freeCount, this.capacity);
233 for (var i = count; i < excessBound; i++) {
234 this._freeList[i] = null;
235 }
236 }
237 };
238 /**
239 * Install the GC on the shared ticker.
240 *
241 * @param {Ticker}[ticker=Ticker.shared]
242 */
243 ObjectPool.prototype.startGC = function (ticker) {
244 if (ticker === void 0) { ticker = Ticker.shared; }
245 ticker.add(this._gcTick, null, UPDATE_PRIORITY.UTILITY);
246 };
247 /**
248 * Stops running the GC on the pool.
249 *
250 * @param {Ticker}[ticker=Ticker.shared]
251 */
252 ObjectPool.prototype.stopGC = function (ticker) {
253 if (ticker === void 0) { ticker = Ticker.shared; }
254 ticker.remove(this._gcTick);
255 };
256 return ObjectPool;
257}());
258
259var poolMap = new Map();
260/**
261 * Factory for creating pools of objects with default constructors. It will store the pool of
262 * a given type and reuse it on further builds.
263 *
264 * @class
265 * @public
266 * @example
267 * ```js
268 * import { ObjectPool, ObjectPoolFactory } from 'pixi-object-pool';
269 *
270 * class AABB {}
271 *
272 * const opool: ObjectPool<AABB> = ObjectPoolFactory.build(AABB) as ObjectPool<AABB>;
273 *
274 * const temp = opool.borrowObject();
275 * // do something
276 * opool.returnObject(temp);
277 * ```
278 */
279var ObjectPoolFactory = /** @class */ (function () {
280 function ObjectPoolFactory() {
281 }
282 /**
283 * @param {Class} Type
284 */
285 ObjectPoolFactory.build = function (Type) {
286 var pool = poolMap.get(Type);
287 if (pool) {
288 return pool;
289 }
290 pool = new (/** @class */ (function (_super) {
291 __extends(DefaultObjectPool, _super);
292 function DefaultObjectPool() {
293 return _super !== null && _super.apply(this, arguments) || this;
294 }
295 DefaultObjectPool.prototype.create = function () {
296 return new Type();
297 };
298 return DefaultObjectPool;
299 }(ObjectPool)))();
300 poolMap.set(Type, pool);
301 return pool;
302 };
303 return ObjectPoolFactory;
304}());
305
306export { ObjectPool, ObjectPoolFactory };
307//# sourceMappingURL=pixi-object-pool.mjs.map