com.alicizax.unity.framework/Runtime/ABase/Event/EventContainer.cs
2025-12-24 14:34:26 +08:00

225 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}
}