perf: significant performance optimizations on ordered behaviour collectors by using a sorted dictionary

This commit is contained in:
2025-10-13 09:58:58 +03:00
parent 9ccf7b754d
commit c7d170fad9
9 changed files with 152 additions and 141 deletions

View File

@@ -3,77 +3,61 @@ using System.Collections.Generic;
namespace Engine.Core;
public class ActiveBehaviourCollectorOrdered<T> : ActiveBehaviourCollector<T> where T : class, IBehaviour
public class ActiveBehaviourCollectorOrdered<TIndex, TItem> : ActiveBehaviourCollector<TItem> where TItem : class, IBehaviour where TIndex : IComparable
{
private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
private readonly LinkedList<T> behaviours = new();
private readonly List<T> sortList = [];
private readonly SortedDictionary<TIndex, FastList<TItem>> behaviours = null!;
private IComparer<T>? _sortBy = null;
public IComparer<T>? SortBy
{
get => _sortBy;
set
{
_sortBy = value;
private readonly Func<TItem, TIndex> getIndexFunc = null!;
private readonly IComparer<TIndex> sortBy = null!;
if (value is not null)
Sort(value);
}
}
private int count = 0;
public override int Count => count;
public override int Count => behaviours.Count;
public override T this[Index index]
public override TItem this[Index index]
{
get
{
int actualIndex = index.IsFromEnd
? behaviours.Count - index.Value
? count - index.Value
: index.Value;
if (actualIndex < 0 || actualIndex >= behaviours.Count)
if (actualIndex < 0 || actualIndex >= count)
throw new IndexOutOfRangeException();
int currentIndex = 0;
foreach (T item in behaviours)
if (currentIndex++ == actualIndex)
return item;
int leftIndex = actualIndex;
foreach ((TIndex i, FastList<TItem> list) in behaviours)
{
if (leftIndex < list.Count)
return list[leftIndex];
leftIndex -= list.Count;
}
throw new IndexOutOfRangeException();
}
}
protected override bool RemoveBehaviour(T tBehaviour) => behaviours.Remove(tBehaviour);
protected override void AddBehaviour(T behaviour)
protected override bool RemoveBehaviour(TItem tBehaviour)
{
if (SortBy is null)
{
behaviours.AddLast(behaviour);
return;
}
TIndex index = getIndexFunc(tBehaviour);
if (!behaviours.TryGetValue(index, out FastList<TItem>? list))
throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
LinkedListNode<T>? insertionNode = FindInsertionNodeFor(behaviour, SortBy);
if (!list.Remove(tBehaviour))
return false;
if (insertionNode is not null)
behaviours.AddAfter(insertionNode, behaviour);
else
behaviours.AddLast(behaviour);
count--;
return true;
}
private LinkedListNode<T>? FindInsertionNodeFor(T behaviour, IComparer<T> sortBy)
protected override void AddBehaviour(TItem behaviour)
{
LinkedListNode<T>? node = behaviours.First;
TIndex key = getIndexFunc(behaviour);
if (!behaviours.TryGetValue(key, out FastList<TItem>? list))
behaviours[key] = list = [];
while (node is not null)
{
int compareValue = sortBy.Compare(node.Value, behaviour);
if (compareValue < 0)
return node.Previous;
node = node.Next;
}
return null;
count++;
list.Add(behaviour);
}
protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
@@ -81,23 +65,40 @@ public class ActiveBehaviourCollectorOrdered<T> : ActiveBehaviourCollector<T> wh
private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
{
T behaviour = (T)sender;
behaviours.Remove(behaviour);
TItem behaviour = (TItem)sender;
RemoveBehaviour(behaviour);
AddBehaviour(behaviour);
}
private void Sort(IComparer<T> comparer)
{
sortList.Sort(comparer);
behaviours.Clear();
foreach (T item in sortList)
behaviours.AddLast(item);
}
public ActiveBehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged;
public ActiveBehaviourCollectorOrdered(IUniverse universe, Comparison<T> sortBy) : base(universe)
public ActiveBehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
{
delegateOnPriorityChanged = OnPriorityChanged;
SortBy = Comparer<T>.Create(sortBy);
this.getIndexFunc = getIndexFunc;
this.sortBy = Comparer<TIndex>.Create(sortBy);
behaviours = new(this.sortBy);
}
public ActiveBehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = Comparer<TIndex>.Create(sortBy);
behaviours = new(this.sortBy);
}
public ActiveBehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
{
this.getIndexFunc = getIndexFunc;
delegateOnPriorityChanged = OnPriorityChanged;
this.sortBy = sortBy;
behaviours = new(sortBy);
}
public ActiveBehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = sortBy;
behaviours = new(sortBy);
}
}