perf: significant performance optimizations on ordered behaviour collectors by using a sorted dictionary
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -3,76 +3,61 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
public class BehaviourCollectorOrdered<T> : BehaviourCollectorBase<T> where T : class
|
||||
public class BehaviourCollectorOrdered<TIndex, TItem> : BehaviourCollectorBase<TItem> where TItem : class 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);
|
||||
@@ -80,23 +65,40 @@ public class BehaviourCollectorOrdered<T> : BehaviourCollectorBase<T> where T :
|
||||
|
||||
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 BehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged;
|
||||
public BehaviourCollectorOrdered(IUniverse universe, Comparison<T> sortBy) : base(universe)
|
||||
public BehaviourCollectorOrdered(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 BehaviourCollectorOrdered(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 BehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
|
||||
{
|
||||
this.getIndexFunc = getIndexFunc;
|
||||
delegateOnPriorityChanged = OnPriorityChanged;
|
||||
this.sortBy = sortBy;
|
||||
behaviours = new(sortBy);
|
||||
}
|
||||
|
||||
public BehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy) : base(universe)
|
||||
{
|
||||
delegateOnPriorityChanged = OnPriorityChanged;
|
||||
this.getIndexFunc = getIndexFunc;
|
||||
this.sortBy = sortBy;
|
||||
behaviours = new(sortBy);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user