diff --git a/src/GameUtils/Entity/EventBus.cs b/src/GameUtils/Entity/EventBus.cs index a1d57c5..8030316 100644 --- a/src/GameUtils/Entity/EventBus.cs +++ b/src/GameUtils/Entity/EventBus.cs @@ -7,7 +7,6 @@ namespace GameUtils.Entity; public class EventBus { private readonly Dictionary _handlers = []; - private readonly Dictionary _snapshots = []; /// /// Subscribes to events of type . @@ -17,19 +16,18 @@ public void Subscribe(Action handler) ArgumentNullException.ThrowIfNull(handler); var type = typeof(TEvent); - ref var listObj = ref System.Runtime.InteropServices.CollectionsMarshal.GetValueRefOrAddDefault(_handlers, type, out bool exists); - List> list; - if (!exists) + ref var obj = ref System.Runtime.InteropServices.CollectionsMarshal.GetValueRefOrAddDefault(_handlers, type, out bool exists); + if (!exists || obj is not Action[] oldArray) { - list = new List>(); - listObj = list; + obj = new Action[] { handler }; } else { - list = (List>)listObj!; + var newArray = new Action[oldArray.Length + 1]; + Array.Copy(oldArray, newArray, oldArray.Length); + newArray[oldArray.Length] = handler; + obj = newArray; } - list.Add(handler); - _snapshots.Remove(type); } /// @@ -41,12 +39,24 @@ public void Unsubscribe(Action handler) ArgumentNullException.ThrowIfNull(handler); var type = typeof(TEvent); - if (_handlers.TryGetValue(type, out var listObj)) + if (_handlers.TryGetValue(type, out var obj) && obj is Action[] oldArray) { - var list = (List>)listObj; - if (list.Remove(handler)) + int index = Array.IndexOf(oldArray, handler); + if (index < 0) { - _snapshots.Remove(type); + return; + } + + if (oldArray.Length == 1) + { + _handlers.Remove(type); + } + else + { + var newArray = new Action[oldArray.Length - 1]; + Array.Copy(oldArray, 0, newArray, 0, index); + Array.Copy(oldArray, index + 1, newArray, index, oldArray.Length - index - 1); + _handlers[type] = newArray; } } } @@ -59,18 +69,13 @@ public void Unsubscribe(Action handler) public void Publish(TEvent eventData) { var type = typeof(TEvent); - if (!_snapshots.TryGetValue(type, out var snapshot)) + if (!_handlers.TryGetValue(type, out var obj)) { - if (!_handlers.TryGetValue(type, out var listObj)) - { - return; - } - snapshot = ((List>)listObj).ToArray(); - _snapshots[type] = snapshot; + return; } - var typedSnapshot = (Action[])snapshot; - foreach (var handler in typedSnapshot) + var handlers = (Action[])obj; + foreach (var handler in handlers) { handler(eventData); } @@ -82,7 +87,6 @@ public void Publish(TEvent eventData) public void Clear() { _handlers.Clear(); - _snapshots.Clear(); } /// @@ -92,6 +96,5 @@ public void Clear() { var type = typeof(TEvent); _handlers.Remove(type); - _snapshots.Remove(type); } } diff --git a/tests/GameUtils.Benchmarks/EventBusBenchmarks.cs b/tests/GameUtils.Benchmarks/EventBusBenchmarks.cs index 50d2918..c3ec210 100644 --- a/tests/GameUtils.Benchmarks/EventBusBenchmarks.cs +++ b/tests/GameUtils.Benchmarks/EventBusBenchmarks.cs @@ -12,12 +12,18 @@ private class TestEvent2 { } private Action _handler1 = null!; private Action _handler2 = null!; + private EventBus _busWithSubscribers = null!; + private TestEvent1 _event1 = null!; [GlobalSetup] public void Setup() { _handler1 = e => { }; _handler2 = e => { }; + _event1 = new TestEvent1(); + _busWithSubscribers = new EventBus(); + _busWithSubscribers.Subscribe(_handler1); + _busWithSubscribers.Subscribe(_handler2); } [Benchmark] @@ -38,5 +44,11 @@ public void SubscribeExistingEvent() bus.Subscribe(_handler1); } } + + [Benchmark] + public void Publish() + { + _busWithSubscribers.Publish(_event1); + } } }