mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
* feat: new method or aggregating multiple config changed subscriptions into one disposable object or more slim unsubscribing code * refactor: moved nested private class declaration to bottom of class * refactor: reusing stateful object in tests is not smart * fix: invalid code for forming new array during InvokeList.Remove call * refactor: extracted new sub-multiple builder into configuration manager extensions * refactor: remove unused code * refactor: removed UnSubscribeActionsDelegates * refactor: whitespaces and renaming --------- Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
119 lines
3.3 KiB
C#
119 lines
3.3 KiB
C#
using System;
|
|
|
|
namespace Robust.Shared.Collections;
|
|
|
|
/// <summary>
|
|
/// Alternative to multi-cast delegates that has separate equality keys.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of delegate to store.</typeparam>
|
|
/// <remarks>
|
|
/// While this type is immutable (via copies), creating a copy (via add or remove) is not currently thread safe.
|
|
/// This is in contrast to multi-cast delegate.
|
|
/// </remarks>
|
|
internal struct InvokeList<T>
|
|
{
|
|
private Entry[]? _entries;
|
|
|
|
public int Count => _entries?.Length ?? 0;
|
|
|
|
/// <summary>
|
|
/// Add an entry to the current invoke list, mutating it.
|
|
/// </summary>
|
|
/// <param name="value">Actual value to store.</param>
|
|
/// <param name="equality">Equality comparison key.</param>
|
|
public void AddInPlace(T value, object equality)
|
|
{
|
|
this = Add(value, equality);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an entry to the invoke list, returning a new instance. The original list is not modified.
|
|
/// </summary>
|
|
/// <param name="value">Actual value to store.</param>
|
|
/// <param name="equality">Equality comparison key.</param>
|
|
public readonly InvokeList<T> Add(T value, object equality)
|
|
{
|
|
if (_entries == null)
|
|
{
|
|
return new InvokeList<T>
|
|
{
|
|
_entries = new[]
|
|
{
|
|
new Entry { Value = value, Equality = equality }
|
|
}
|
|
};
|
|
}
|
|
|
|
var arr = _entries;
|
|
Array.Resize(ref arr, arr.Length + 1);
|
|
arr[^1] = new Entry { Value = value, Equality = equality };
|
|
|
|
return new InvokeList<T>
|
|
{
|
|
_entries = arr
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove an entry from the current invoke list, mutating it.
|
|
/// </summary>
|
|
/// <param name="equality">Equality comparison key.</param>
|
|
public void RemoveInPlace(object equality)
|
|
{
|
|
this = Remove(equality);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove an entry from the invoke list, returning a new instance. The original list is not modified.
|
|
/// </summary>
|
|
/// <param name="equality">Equality comparison key.</param>
|
|
public readonly InvokeList<T> Remove(object equality)
|
|
{
|
|
if (_entries == null)
|
|
return this;
|
|
|
|
// Find if we even have this key in the list.
|
|
var entryIdx = -1;
|
|
for (var i = 0; i < _entries.Length; i++)
|
|
{
|
|
var entry = _entries[i];
|
|
if (equality.Equals(entry.Equality))
|
|
{
|
|
entryIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Entry not in the list, copy is identical.
|
|
if (entryIdx < 0)
|
|
return this;
|
|
|
|
// Would remove the last element from the array, new instance is empty.
|
|
if (_entries.Length == 1)
|
|
return default;
|
|
|
|
// Create new backing array and copy stuff into it.
|
|
var newEntries = new Entry[_entries.Length - 1];
|
|
for (int srcIdx = 0, dstIdx = 0; dstIdx < newEntries.Length; srcIdx++, dstIdx++)
|
|
{
|
|
if (srcIdx == entryIdx)
|
|
srcIdx++;
|
|
|
|
newEntries[dstIdx] = _entries[srcIdx];
|
|
}
|
|
|
|
return new InvokeList<T>
|
|
{
|
|
_entries = newEntries
|
|
};
|
|
}
|
|
|
|
public ReadOnlySpan<Entry> Entries => _entries;
|
|
|
|
public struct Entry
|
|
{
|
|
public T? Value;
|
|
public object? Equality;
|
|
}
|
|
}
|