Friday, August 17, 2012

New Poolean

Looking back to when I made my first "Pool" (called Poolean) and the reasons why I made it the way it was I came to realize I was trying to avoid using "List.Remove(T)" besides avoiding to create new elements every time something was needed.
Some time after that I stumbled upon a performance problem that was going to 
hinder my game if the number of elements to be managed was going to be big, let'ssay that a pool is used a lot, meaning that the elements within the pool are
almost always "In use" and often the pool requires to expand (create new elementsto accommodate demand). Following the way the pool used to work, I would have to check if the "next" element was free, and if it was not continue until I ran out of space, then I started back from 0 to right before the element I just used, andif nothing was available then expand the pool.
The problem with this is that if I want something that requires big numbers (likeparticles) it would get hairy real quick.
I was trying to make a class that could hold a collection of objects and be able to remove the objects without having to shift things around (like List.Remove(T) does) because once again that would be very slow, I came with the idea of removing the certain element and swapping the last element in the collection to the position of the element we just removed, putting the count down by one and that would be all, in order to do this, the object I wanted to use in this "Collection" would have to contain an interface that allows access to certain index number, just a simple property to know in which position the element is in the collection. This methodology could fix my Poolean issue, by knowing how many items are in the pool, and knowing I always remove the last one, this made the entire "Searching for the next element" completely obsolete, which made me happy, so now the new Poolean looks like this:    


public class Poolean<T> where T: new()
    {
        public T[] Pool;
        public int Size;
        public int GrowthAmount;
        public int CurrentFreeIndex;
        public Type TypeOfT;

        public Poolean(int size, int Growth)
        {
            CurrentFreeIndex = size - 1;
            GrowthAmount = Growth;
            TypeOfT = typeof(T);

            Pool = new T[size];

            Size = size;

            for (int i = 0; i < Size; i++)
            {
                T NewElement = (T)Activator.CreateInstance(TypeOfT);
                Pool[i] = NewElement;
            }
        }

        public void Get(out T Vessel)
        {
            if (CurrentFreeIndex > -1)
            {
                Vessel = (T)Pool[CurrentFreeIndex];
                Pool[CurrentFreeIndex] = default(T);
                CurrentFreeIndex--;
            }
            else
            {
                //Expand
                CurrentFreeIndex += GrowthAmount;
                Size += GrowthAmount;
                Pool = new T[Size];
                for (int i = 0; i < GrowthAmount; i++)
                {
                    T NewItem = (T)Activator.CreateInstance(TypeOfT);
                    Pool[i] = NewItem;
                }

                //try again
                Vessel = (T)Pool[CurrentFreeIndex];
                Pool[CurrentFreeIndex] = default(T);
                CurrentFreeIndex--;
            }
        }

        public void ReturnPoolable(T Poolable)
        {
            CurrentFreeIndex++;
            Pool[CurrentFreeIndex] = Poolable;
        }
    }


As you can see it is a lot shorted and easier to understand, let's go over the Constructor first, in the constructor you specify how many elements do you want in the pool to begin with and in the event that the pool runs out of space, how many elements you want to add, pretty simple, there we define what type T is and then we populate the array of Ts with objects of type T. Then we have the "Get" function which takes an element out of the pool if it has any left and if it doesn't it expands, and finally we have the "ReturnPoolable" which adds the element back to the pool and gets the count up by one.

This made the pool lightning faster, but I hope I come up with an idea to make it even faster.

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. if (CurrentFreeIndex < -1) needs to be reversed i.e if (CurrentFreeIndex > -1)

    ReplyDelete
    Replies
    1. That was an html typo, thanks for letting me know though =]

      Delete