using System.Reflection;
using System.Text;
namespace AxibugEmuOnline.Server
{
public static class ObjectPoolAuto
{
/************************************************************************************************************************/
///
/// 获取或者创建一个新的
///
/// Remember to 需要回收参见这个
public static T Acquire()
where T : class, new()
=> ObjectPool.Acquire();
///
/// 获取或者创建一个新的
///
/// Remember to 需要回收参见这个
public static void Acquire(out T item)
where T : class, new()
=> item = ObjectPool.Acquire();
/************************************************************************************************************************/
///
/// 回收对象
///
public static void Release(T item)
where T : class, new()
=> ObjectPool.Release(item);
///
/// 回收对象
///
public static void Release(ref T item) where T : class, new()
{
if (item != null)
{
ObjectPool.Release(item);
item = null;
}
}
/************************************************************************************************************************/
public const string
NotClearError = " They must be cleared before being released to the pool and not modified after that.";
/************************************************************************************************************************/
///
/// 获取或创建List
///
/// Remember to 回收参见此方法
public static List AcquireList()
{
var list = ObjectPool>.Acquire();
AppSrv.g_Log.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError);
return list;
}
///
/// 回收List
///
public static void Release(List list)
{
list.Clear();
ObjectPool>.Release(list);
}
/************************************************************************************************************************/
///
/// 获取或创建Queue
///
/// Remember to 回收参见此方法
public static Queue AcquireQueue()
{
var queue = ObjectPool>.Acquire();
AppSrv.g_Log.Assert(queue.Count == 0, "A pooled list is not empty." + NotClearError);
return queue;
}
///
/// 回收Queue
///
public static void Release(Queue list)
{
list.Clear();
ObjectPool>.Release(list);
}
/************************************************************************************************************************/
///
/// 获取或创建HashSet
///
public static HashSet AcquireSet()
{
var set = ObjectPool>.Acquire();
AppSrv.g_Log.Assert(set.Count == 0, "A pooled set is not empty." + NotClearError);
return set;
}
///
/// 释放HashSet
///
public static void Release(HashSet set)
{
set.Clear();
ObjectPool>.Release(set);
}
/************************************************************************************************************************/
///
/// 获取一个字符串StringBuilder
///
/// Remember to 回收参见这个
public static StringBuilder AcquireStringBuilder()
{
var builder = ObjectPool.Acquire();
AppSrv.g_Log.Assert(builder.Length == 0, $"A pooled {nameof(StringBuilder)} is not empty." + NotClearError);
return builder;
}
///
/// 回收 StringBuilder
///
public static void Release(StringBuilder builder)
{
builder.Length = 0;
ObjectPool.Release(builder);
}
///
/// 回收 StringBuilder
///
public static string ReleaseToString(this StringBuilder builder)
{
var result = builder.ToString();
Release(builder);
return result;
}
/************************************************************************************************************************/
private static class Cache
{
public static readonly Dictionary, T>>
Results = new Dictionary, T>>();
}
///
/// 此方法主要用于频繁绘制缓存,比如说GUI绘制
///
public static T GetCachedResult(Func function)
{
var method = function.Method;
if (!Cache.Results.TryGetValue(method, out var result))
{
result = new KeyValuePair, T>(function, function());
Cache.Results.Add(method, result);
}
else if (result.Key != function)
{
AppSrv.g_Log.Warning(
$"{nameof(GetCachedResult)}<{typeof(T).Name}>" +
$" was previously called on {method.Name} with a different target." +
" This likely means that a new delegate is being passed into every call" +
" so it can't actually return the same cached object.");
}
return result.Value;
}
/************************************************************************************************************************/
public static class Disposable
{
/************************************************************************************************************************/
///
/// Calls to get a spare if
///
public static IDisposable Acquire(out T item)
where T : class, new()
=> ObjectPool.Disposable.Acquire(out item);
/************************************************************************************************************************/
///
/// Calls to get a spare if
///
public static IDisposable AcquireList(out List list)
{
var disposable = ObjectPool>.Disposable.Acquire(out list, onRelease: (l) => l.Clear());
AppSrv.g_Log.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError);
return disposable;
}
/************************************************************************************************************************/
///
/// Calls to get a spare if
///
public static IDisposable AcquireSet(out HashSet set)
{
var disposable = ObjectPool>.Disposable.Acquire(out set, onRelease: (s) => s.Clear());
AppSrv.g_Log.Assert(set.Count == 0, "A pooled set is not empty." + NotClearError);
return disposable;
}
/************************************************************************************************************************/
}
/************************************************************************************************************************/
}
public static class ObjectPool where T : class, new()
{
/************************************************************************************************************************/
private static readonly List
Items = new List();
/************************************************************************************************************************/
/// The number of spare items currently in the pool.
public static int Count
{
get => Items.Count;
set
{
var count = Items.Count;
if (count < value)
{
if (Items.Capacity < value)
Items.Capacity = NextPowerOfTwo(value);
do
{
Items.Add(new T());
count++;
}
while (count < value);
}
else if (count > value)
{
Items.RemoveRange(value, count - value);
}
}
}
public static int NextPowerOfTwo(int value)
{
if (value <= 0)
{
throw new ArgumentException("Value must be greater than zero.");
}
int powerOfTwo = 1;
while (powerOfTwo < value)
{
powerOfTwo <<= 1; // equivalent to multiplying by 2
}
return powerOfTwo;
}
/************************************************************************************************************************/
///
/// If the is less than the specified value, this method increases it to that value by
/// creating new objects.
///
public static void SetMinCount(int count)
{
if (Count < count)
Count = count;
}
/************************************************************************************************************************/
/// The of the internal list of spare items.
public static int Capacity
{
get => Items.Capacity;
set
{
if (Items.Count > value)
Items.RemoveRange(value, Items.Count - value);
Items.Capacity = value;
}
}
/************************************************************************************************************************/
/// Returns a spare item if there are any, or creates a new one.
/// Remember to it when you are done.
public static T Acquire()
{
var count = Items.Count;
if (count == 0)
{
return new T();
}
else
{
count--;
var item = Items[count];
Items.RemoveAt(count);
return item;
}
}
/************************************************************************************************************************/
/// Adds the `item` to the list of spares so it can be reused.
public static void Release(T item)
{
Items.Add(item);
}
/************************************************************************************************************************/
/// Returns a description of the state of this pool.
public static string GetDetails()
{
return
$"{typeof(T).Name}" +
$" ({nameof(Count)} = {Items.Count}" +
$", {nameof(Capacity)} = {Items.Capacity}" +
")";
}
/************************************************************************************************************************/
///
/// An system to allow pooled objects to be acquired and released within using
/// statements instead of needing to manually release everything.
///
public sealed class Disposable : IDisposable
{
/************************************************************************************************************************/
private static readonly List LazyStack = new List();
private static int _ActiveDisposables;
private T _Item;
private Action _OnRelease;
/************************************************************************************************************************/
private Disposable() { }
///
/// Calls to set the `item` and returns an
/// that will call on the `item` when disposed.
///
public static IDisposable Acquire(out T item, Action onRelease = null)
{
Disposable disposable;
if (LazyStack.Count <= _ActiveDisposables)
{
LazyStack.Add(disposable = new Disposable());
}
else
{
disposable = LazyStack[_ActiveDisposables];
}
_ActiveDisposables++;
disposable._Item = item = ObjectPool.Acquire();
disposable._OnRelease = onRelease;
return disposable;
}
/************************************************************************************************************************/
void IDisposable.Dispose()
{
_OnRelease?.Invoke(_Item);
Release(_Item);
_ActiveDisposables--;
}
/************************************************************************************************************************/
}
}
}