Minecraft-Phantom-Panel/Utils/Phantom.Utils/Collections/TableData.cs

87 lines
2.6 KiB
C#

using System.Collections;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
namespace Phantom.Utils.Collections;
public sealed class TableData<TRow, TKey> : IReadOnlyList<TRow>, IReadOnlyDictionary<TKey, TRow> where TRow : notnull where TKey : notnull {
private readonly List<TRow> rowList = new ();
private readonly Dictionary<TKey, TRow> rowDictionary = new ();
public TRow this[int index] => rowList[index];
public TRow this[TKey key] => rowDictionary[key];
public IEnumerable<TKey> Keys => rowDictionary.Keys;
public IEnumerable<TRow> Values => rowDictionary.Values;
public bool IsEmpty => rowList.Count == 0;
public int Count => rowList.Count;
private void AddRowInternal(TKey key, TRow row) {
rowList.Add(row);
rowDictionary[key] = row;
}
private void UpdateRowInternal(TKey key, int rowIndex, TRow row) {
rowList[rowIndex] = row;
rowDictionary[key] = row;
}
public bool ContainsKey(TKey key) {
return rowDictionary.ContainsKey(key);
}
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TRow value) {
return rowDictionary.TryGetValue(key, out value);
}
public bool TryUpdateRow(TKey key, Func<TRow, TRow> updateRow) {
if (rowDictionary.TryGetValue(key, out var row)) {
int rowIndex = rowList.FindIndex(r => ReferenceEquals(r, row));
UpdateRowInternal(key, rowIndex, updateRow(row));
return true;
}
else {
return false;
}
}
public void UpdateFrom<TSource>(ImmutableArray<TSource> sourceItems, Func<TSource, TKey> getKey, Func<TSource, TRow> createRow, Func<TSource, TRow, TRow> updateRow) {
Dictionary<TRow, int> rowIndices = Enumerable.Range(0, rowList.Count).ToDictionary(i => rowList[i], static i => i, ReferenceEqualityComparer<TRow>.Instance);
HashSet<TKey> removedKeys = rowDictionary.Keys.ToHashSet();
foreach (var sourceItem in sourceItems) {
var key = getKey(sourceItem);
if (rowDictionary.TryGetValue(key, out var row)) {
UpdateRowInternal(key, rowIndices[row], updateRow(sourceItem, row));
removedKeys.Remove(key);
}
else {
AddRowInternal(key, createRow(sourceItem));
}
}
foreach (var key in removedKeys) {
var row = rowDictionary[key];
rowList.Remove(row);
rowDictionary.Remove(key);
}
}
public List<TRow>.Enumerator GetEnumerator() {
return rowList.GetEnumerator();
}
IEnumerator<TRow> IEnumerable<TRow>.GetEnumerator() {
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
IEnumerator<KeyValuePair<TKey, TRow>> IEnumerable<KeyValuePair<TKey, TRow>>.GetEnumerator() {
return rowDictionary.GetEnumerator();
}
}