using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
namespace UnityGameEngine.Utilities
{
public class ObjectPoolWithConstructorInternal<T>
{
public int ObjectsCreated { get; internal set; }
public int InUse { get; internal set; }
public int Available { get { return ObjectsCreated - InUse; } }
private Type objectType;
private ConstructorInfo constructor;
private int numConstructorArgs = 0;
private Queue<T> availableQueue = new Queue<T>();
private HashSet<T> availableObjects = new HashSet<T>();
public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams)
{
this.objectType = objectType;
ConstructorInfo constructor = objectType.GetConstructor(constructorParams);
if (!typeof(T).IsAssignableFrom(objectType))
{
Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name);
}
else if (constructor == null)
{
string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params (";
err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!";
Debug.LogError(err);
}
else
{
this.constructor = constructor;
numConstructorArgs = constructorParams.Length;
}
}
public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { }
protected bool HasAvailableObject { get { return availableObjects.Count > 0; } }
protected T GetObjectIfAvailable()
{
InUse++;
if (availableObjects.Count > 0)
{
T obj = availableQueue.Dequeue();
while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue();
return obj;
}
return default(T);
}
protected T GetNewObject(object[] constructorArgs)
{
ObjectsCreated++;
InUse++;
if (constructorArgs.Length != numConstructorArgs)
{
Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!");
return default(T);
}
bool valid = true;
object obj = null;
if (constructor == null) return default(T);
try
{
obj = constructor.Invoke(constructorArgs);
if (!(obj is T))
{
valid = false;
}
} catch (Exception e)
{
valid = false;
}
if (!valid)
{
Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!");
return default(T);
}
return (T)obj;
}
public void ReturnObject(T obj)
{
if (!availableObjects.Contains(obj))
{
availableQueue.Enqueue(obj);
availableObjects.Add(obj);
InUse--;
}
}
public int AvailableObjectsRemoved { get; private set; }
public T RemoveAvailable()
{
if (availableObjects.Count > 0)
{
T obj = availableQueue.Dequeue();
while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue();
ObjectsCreated--;
AvailableObjectsRemoved++;
return obj;
}
return default(T);
}
public void RemoveAvailable(T obj)
{
if (availableObjects.Contains(obj))
{
availableObjects.Remove(obj);
ObjectsCreated--;
AvailableObjectsRemoved++;
}
}
}
public abstract class ObjectPoolBase<T>
{
public int ObjectsCreated { get; internal set; }
public int InUse { get; internal set; }
public int Available { get { return ObjectsCreated - InUse; } }
private Queue<T> availableQueue = new Queue<T>();
private HashSet<T> availableObjects = new HashSet<T>();
private ConstructorInfo constructor;
public ObjectPoolBase(Type newType = null)
{
if (newType != null)
{
constructor = newType.GetConstructor(Type.EmptyTypes);
}
}
protected abstract T CreateNewObject();
public T GetNextObject()
{
InUse++;
T obj = default(T);
if (availableObjects.Count > 0)
{
obj = availableQueue.Dequeue();
while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue();
}
else
{
ObjectsCreated++;
obj = CreateNewObject();
}
return obj;
}
public void ReturnObject(T obj)
{
if (!availableObjects.Contains(obj))
{
InUse--;
availableObjects.Add(obj);
availableQueue.Enqueue(obj);
}
}
public void ReturnObject(object obj)
{
if (obj is T)
{
if (!availableObjects.Contains((T)obj))
{
InUse--;
availableObjects.Add((T)obj);
availableQueue.Enqueue((T)obj);
}
}
}
public int AvailableObjectsRemoved { get; private set; }
public T RemoveAvailable()
{
if (availableObjects.Count > 0)
{
T obj = availableQueue.Dequeue();
while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue();
ObjectsCreated--;
AvailableObjectsRemoved++;
return obj;
}
return default(T);
}
public void RemoveAvailable(T obj)
{
if (availableObjects.Contains(obj))
{
availableObjects.Remove(obj);
ObjectsCreated--;
AvailableObjectsRemoved++;
}
}
}
public class ObjectPool<T> : ObjectPoolBase<T> where T : new()
{
protected override T CreateNewObject()
{
return new T();
}
}
public class ObjectPoolBaseType<T> : ObjectPoolBase<T>
{
private ConstructorInfo constructor;
public ObjectPoolBaseType(Type type)
{
constructor = type.GetConstructor(Type.EmptyTypes);
}
protected override T CreateNewObject()
{
return (T)constructor.Invoke(null);
}
}
public class ObjectPool<T, TConstructArg1> : ObjectPoolWithConstructorInternal<T>
{
public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { }
public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { }
public T GetNextObject(TConstructArg1 arg1)
{
if (HasAvailableObject)
{
return GetObjectIfAvailable();
}
return GetNewObject(new object[] { arg1 });
}
}
public class ObjectPool<T, TConstructArg1, TConstructArg2> : ObjectPoolWithConstructorInternal<T>
{
public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { }
public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { }
public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2)
{
if (HasAvailableObject)
{
return GetObjectIfAvailable();
}
return GetNewObject(new object[] { arg1, arg2 });
}
}
public class ObjectPool<T, TConstructArg1, TConstructArg2, TConstructArg3> : ObjectPoolWithConstructorInternal<T>
{
public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { }
public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { }
public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3)
{
if (HasAvailableObject)
{
return GetObjectIfAvailable();
}
return GetNewObject(new object[] { arg1, arg2, arg3 });
}
}
}