Skip to content

Instantly share code, notes, and snippets.

@guFalcon
Last active September 13, 2016 19:39
Show Gist options
  • Save guFalcon/39a24c1c0bba644a2ba3e03f53601632 to your computer and use it in GitHub Desktop.
Save guFalcon/39a24c1c0bba644a2ba3e03f53601632 to your computer and use it in GitHub Desktop.
This class allows pooling with on-demand generation of objects without restrictions on the constructor.

Description

This class allows pooling with on-demand generation of objects without restrictions on the constructor. The objects you want to pool could have a non-argument constructor or not. The exposed events allow you to react on actions within the pool like when somebody is returning an element, if a new one is constructed or if an old one is handed out again.

Usage

// Member variable:
LockFreePool<AttackSprite> attackPool;

// In the constructor:
attackPool = new LockFreePool<AttackSprite>(new object[] {
                                                spriteBatch, game, tokens.AttackSpriteToken,
							                                  new Vector2(-1000f, -1000f), string.Empty});
// Or, if an empty-parameter constructor exists for the AttackSprite:
attackPool = new LockFreePool<AttackSprite>();
							                                  
// Somewhere in the program:
AttackSprite s = attackPool.Get();
//... then do something with the sprite...

// Somewhere else in the program:
attackPool.Return(s);
// ***************************************************************************
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
// ***************************************************************************
using System;
using System.Collections.Concurrent;
using JetBrains.Annotations;
namespace Utilities.Pooling
{
[PublicAPI]
public class PoolEventArgs<T> : EventArgs
{
public T Object { get; set; }
public PoolEventArgs(T createdObject)
{
Object = createdObject;
}
}
/// <summary>
/// This class is a lock-free pool implementation.
/// </summary>
/// <typeparam name="T"></typeparam>
[PublicAPI]
public class LockFreePool<T> where T : class, LockFreePoolItem
{
public long CreationCount { get; set; }
public event EventHandler<PoolEventArgs<T>> Created;
public event EventHandler<PoolEventArgs<T>> Reused;
public event EventHandler<PoolEventArgs<T>> Returned;
private readonly ConcurrentQueue<T> pool = new ConcurrentQueue<T>();
private readonly object[] constructorParameters;
public LockFreePool()
{
constructorParameters = new object[] {};
}
/// <summary>
/// Initializes a new instance of the <see cref="LockFreePool{T}" /> class.
/// </summary>
/// <param name="constructorParameters">The constructor parameters of the to-be-constructed pool-items.</param>
public LockFreePool(object[] constructorParameters)
{
this.constructorParameters = constructorParameters;
}
/// <summary>
/// Gets the next item from the pool or constructs one if the pool is empty.
/// </summary>
/// <returns>An Item.</returns>
public T Get()
{
T result;
if (!pool.TryDequeue(out result))
{
// The queue was empty. Construct new T.
result = (T) Activator.CreateInstance(typeof(T), constructorParameters);
Created?.Invoke(this, new PoolEventArgs<T>(result));
CreationCount++;
}
else
{
Reused?.Invoke(this, new PoolEventArgs<T>(result));
}
return result;
}
/// <summary>
/// Return an item back to the pool.
/// </summary>
/// <param name="item">The item to return</param>
/// <returns>This instance in order to support a fluent interface.</returns>
public LockFreePool<T> Return(T item)
{
item.Reset();
pool.Enqueue(item);
Returned?.Invoke(this, new PoolEventArgs<T>(item));
return this;
}
/// <summary>
/// Gets the number of currently enqueued items.
/// </summary>
/// <returns>A number.</returns>
public int Count()
{
return pool.Count;
}
/// <summary>
/// Clears this instance.
/// </summary>
/// <returns>This instance in order to support a fluent interface.</returns>
public LockFreePool<T> Clear()
{
pool.Clear();
return this;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment