Question

I see the benefit of using object pooling, and I also want to combine it with Vectors. But, reading about Vectors, I see that they can only be defined at compile time, meaning a separate pooler class for each of the pooled classes is required. On the other hand, I would like to have a random class instance of a set (all extending a certain class) to be pulled from a pool at runtime, so that I don't exactly know which object pooler is to be called. And, in order to not multiply the code sequences for pooler classes, I want to combine all pools into a UniversalPooler class, which then can serve requests like var foo:SomeClass=UniversalPool.getFromPool(SomeClass);. The question is, how can I implement such a universal pooler performance effectively, using Vectors if at all possible, and probably using random subclass selection?

Was it helpful?

Solution

Yes, unfortunately it's not possible to use Vectors, AS3 has very poor implementation of generics. I use the following pooling based on class map Dictionary and Arrays for objects storage:

package util.pool
{
import flash.utils.Dictionary;

public class ObjectPool
{
    private var storage:Dictionary = new Dictionary();

    public function ObjectPool()
    {
    }

    private function createNew(constructor:Class, ...args):Object
    {
        //as3 - (facepalm), why there isn't API to path array of params to constructor
        switch (args.length) {
            case 0:return new constructor();
            case 1:return new constructor(args[0]);
            case 2:return new constructor(args[0], args[1]);
            case 3:return new constructor(args[0], args[1], args[2]);
            case 4:return new constructor(args[0], args[1], args[2], args[3]);
            case 5:return new constructor(args[0], args[1], args[2], args[3], args[4]);
            case 6:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5]);
            case 7:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
            case 8:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
            case 9:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
            case 10:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
            default: throw new Error("too much arguments for constructor, add more switch cases :))");
        }       
    }

    public function create(constructor:Class, ...args):Object
    {
        var pool:Array = getOrCreatePool(constructor);

        var res:*;
        if(pool.length > 0)
        {
            res = pool.pop();
        }else
        {
            args.unshift(constructor);
            res = createNew.apply(null, args);
        }

        return res;
    }

    public function destroy(obj:Object):void
    {
        if(!obj) return;
        if(!(obj is Object)) return;

        var constructor:Class = obj["constructor"];
        var pool:Array = getOrCreatePool(constructor);
        pool[pool.length] = obj;
    }

    public function destroyArr(objs:Object):void
    {
        for each(var obj:Object in objs)
            destroy(obj);
    }

    private function getOrCreatePool(constructor:Class):Array
    {
        var pool:Array = storage[constructor];
        if(!pool)
        {
            pool = [];
            storage[constructor] = pool;
        }

        return pool;
    }
}
}

It can be used as one global pool. And I don't think that there can be much more effective implementation, it's a quite simple feature in general.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top