diff --git a/src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs b/src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs new file mode 100644 index 0000000..623ae31 --- /dev/null +++ b/src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs @@ -0,0 +1,141 @@ +// File name: PooledObjectBuffer.cs +// +// Author(s): Alessio Parma +// +// The MIT License (MIT) +// +// Copyright (c) 2013-2018 Alessio Parma +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +// associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, +// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// 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 OR COPYRIGHT HOLDERS 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. + +using System; +using System.Collections.Generic; +using System.Threading; + +namespace CodeProject.ObjectPool.Core +{ + /// + /// A buffer into which pooled objects are stored. This buffer mostly behaves like a queue, + /// even if that behaviour is not stricly respected in order to maximize performance. + /// + /// + /// The type of the object that which will be managed by the pool. The pooled object have to be + /// a sub-class of PooledObject. + /// + public sealed class PooledObjectBuffer + where T : PooledObject + { + /// + /// The concurrent buffer containing pooled objects. + /// + private T[] _pooledObjects; + + public int Capacity => _pooledObjects.Length; + + public int Count + { + get + { + var count = 0; + for (var i = 0; i < _pooledObjects.Length; ++i) + { + if (_pooledObjects[i] != null) + { + count++; + } + } + return count; + } + } + + /// + /// All objects currently stored inside the pool. + /// + protected IEnumerable PooledObjects + { + get + { + for (var i = 0; i <= _pooledObjects.Length; ++i) + { + var item = _pooledObjects[i]; + if (item != null) + { + yield return item; + } + } + } + } + + public bool TryDequeue(out T pooledObject) + { + for (var i = 0; i < _pooledObjects.Length; i++) + { + var item = _pooledObjects[i]; + if (item != null && Interlocked.CompareExchange(ref _pooledObjects[i], null, item) == item) + { + pooledObject = item; + return true; + } + } + pooledObject = null; + return false; + } + + public bool TryEnqueue(T pooledObject) + { + for (var i = 0; i < _pooledObjects.Length; i++) + { + ref var item = ref _pooledObjects[i]; + if (item == null && Interlocked.CompareExchange(ref item, pooledObject, null) == null) + { + return true; + } + } + return false; + } + + public void ResizeBuffer(int newSize) + { + if (_pooledObjects == null) + { + _pooledObjects = new T[newSize]; + return; + } + + var currentSize = _pooledObjects.Length; + if (currentSize == newSize) + { + // Nothing to do. + return; + } + + if (currentSize > newSize) + { + for (var i = newSize; i < currentSize; ++i) + { + ref var item = ref _pooledObjects[i]; + if (item != null) + { + item.Dispose(); + item = null; + } + } + } + + Array.Resize(ref _pooledObjects, newSize); + } + } +} \ No newline at end of file diff --git a/src/CodeProject.ObjectPool/ObjectPool.cs b/src/CodeProject.ObjectPool/ObjectPool.cs index 014be3f..c07a8ef 100644 --- a/src/CodeProject.ObjectPool/ObjectPool.cs +++ b/src/CodeProject.ObjectPool/ObjectPool.cs @@ -11,7 +11,6 @@ using CodeProject.ObjectPool.Core; using PommaLabs.Thrower; using System; -using System.Collections.Generic; using System.Linq; using System.Threading; @@ -60,21 +59,26 @@ public int MaximumPoolSize { get { - return _pooledObjects.Length; + return _pooledObjects.Capacity; } set { // Preconditions Raise.ArgumentOutOfRangeException.If(value < 1, nameof(value), ErrorMessages.NegativeOrZeroMaximumPoolSize); - ResizeBuffer(value); + _pooledObjects.ResizeBuffer(value); } } /// /// Gets the count of the objects currently in the pool. /// - public int ObjectsInPoolCount => _pooledObjects.Count(x => x != null); + public int ObjectsInPoolCount => _pooledObjects.Count; + + /// + /// The concurrent buffer containing pooled objects. + /// + protected PooledObjectBuffer _pooledObjects { get; } = new PooledObjectBuffer(); #endregion Public Properties @@ -140,7 +144,7 @@ public ObjectPool(int maximumPoolSize, Func factoryMethod) ~ObjectPool() { // The pool is going down, releasing the resources for all objects in pool. - ClearBuffer(); + Clear(); } #endregion Finalizer @@ -153,7 +157,10 @@ public ObjectPool(int maximumPoolSize, Func factoryMethod) public void Clear() { // Destroy all objects. - ClearBuffer(); + while (_pooledObjects.TryDequeue(out T dequeuedObjectToDestroy)) + { + DestroyPooledObject(dequeuedObjectToDestroy); + } } /// @@ -162,7 +169,7 @@ public void Clear() /// A monitored object from the pool. public T GetObject() { - if (TryDequeue(out T pooledObject)) + if (_pooledObjects.TryDequeue(out T pooledObject)) { // Object found in pool. if (Diagnostics.Enabled) @@ -217,7 +224,7 @@ void IObjectPoolHandle.ReturnObjectToPool(PooledObject objectToReturnToPool, boo } // Trying to add the object back to the pool. - if (TryEnqueue(returnedObject)) + if (_pooledObjects.TryEnqueue(returnedObject)) { if (Diagnostics.Enabled) { @@ -241,108 +248,6 @@ void IObjectPoolHandle.ReturnObjectToPool(PooledObject objectToReturnToPool, boo #endregion Pool Operations - #region Extensibility - - /// - /// All objects currently stored inside the pool. - /// - protected IEnumerable PooledObjects - { - get - { - for (var i = 0; i <= _pooledObjects.Length; ++i) - { - var item = _pooledObjects[i]; - if (item != null) - { - yield return item; - } - } - } - } - - #endregion Extensibility - - #region Low-level Pooling - - /// - /// The concurrent buffer containing pooled objects. - /// - private T[] _pooledObjects; - - private void ClearBuffer() - { - if (_pooledObjects == null) - { - return; - } - while (TryDequeue(out T dequeuedObjectToDestroy)) - { - DestroyPooledObject(dequeuedObjectToDestroy); - } - } - - private bool TryDequeue(out T pooledObject) - { - for (var i = 0; i < _pooledObjects.Length; i++) - { - var item = _pooledObjects[i]; - if (item != null && Interlocked.CompareExchange(ref _pooledObjects[i], null, item) == item) - { - pooledObject = item; - return true; - } - } - pooledObject = null; - return false; - } - - private bool TryEnqueue(T pooledObject) - { - for (var i = 0; i < _pooledObjects.Length; i++) - { - ref var item = ref _pooledObjects[i]; - if (item == null && Interlocked.CompareExchange(ref item, pooledObject, null) == null) - { - return true; - } - } - return false; - } - - private void ResizeBuffer(int newSize) - { - if (_pooledObjects == null) - { - _pooledObjects = new T[newSize]; - return; - } - - var currentSize = _pooledObjects.Length; - if (currentSize == newSize) - { - // Nothing to do. - return; - } - - if (currentSize > newSize) - { - for (var i = newSize; i < currentSize; ++i) - { - ref var item = ref _pooledObjects[i]; - if (item != null) - { - item.Dispose(); - item = null; - } - } - } - - Array.Resize(ref _pooledObjects, newSize); - } - - #endregion Low-level Pooling - #region Private Methods /// diff --git a/test/CodeProject.ObjectPool.Examples/Customizations/TimedObjectPool.cs b/test/CodeProject.ObjectPool.Examples/Customizations/TimedObjectPool.cs new file mode 100644 index 0000000..92dfa6e --- /dev/null +++ b/test/CodeProject.ObjectPool.Examples/Customizations/TimedObjectPool.cs @@ -0,0 +1,29 @@ +// File name: TimedObjectPool.cs +// +// Author(s): Alessio Parma +// +// The MIT License (MIT) +// +// Copyright (c) 2013-2018 Alessio Parma +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +// associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, +// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// 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 OR COPYRIGHT HOLDERS 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. + +namespace CodeProject.ObjectPool.Examples.Customizations +{ + internal class TimedObjectPool + { + } +} \ No newline at end of file