You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.9 KiB

// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2017 Intel Corporation. All Rights Reserved.
namespace Intel.RealSense
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using ObjectFactory = System.Func<System.IntPtr, object>;
using PooledStack = System.Collections.Generic.Stack<Base.PooledObject>;
/// <summary>
/// Object pool to reuse objects, avoids allocation and GC pauses
/// </summary>
public static class ObjectPool
{
private static readonly Dictionary<Type, PooledStack> Pools = new Dictionary<Type, PooledStack>(TypeComparer.Default);
private static readonly Dictionary<Type, ObjectFactory> Factories = new Dictionary<Type, ObjectFactory>(TypeComparer.Default);
private class TypeComparer : IEqualityComparer<Type>
{
public static readonly TypeComparer Default = new TypeComparer();
public bool Equals(Type x, Type y)
{
return x == y;
}
public int GetHashCode(Type obj)
{
return obj.GetHashCode();
}
}
private static PooledStack GetPool(Type t)
{
Stack<Base.PooledObject> s;
if (Pools.TryGetValue(t, out s))
{
return s;
}
lock ((Pools as ICollection).SyncRoot)
{
return Pools[t] = new PooledStack();
}
}
private static object CreateInstance(Type t, IntPtr ptr)
{
Func<IntPtr, object> factory;
if (Factories.TryGetValue(t, out factory))
{
return factory(ptr);
}
var ctorinfo = t.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance,
null,
new Type[] { typeof(IntPtr) },
null);
var args = new ParameterExpression[] { Expression.Parameter(typeof(IntPtr), "ptr") };
var lambda = Expression.Lambda<ObjectFactory>(Expression.New(ctorinfo, args), args).Compile();
lock ((Factories as ICollection).SyncRoot)
{
Factories[t] = lambda;
}
return lambda(ptr);
}
private static object Get(Type t, IntPtr ptr)
{
var stack = GetPool(t);
lock ((stack as ICollection).SyncRoot)
{
if (stack.Count > 0)
{
Base.PooledObject obj;
obj = stack.Pop();
obj.m_instance.Reset(ptr);
obj.Initialize();
return obj;
}
}
return CreateInstance(t, ptr);
}
/// <summary>
/// Get an object from the pool, should be released back
/// </summary>
/// <typeparam name="T">type of object</typeparam>
/// <param name="ptr">native handle</param>
/// <returns>an object of type <typeparamref name="T"/></returns>
public static T Get<T>(IntPtr ptr)
where T : Base.PooledObject
{
if (ptr == IntPtr.Zero)
{
throw new ArgumentNullException(nameof(ptr));
}
return Get(typeof(T), ptr) as T;
}
/// <summary>
/// Return an object to the pool
/// </summary>
/// <typeparam name="T">type of object</typeparam>
/// <param name="obj">object to return to pool</param>
public static void Release<T>(T obj)
where T : Base.PooledObject
{
var stack = GetPool(obj.GetType());
lock ((stack as ICollection).SyncRoot)
{
stack.Push(obj);
}
}
}
}