internal void Subscribe(Action <T> action) { Debug.Assert(action is not null); _lock.Enter(); // ---- enter try { var count = _count; if (count == 0) { Debug.Assert(_actions is null); _actions = action; } else if (count == 1) { Debug.Assert(_actions is Action <T>); if (ArrayPoolForEventRaiser.TryGetArray4Fast(out var actions) == false) { actions = new object[DefaultBufferCapacity]; } Debug.Assert(actions.Length >= 2); MemoryMarshal.GetArrayDataReference(actions) = _actions; Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(actions), 1) = action; _actions = actions; } else { var actions = SafeCast.NotNullAs <object?[]>(_actions); if (actions.Length == count) { var newActions = new object[actions.Length * 2]; actions.AsSpan().CopyTo(newActions); if (actions.Length == ArrayPoolForEventRaiser.LengthOfPoolTargetArray) { actions[0] = null; actions[1] = null; actions[2] = null; actions[3] = null; ArrayPoolForEventRaiser.ReturnArray4Fast(actions); } _actions = newActions; actions = newActions; } actions[count] = action; } _count = count + 1; } finally { _lock.Exit(); // ---- exit } }
internal void Unsubscribe(Action <T>?action) { if (action is null) { return; } _lock.Enter(); // ---- enter try { var actions = _actions; var count = _count; if (count == 0) { Debug.Assert(actions is null); return; } else if (count == 1) { if (ReferenceEquals(_actions, action)) { _count = 0; _actions = null; } return; } else { var actionSpan = SafeCast.NotNullAs <object?[]>(actions).AsSpan(0, count); for (int i = 0; i < actionSpan.Length; i++) { if (ReferenceEquals(actionSpan[i], action)) { _count = count - 1; if (i < _count) { var copyLen = _count - i; actionSpan.Slice(i + 1, copyLen).CopyTo(actionSpan.Slice(i)); } actionSpan[_count] = null; if (_count == 1) { var a = actionSpan[0]; var actionsArray = SafeCast.NotNullAs <object?[]>(actions); if (actionsArray.Length == ArrayPoolForEventRaiser.LengthOfPoolTargetArray) { actionsArray[0] = null; actionsArray[1] = null; actionsArray[2] = null; actionsArray[3] = null; ArrayPoolForEventRaiser.ReturnArray4Fast(actionsArray); } _actions = a; } return; } } return; } } finally { _lock.Exit(); // ---- exit } }