fix: Updates container searches for non-generic types (#1567)
This commit is contained in:
parent
331f24cb71
commit
3109f59d4d
9 changed files with 248 additions and 175 deletions
|
|
@ -22,20 +22,17 @@ namespace Server.Items;
|
|||
|
||||
public partial class Container
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FindItemsByTypeEnumerator<Item> FindItems(bool recurse = true, Predicate<Item> predicate = null)
|
||||
=> FindItemsByType(recurse, predicate);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a breadth-first search through all the <see cref="Item" />s and
|
||||
/// nested <see cref="Container" />s within this <see cref="Container" />.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// DO NOT consume, delete, or move items while iterating
|
||||
/// DO NOT consume, delete, or move items while iterating with any FindItemByType or FindItems overloads
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// var total = 0;
|
||||
///
|
||||
/// foreach (var gold in cont.FindItemsByType<Gold>())
|
||||
/// {
|
||||
/// total += gold.Amount;
|
||||
|
|
@ -57,12 +54,20 @@ public partial class Container
|
|||
/// <paramref name="predicate" />.
|
||||
/// </returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FindItemsByTypeEnumerator<T> FindItemsByType<T>(bool recurse = true, Predicate<T> predicate = null)
|
||||
where T : Item => new(this, recurse, predicate);
|
||||
public FindItemsByTypeEnumerator<T> FindItemsByType<T>(bool recurse = true, Predicate<T> predicate = null) where T : Item =>
|
||||
new(this, recurse, predicate);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public QueuedItemsEnumerator<Item> EnumerateItems(bool recurse = true, Predicate<Item> predicate = null)
|
||||
=> EnumerateItemsByType(recurse, predicate);
|
||||
public FindItemsByTypeEnumerator<Item> FindItemsByType(Type type, bool recurse = true) =>
|
||||
new(this, recurse, type.IsInstanceOfType);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FindItemsByTypeEnumerator<Item> FindItemsByType(Type[] types, bool recurse = true) =>
|
||||
new(this, recurse, item => item.InTypeList(types));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FindItemsByTypeEnumerator<Item> FindItems(bool recurse = true, Predicate<Item> predicate = null) =>
|
||||
new(this, recurse, predicate);
|
||||
|
||||
/// <summary>
|
||||
/// Safely enumerates items using a breadth-first search through all the <see cref="Item" />s and
|
||||
|
|
@ -70,7 +75,8 @@ public partial class Container
|
|||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use EnumerateItemsByType for situations where the item might be manipulated, consumed, or moved.
|
||||
/// Note: This method scans through the container before returning the enumerator for iteration.
|
||||
/// Note: This method scans through the container before returning the enumerator for iteration and therefore
|
||||
/// incurs a performance penalty from the overhead.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
|
|
@ -98,16 +104,10 @@ public partial class Container
|
|||
/// <paramref name="predicate" />.
|
||||
/// </returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public QueuedItemsEnumerator<T> EnumerateItemsByType<T>(bool recurse = true, Predicate<T> predicate = null)
|
||||
where T : Item => new(QueueItemsByType(recurse, predicate));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PooledRefQueue<Item> QueueItems(bool recurse = true, Predicate<Item> predicate = null) =>
|
||||
QueueItemsByType(recurse, predicate);
|
||||
|
||||
public PooledRefQueue<T> QueueItemsByType<T>(bool recurse = true, Predicate<T> predicate = null) where T : Item
|
||||
public PooledRefQueue<T> EnumerateItemsByType<T>(bool recurse = true, Predicate<T> predicate = null) where T : Item
|
||||
{
|
||||
var queue = PooledRefQueue<T>.Create();
|
||||
var queue = PooledRefQueue<T>.Create(128);
|
||||
|
||||
foreach (var item in FindItemsByType(recurse, predicate))
|
||||
{
|
||||
queue.Enqueue(item);
|
||||
|
|
@ -117,12 +117,45 @@ public partial class Container
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PooledRefList<Item> ListItems(bool recurse = true, Predicate<Item> predicate = null) =>
|
||||
ListItemsByType(recurse, predicate);
|
||||
public PooledRefQueue<Item> EnumerateItemsByType(Type type, bool recurse = true)
|
||||
{
|
||||
var queue = PooledRefQueue<Item>.Create(128);
|
||||
|
||||
foreach (var item in FindItemsByType<Item>(recurse))
|
||||
{
|
||||
if (type.IsInstanceOfType(item))
|
||||
{
|
||||
queue.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PooledRefQueue<Item> EnumerateItemsByType(Type[] types, bool recurse = true)
|
||||
{
|
||||
var queue = PooledRefQueue<Item>.Create(128);
|
||||
|
||||
foreach (var item in FindItemsByType<Item>(recurse))
|
||||
{
|
||||
if (item.InTypeList(types))
|
||||
{
|
||||
queue.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PooledRefQueue<Item> EnumerateItems(bool recurse = true, Predicate<Item> predicate = null) =>
|
||||
EnumerateItemsByType(recurse, predicate);
|
||||
|
||||
public PooledRefList<T> ListItemsByType<T>(bool recurse = true, Predicate<T> predicate = null) where T : Item
|
||||
{
|
||||
var list = PooledRefList<T>.Create();
|
||||
var list = PooledRefList<T>.Create(128);
|
||||
|
||||
foreach (var item in FindItemsByType(recurse, predicate))
|
||||
{
|
||||
list.Add(item);
|
||||
|
|
@ -131,22 +164,69 @@ public partial class Container
|
|||
return list;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PooledRefList<Item> ListItemsByType(Type type, bool recurse = true)
|
||||
{
|
||||
var list = PooledRefList<Item>.Create(128);
|
||||
|
||||
foreach (var item in FindItemsByType<Item>(recurse))
|
||||
{
|
||||
if (type.IsInstanceOfType(item))
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PooledRefList<Item> ListItemsByType(Type[] types, bool recurse = true)
|
||||
{
|
||||
var list = PooledRefList<Item>.Create(128);
|
||||
|
||||
foreach (var item in FindItemsByType<Item>(recurse))
|
||||
{
|
||||
if (item.InTypeList(types))
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PooledRefList<Item> ListItems(bool recurse = true, Predicate<Item> predicate = null) =>
|
||||
ListItemsByType(recurse, predicate);
|
||||
|
||||
public ref struct FindItemsByTypeEnumerator<T> where T : Item
|
||||
{
|
||||
private const string InvalidOperation_EnumFailedVersion =
|
||||
"Container was modified after enumerator was instantiated. Use Container.EnumerateItems method instead for safe enumerations.";
|
||||
|
||||
private PooledRefQueue<Container> _containers;
|
||||
private Span<Item> _items;
|
||||
private int _index;
|
||||
private T _current;
|
||||
private bool _recurse;
|
||||
private Predicate<T> _predicate;
|
||||
private readonly bool _recurse;
|
||||
private readonly Predicate<T> _predicate;
|
||||
private Container _currentContainer;
|
||||
private int _version;
|
||||
|
||||
public FindItemsByTypeEnumerator(Container container, bool recurse, Predicate<T> predicate)
|
||||
{
|
||||
_containers = PooledRefQueue<Container>.Create();
|
||||
_containers = PooledRefQueue<Container>.Create(_recurse ? 64 : 0);
|
||||
|
||||
if (container?.m_Items != null)
|
||||
if (container != null)
|
||||
{
|
||||
_items = CollectionsMarshal.AsSpan(container.m_Items);
|
||||
if (container.m_Items != null)
|
||||
{
|
||||
_items = CollectionsMarshal.AsSpan(container.m_Items);
|
||||
}
|
||||
|
||||
_currentContainer = container;
|
||||
_version = container._version;
|
||||
}
|
||||
|
||||
_current = default;
|
||||
|
|
@ -163,8 +243,11 @@ public partial class Container
|
|||
{
|
||||
while (_containers.TryDequeue(out var c))
|
||||
{
|
||||
_currentContainer = c;
|
||||
_items = CollectionsMarshal.AsSpan(c.m_Items);
|
||||
_index = 0;
|
||||
_version = c._version;
|
||||
|
||||
if (SetNextItem())
|
||||
{
|
||||
return true;
|
||||
|
|
@ -177,6 +260,11 @@ public partial class Container
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool SetNextItem()
|
||||
{
|
||||
if (_version != _currentContainer._version)
|
||||
{
|
||||
throw new InvalidOperationException(InvalidOperation_EnumFailedVersion);
|
||||
}
|
||||
|
||||
while (_index < _items.Length)
|
||||
{
|
||||
Item item = _items[_index++];
|
||||
|
|
@ -187,6 +275,11 @@ public partial class Container
|
|||
|
||||
if (item is T t && _predicate?.Invoke(t) != false)
|
||||
{
|
||||
if (_version != _currentContainer._version)
|
||||
{
|
||||
throw new InvalidOperationException(InvalidOperation_EnumFailedVersion);
|
||||
}
|
||||
|
||||
_current = t;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -207,40 +300,4 @@ public partial class Container
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FindItemsByTypeEnumerator<T> GetEnumerator() => this;
|
||||
}
|
||||
|
||||
public ref struct QueuedItemsEnumerator<T> where T : Item
|
||||
{
|
||||
private PooledRefQueue<T> _queue;
|
||||
private T _current;
|
||||
|
||||
public QueuedItemsEnumerator(PooledRefQueue<T> queue)
|
||||
{
|
||||
_queue = queue;
|
||||
_current = default;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_queue.TryDequeue(out var item))
|
||||
{
|
||||
_current = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public T Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose() => _queue.Dispose();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public QueuedItemsEnumerator<T> GetEnumerator() => this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue