Skip to content

Commit d9b6946

Browse files
committed
optimize pool implementation (for performance)
remove previous inUse array, and replaced by a counter to keep track of "used" instances
1 parent 5b54a31 commit d9b6946

File tree

2 files changed

+44
-19
lines changed

2 files changed

+44
-19
lines changed

packages/melonjs/src/system/pool.test.ts

+15-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ test("can acquire objects from the pool", () => {
1414
expect(object1).toBeInstanceOf(GameObject);
1515
expect(object2).toBeInstanceOf(GameObject);
1616
expect(object1).not.toBe(object2);
17-
expect(pool.size()).toBe(2);
17+
expect(pool.size()).toBe(0);
18+
expect(pool.used()).toBe(2);
1819
});
1920

2021
test("can release objects from the pool", () => {
@@ -23,27 +24,34 @@ test("can release objects from the pool", () => {
2324
});
2425
const object1 = pool.get();
2526
pool.release(object1);
26-
pool.get();
2727
expect(pool.size()).toBe(1);
28+
expect(pool.used()).toBe(0);
29+
pool.get();
30+
expect(pool.size()).toBe(0);
31+
expect(pool.used()).toBe(1);
2832
});
2933

3034
test("can manually purge", () => {
3135
const pool = createPool(() => {
3236
return { instance: new GameObject() };
3337
});
3438
const object1 = pool.get();
39+
expect(pool.used()).toBe(1);
3540
const object2 = pool.get();
3641
const object3 = pool.get();
37-
expect(pool.size()).toBe(3);
42+
expect(pool.size()).toBe(0);
43+
expect(pool.used()).toBe(3);
3844
pool.release(object1);
39-
pool.purge();
40-
expect(pool.size()).toBe(2);
45+
expect(pool.size()).toBe(1);
46+
expect(pool.used()).toBe(2);
4147
pool.release(object2);
4248
pool.purge();
43-
expect(pool.size()).toBe(1);
49+
expect(pool.size()).toBe(0);
50+
expect(pool.used()).toBe(0);
4451
pool.release(object3);
52+
expect(pool.size()).toBe(1);
53+
expect(pool.size()).toBe(1);
4554
pool.purge();
46-
expect(pool.size()).toBe(0);
4755
});
4856

4957
test("can pass arguments", () => {

packages/melonjs/src/system/pool.ts

+29-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export interface Pool<T, A extends unknown[]> {
33
release(object: T): void;
44
purge(): void;
55
size(): number;
6+
used(): number;
67
}
78

89
type Reset<A extends unknown[]> = ((...args: A) => void) | undefined;
@@ -16,38 +17,54 @@ export const createPool = <T, A extends unknown[]>(
1617
options: (...args: A) => CreatePoolOptions<T, A>,
1718
): Pool<T, A> => {
1819
const available: T[] = [];
19-
const inUse: T[] = [];
2020
const instanceResetMethods = new Map<T, Reset<A>>();
21+
let inUse: number = 0;
2122

2223
return {
23-
release: (object: T) => {
24-
const index = inUse.indexOf(object);
25-
if (index >= 0) {
26-
const [instance] = inUse.splice(index, 1);
27-
available.push(instance);
28-
} else {
29-
throw new Error("Trying to release an instance that is not in use.");
30-
}
24+
/**
25+
* release an object back to the pool
26+
* @param instance The object to release.
27+
*/
28+
release: (instance: T) => {
29+
available.push(instance);
30+
inUse--;
3131
},
32+
/**
33+
* get an instance from the pool
34+
* @param args The arguments for creating the instance.
35+
*/
3236
get: (...args) => {
3337
const object = available.pop();
3438
if (object) {
35-
inUse.push(object);
3639
const reset = instanceResetMethods.get(object);
3740
reset?.(...args);
41+
inUse++;
3842
return object;
3943
} else {
4044
const { instance, reset } = options(...args);
4145
instanceResetMethods.set(instance, reset);
42-
inUse.push(instance);
46+
inUse++;
4347
return instance;
4448
}
4549
},
50+
/**
51+
* purge the pool
52+
*/
4653
purge: () => {
4754
available.length = 0;
55+
inUse = 0;
4856
},
57+
/**
58+
* get the current size of the pool (how many objects are available)
59+
*/
4960
size: () => {
50-
return available.length + inUse.length;
61+
return available.length;
62+
},
63+
/**
64+
* get the number of objects currently in use
65+
*/
66+
used: () => {
67+
return inUse;
5168
},
5269
};
5370
};

0 commit comments

Comments
 (0)