225 lines
7.0 KiB
C#
225 lines
7.0 KiB
C#
using System;
|
||
using System.Runtime.CompilerServices;
|
||
using System.Runtime.InteropServices;
|
||
using Unity.IL2CPP.CompilerServices;
|
||
using UnityEngine;
|
||
|
||
namespace AlicizaX
|
||
{
|
||
[Il2CppSetOption(Option.NullChecks, false)]
|
||
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||
public static class EventContainer<TPayload> where TPayload : struct, IEventArgs
|
||
{
|
||
private static readonly int InitialSize = EventInitialSize<TPayload>.Size;
|
||
private static readonly int TypeId;
|
||
|
||
// 优化3: SoA布局,提升缓存命中率
|
||
private static Action<TPayload>[] _callbacks;
|
||
private static int[] _versions;
|
||
private static int[] _activeSlots;
|
||
|
||
private static int[] _freeSlots;
|
||
private static int _freeCount;
|
||
private static int[] _activeIndices;
|
||
private static int _activeCount;
|
||
private static int _version;
|
||
|
||
#if Event_StrictCheck
|
||
private static System.Collections.Generic.HashSet<Action<TPayload>> _activeHandlers;
|
||
#endif
|
||
|
||
static EventContainer()
|
||
{
|
||
TypeId = UnsubscribeRegistry.Register(Unsubscribe);
|
||
|
||
_callbacks = new Action<TPayload>[InitialSize];
|
||
_versions = new int[InitialSize];
|
||
_activeSlots = new int[InitialSize];
|
||
_freeSlots = new int[InitialSize];
|
||
_activeIndices = new int[InitialSize];
|
||
_freeCount = InitialSize;
|
||
|
||
for (int i = 0; i < InitialSize; i++)
|
||
{
|
||
_freeSlots[i] = i;
|
||
}
|
||
|
||
#if Event_StrictCheck
|
||
_activeHandlers = new System.Collections.Generic.HashSet<Action<TPayload>>();
|
||
#endif
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static EventRuntimeHandle Subscribe(Action<TPayload> callback)
|
||
{
|
||
#if Event_StrictCheck
|
||
if (_activeHandlers.Contains(callback))
|
||
{
|
||
UnityEngine.Debug.LogWarning($"重复订阅事件处理程序: {callback.Method.Name}");
|
||
return default;
|
||
}
|
||
|
||
_activeHandlers.Add(callback);
|
||
#endif
|
||
|
||
int handlerIndex = GetFreeSlot();
|
||
|
||
// 优化4: 提前扩容检查
|
||
if (_activeCount >= _activeIndices.Length)
|
||
{
|
||
Array.Resize(ref _activeIndices, _activeIndices.Length << 1);
|
||
}
|
||
|
||
int activeIndex = _activeCount++;
|
||
_activeIndices[activeIndex] = handlerIndex;
|
||
|
||
int version = ++_version;
|
||
_callbacks[handlerIndex] = callback;
|
||
_versions[handlerIndex] = version;
|
||
_activeSlots[handlerIndex] = activeIndex;
|
||
|
||
return new EventRuntimeHandle(TypeId, handlerIndex, version);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
private static int GetFreeSlot()
|
||
{
|
||
if (_freeCount > 0)
|
||
{
|
||
return _freeSlots[--_freeCount];
|
||
}
|
||
|
||
int oldLen = _callbacks.Length;
|
||
int newSize = oldLen == 0 ? 64 : oldLen << 1;
|
||
|
||
// 批量扩容
|
||
Array.Resize(ref _callbacks, newSize);
|
||
Array.Resize(ref _versions, newSize);
|
||
Array.Resize(ref _activeSlots, newSize);
|
||
Array.Resize(ref _freeSlots, newSize);
|
||
|
||
// 逆序添加,保持小索引优先(缓存友好)
|
||
for (int i = newSize - 1; i >= oldLen; i--)
|
||
{
|
||
_freeSlots[_freeCount++] = i;
|
||
}
|
||
|
||
return _freeSlots[--_freeCount];
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
private static void Unsubscribe(int handlerIndex, int version)
|
||
{
|
||
// 优化5: 提前版本检查
|
||
if (_versions[handlerIndex] != version) return;
|
||
|
||
int lastActiveIndex = --_activeCount;
|
||
int lastHandlerIndex = _activeIndices[lastActiveIndex];
|
||
int currentActiveIndex = _activeSlots[handlerIndex];
|
||
|
||
// Swap-remove
|
||
_activeIndices[currentActiveIndex] = lastHandlerIndex;
|
||
_activeSlots[lastHandlerIndex] = currentActiveIndex;
|
||
|
||
#if Event_StrictCheck
|
||
_activeHandlers.Remove(_callbacks[handlerIndex]);
|
||
#endif
|
||
|
||
_callbacks[handlerIndex] = null;
|
||
_versions[handlerIndex] = 0;
|
||
|
||
if (_freeCount >= _freeSlots.Length)
|
||
{
|
||
Array.Resize(ref _freeSlots, _freeSlots.Length << 1);
|
||
}
|
||
|
||
_freeSlots[_freeCount++] = handlerIndex;
|
||
}
|
||
|
||
// 优化6: 改进Publish,减少数组访问和分支
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void Publish(in TPayload payload)
|
||
{
|
||
int count = _activeCount;
|
||
if (count == 0) return; // 快速路径
|
||
|
||
int[] indices = _activeIndices;
|
||
Action<TPayload>[] callbacks = _callbacks;
|
||
|
||
// 优化7: 更高效的循环展开
|
||
int i = 0;
|
||
int unrolled = count & ~3; // count - (count % 4)
|
||
|
||
// 4路展开主循环
|
||
for (; i < unrolled; i += 4)
|
||
{
|
||
int idx0 = indices[i];
|
||
int idx1 = indices[i + 1];
|
||
int idx2 = indices[i + 2];
|
||
int idx3 = indices[i + 3];
|
||
|
||
callbacks[idx0](payload);
|
||
callbacks[idx1](payload);
|
||
callbacks[idx2](payload);
|
||
callbacks[idx3](payload);
|
||
}
|
||
|
||
// 优化8: 使用Duff's Device处理剩余
|
||
switch (count - i)
|
||
{
|
||
case 3:
|
||
callbacks[indices[i + 2]](payload);
|
||
goto case 2;
|
||
case 2:
|
||
callbacks[indices[i + 1]](payload);
|
||
goto case 1;
|
||
case 1: callbacks[indices[i]](payload); break;
|
||
}
|
||
}
|
||
|
||
// 额外优化方法
|
||
public static int SubscriberCount
|
||
{
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
get => _activeCount;
|
||
}
|
||
|
||
// 预热容量,避免运行时扩容
|
||
public static void EnsureCapacity(int capacity)
|
||
{
|
||
if (_callbacks.Length >= capacity) return;
|
||
|
||
int oldLen = _callbacks.Length;
|
||
Array.Resize(ref _callbacks, capacity);
|
||
Array.Resize(ref _versions, capacity);
|
||
Array.Resize(ref _activeSlots, capacity);
|
||
Array.Resize(ref _freeSlots, capacity);
|
||
Array.Resize(ref _activeIndices, capacity);
|
||
|
||
for (int i = capacity - 1; i >= oldLen; i--)
|
||
{
|
||
_freeSlots[_freeCount++] = i;
|
||
}
|
||
}
|
||
|
||
// 清空所有订阅
|
||
public static void Clear()
|
||
{
|
||
for (int i = 0; i < _activeCount; i++)
|
||
{
|
||
int idx = _activeIndices[i];
|
||
_callbacks[idx] = null;
|
||
_versions[idx] = 0;
|
||
_freeSlots[_freeCount++] = idx;
|
||
}
|
||
|
||
_activeCount = 0;
|
||
|
||
#if Event_StrictCheck
|
||
_activeHandlers.Clear();
|
||
#endif
|
||
}
|
||
}
|
||
}
|