diff --git a/source/MonoGame.Extended/Collections/IPoolable.cs b/source/MonoGame.Extended/Collections/IPoolable.cs index cba24b853..23caa37de 100644 --- a/source/MonoGame.Extended/Collections/IPoolable.cs +++ b/source/MonoGame.Extended/Collections/IPoolable.cs @@ -1,12 +1,12 @@ -namespace MonoGame.Extended.Collections -{ - public delegate void ReturnToPoolDelegate(IPoolable poolable); +using System; +namespace MonoGame.Extended.Collections +{ public interface IPoolable { IPoolable NextNode { get; set; } IPoolable PreviousNode { get; set; } - void Initialize(ReturnToPoolDelegate returnDelegate); + void Initialize(Action returnDelegate); void Return(); } -} \ No newline at end of file +} diff --git a/source/MonoGame.Extended/Collections/ObjectPool.cs b/source/MonoGame.Extended/Collections/ObjectPool.cs index 066fa9654..44dffe0e0 100644 --- a/source/MonoGame.Extended/Collections/ObjectPool.cs +++ b/source/MonoGame.Extended/Collections/ObjectPool.cs @@ -15,7 +15,7 @@ public enum ObjectPoolIsFullPolicy public class ObjectPool : IEnumerable where T : class, IPoolable { - private readonly ReturnToPoolDelegate _returnToPoolDelegate; + private readonly Action _returnToPoolDelegate; private readonly Deque _freeItems; // circular buffer for O(1) operations private T _headNode; // linked list for iteration @@ -144,7 +144,13 @@ private void Use(T item) { item.Initialize(_returnToPoolDelegate); item.NextNode = null; - if (item != _tailNode) + if(_tailNode is null) + { + _headNode = item; + _tailNode = item; + item.PreviousNode = null; + } + else { item.PreviousNode = _tailNode; _tailNode.NextNode = item; @@ -154,4 +160,4 @@ private void Use(T item) ItemUsed?.Invoke(item); } } -} \ No newline at end of file +} diff --git a/tests/MonoGame.Extended.Tests/Collections/ObjectPoolTests.cs b/tests/MonoGame.Extended.Tests/Collections/ObjectPoolTests.cs new file mode 100644 index 000000000..ed1a9e27f --- /dev/null +++ b/tests/MonoGame.Extended.Tests/Collections/ObjectPoolTests.cs @@ -0,0 +1,51 @@ +// Copyright (c) Craftwork Games. All rights reserved. +// Licensed under the MIT license. +// See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MonoGame.Extended.Collections; + +namespace MonoGame.Extended.Tests.Collections; + +public class ObjectPoolTests +{ + private class TestPoolable : IPoolable + { + public Action ReturnAction { get; private set; } + public IPoolable NextNode { get; set; } + public IPoolable PreviousNode { get; set; } + + public void Initialize(Action returnAction) + { + ReturnAction = returnAction; + } + + public void Return() + { + ReturnAction(this); + } + } + + [Fact] + public void ObjectPool_ThrowsNullReferenceException_WhenAllItemsReturnedAndNewCalled() + { + // Arrange + var pool = new ObjectPool(() => new TestPoolable(), 2); + + // Act & Assert + var item1 = pool.New(); + var item2 = pool.New(); + + // Return all items to the pool + item1.Return(); + item2.Return(); + + + var exception = Record.Exception(() => pool.New()); + Assert.Null(exception); + } +}