perf: ordered behaviour collectors now use linked lists for performance

This commit is contained in:
2025-10-11 16:07:26 +03:00
parent e3d4899112
commit 9ccf7b754d
2 changed files with 109 additions and 28 deletions

View File

@@ -7,6 +7,9 @@ public class ActiveBehaviourCollectorOrdered<T> : ActiveBehaviourCollector<T> wh
{ {
private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!; private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
private readonly LinkedList<T> behaviours = new();
private readonly List<T> sortList = [];
private IComparer<T>? _sortBy = null; private IComparer<T>? _sortBy = null;
public IComparer<T>? SortBy public IComparer<T>? SortBy
{ {
@@ -16,43 +19,81 @@ public class ActiveBehaviourCollectorOrdered<T> : ActiveBehaviourCollector<T> wh
_sortBy = value; _sortBy = value;
if (value is not null) if (value is not null)
activeBehaviours.Sort(value); Sort(value);
} }
} }
public override int Count => behaviours.Count;
public override T this[Index index]
{
get
{
int actualIndex = index.IsFromEnd
? behaviours.Count - index.Value
: index.Value;
if (actualIndex < 0 || actualIndex >= behaviours.Count)
throw new IndexOutOfRangeException();
int currentIndex = 0;
foreach (T item in behaviours)
if (currentIndex++ == actualIndex)
return item;
throw new IndexOutOfRangeException();
}
}
protected override bool RemoveBehaviour(T tBehaviour) => behaviours.Remove(tBehaviour);
protected override void AddBehaviour(T behaviour) protected override void AddBehaviour(T behaviour)
{ {
if (SortBy is null) if (SortBy is null)
{ {
activeBehaviours.Add(behaviour); behaviours.AddLast(behaviour);
return; return;
} }
int insertionIndex = activeBehaviours.BinarySearch(behaviour, SortBy); LinkedListNode<T>? insertionNode = FindInsertionNodeFor(behaviour, SortBy);
if (insertionIndex < 0) if (insertionNode is not null)
insertionIndex = ~insertionIndex; behaviours.AddAfter(insertionNode, behaviour);
else
activeBehaviours.Insert(insertionIndex, behaviour); behaviours.AddLast(behaviour);
} }
protected override void OnBehaviourAdd(IBehaviour behaviour) private LinkedListNode<T>? FindInsertionNodeFor(T behaviour, IComparer<T> sortBy)
{ {
behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); LinkedListNode<T>? node = behaviours.First;
while (node is not null)
{
int compareValue = sortBy.Compare(node.Value, behaviour);
if (compareValue < 0)
return node.Previous;
node = node.Next;
}
return null;
} }
protected override void OnBehaviourRemove(IBehaviour behaviour) protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
{ protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
}
private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args) private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
{ {
T behaviour = (T)sender; T behaviour = (T)sender;
activeBehaviours.Remove(behaviour); behaviours.Remove(behaviour);
AddBehaviour(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() => delegateOnPriorityChanged = OnPriorityChanged;
public ActiveBehaviourCollectorOrdered(IUniverse universe, Comparison<T> sortBy) : base(universe) public ActiveBehaviourCollectorOrdered(IUniverse universe, Comparison<T> sortBy) : base(universe)
{ {

View File

@@ -3,10 +3,13 @@ using System.Collections.Generic;
namespace Engine.Core; namespace Engine.Core;
public class BehaviourCollectorOrdered<T> : BehaviourCollector<T> where T : class public class BehaviourCollectorOrdered<T> : BehaviourCollectorBase<T> where T : class
{ {
private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!; private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
private readonly LinkedList<T> behaviours = new();
private readonly List<T> sortList = [];
private IComparer<T>? _sortBy = null; private IComparer<T>? _sortBy = null;
public IComparer<T>? SortBy public IComparer<T>? SortBy
{ {
@@ -16,35 +19,64 @@ public class BehaviourCollectorOrdered<T> : BehaviourCollector<T> where T : clas
_sortBy = value; _sortBy = value;
if (value is not null) if (value is not null)
behaviours.Sort(value); Sort(value);
} }
} }
public override int Count => behaviours.Count;
public override T this[Index index]
{
get
{
int actualIndex = index.IsFromEnd
? behaviours.Count - index.Value
: index.Value;
if (actualIndex < 0 || actualIndex >= behaviours.Count)
throw new IndexOutOfRangeException();
int currentIndex = 0;
foreach (T item in behaviours)
if (currentIndex++ == actualIndex)
return item;
throw new IndexOutOfRangeException();
}
}
protected override bool RemoveBehaviour(T tBehaviour) => behaviours.Remove(tBehaviour);
protected override void AddBehaviour(T behaviour) protected override void AddBehaviour(T behaviour)
{ {
if (SortBy is null) if (SortBy is null)
{ {
behaviours.Add(behaviour); behaviours.AddLast(behaviour);
return; return;
} }
int insertionIndex = behaviours.BinarySearch(behaviour, SortBy); LinkedListNode<T>? insertionNode = FindInsertionNodeFor(behaviour, SortBy);
if (insertionIndex < 0) if (insertionNode is not null)
insertionIndex = ~insertionIndex; behaviours.AddAfter(insertionNode, behaviour);
else
behaviours.Insert(insertionIndex, behaviour); behaviours.AddLast(behaviour);
} }
protected override void OnBehaviourAdd(IBehaviour behaviour) private LinkedListNode<T>? FindInsertionNodeFor(T behaviour, IComparer<T> sortBy)
{ {
behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); LinkedListNode<T>? node = behaviours.First;
while (node is not null)
{
int compareValue = sortBy.Compare(node.Value, behaviour);
if (compareValue < 0)
return node.Previous;
node = node.Next;
}
return null;
} }
protected override void OnBehaviourRemove(IBehaviour behaviour) protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
{ protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
}
private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args) private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
{ {
@@ -53,6 +85,14 @@ public class BehaviourCollectorOrdered<T> : BehaviourCollector<T> where T : clas
AddBehaviour(behaviour); AddBehaviour(behaviour);
} }
private void Sort(IComparer<T> comparer)
{
sortList.Sort(comparer);
behaviours.Clear();
foreach (T item in sortList)
behaviours.AddLast(item);
}
public BehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged; public BehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged;
public BehaviourCollectorOrdered(IUniverse universe, Comparison<T> sortBy) : base(universe) public BehaviourCollectorOrdered(IUniverse universe, Comparison<T> sortBy) : base(universe)
{ {