From 9ccf7b754d89349878c3535fd83b97f632943434 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 11 Oct 2025 16:07:26 +0300 Subject: [PATCH] perf: ordered behaviour collectors now use linked lists for performance --- .../ActiveBehaviourCollectorOrdered.cs | 69 +++++++++++++++---- .../Collectors/BehaviourCollectorOrdered.cs | 68 ++++++++++++++---- 2 files changed, 109 insertions(+), 28 deletions(-) diff --git a/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs b/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs index 5c20423..fbc14e4 100644 --- a/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs +++ b/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs @@ -7,6 +7,9 @@ public class ActiveBehaviourCollectorOrdered : ActiveBehaviourCollector wh { private readonly Event.EventHandler delegateOnPriorityChanged = null!; + private readonly LinkedList behaviours = new(); + private readonly List sortList = []; + private IComparer? _sortBy = null; public IComparer? SortBy { @@ -16,43 +19,81 @@ public class ActiveBehaviourCollectorOrdered : ActiveBehaviourCollector wh _sortBy = value; 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) { if (SortBy is null) { - activeBehaviours.Add(behaviour); + behaviours.AddLast(behaviour); return; } - int insertionIndex = activeBehaviours.BinarySearch(behaviour, SortBy); + LinkedListNode? insertionNode = FindInsertionNodeFor(behaviour, SortBy); - if (insertionIndex < 0) - insertionIndex = ~insertionIndex; - - activeBehaviours.Insert(insertionIndex, behaviour); + if (insertionNode is not null) + behaviours.AddAfter(insertionNode, behaviour); + else + behaviours.AddLast(behaviour); } - protected override void OnBehaviourAdd(IBehaviour behaviour) + private LinkedListNode? FindInsertionNodeFor(T behaviour, IComparer sortBy) { - behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); + LinkedListNode? 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) - { - behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged); - } + protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); + protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged); private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args) { T behaviour = (T)sender; - activeBehaviours.Remove(behaviour); + behaviours.Remove(behaviour); AddBehaviour(behaviour); } + private void Sort(IComparer comparer) + { + sortList.Sort(comparer); + behaviours.Clear(); + foreach (T item in sortList) + behaviours.AddLast(item); + } + public ActiveBehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged; public ActiveBehaviourCollectorOrdered(IUniverse universe, Comparison sortBy) : base(universe) { diff --git a/Engine.Core/Collectors/BehaviourCollectorOrdered.cs b/Engine.Core/Collectors/BehaviourCollectorOrdered.cs index bbf445b..5558aa2 100644 --- a/Engine.Core/Collectors/BehaviourCollectorOrdered.cs +++ b/Engine.Core/Collectors/BehaviourCollectorOrdered.cs @@ -3,10 +3,13 @@ using System.Collections.Generic; namespace Engine.Core; -public class BehaviourCollectorOrdered : BehaviourCollector where T : class +public class BehaviourCollectorOrdered : BehaviourCollectorBase where T : class { private readonly Event.EventHandler delegateOnPriorityChanged = null!; + private readonly LinkedList behaviours = new(); + private readonly List sortList = []; + private IComparer? _sortBy = null; public IComparer? SortBy { @@ -16,35 +19,64 @@ public class BehaviourCollectorOrdered : BehaviourCollector where T : clas _sortBy = value; 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) { if (SortBy is null) { - behaviours.Add(behaviour); + behaviours.AddLast(behaviour); return; } - int insertionIndex = behaviours.BinarySearch(behaviour, SortBy); + LinkedListNode? insertionNode = FindInsertionNodeFor(behaviour, SortBy); - if (insertionIndex < 0) - insertionIndex = ~insertionIndex; - - behaviours.Insert(insertionIndex, behaviour); + if (insertionNode is not null) + behaviours.AddAfter(insertionNode, behaviour); + else + behaviours.AddLast(behaviour); } - protected override void OnBehaviourAdd(IBehaviour behaviour) + private LinkedListNode? FindInsertionNodeFor(T behaviour, IComparer sortBy) { - behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); + LinkedListNode? 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) - { - behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged); - } + protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); + protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged); private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args) { @@ -53,6 +85,14 @@ public class BehaviourCollectorOrdered : BehaviourCollector where T : clas AddBehaviour(behaviour); } + private void Sort(IComparer comparer) + { + sortList.Sort(comparer); + behaviours.Clear(); + foreach (T item in sortList) + behaviours.AddLast(item); + } + public BehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged; public BehaviourCollectorOrdered(IUniverse universe, Comparison sortBy) : base(universe) {