Fix TriggerEvent problem with iterate breaking on Remove when it has multiple handlers

pull/487/head
hadashiA 2023-09-02 22:26:09 +09:00
parent c1042b32b7
commit 22940635fe
1 changed files with 61 additions and 81 deletions

View File

@ -20,8 +20,6 @@ namespace Cysharp.Threading.Tasks
{ {
ITriggerHandler<T> head; // head.prev is last ITriggerHandler<T> head; // head.prev is last
ITriggerHandler<T> iteratingHead; ITriggerHandler<T> iteratingHead;
bool preserveRemoveSelf;
ITriggerHandler<T> iteratingNode; ITriggerHandler<T> iteratingNode;
void LogError(Exception ex) void LogError(Exception ex)
@ -55,18 +53,9 @@ namespace Cysharp.Threading.Tasks
Remove(h); Remove(h);
} }
if (preserveRemoveSelf) // If `h` itself is removed by OnNext, h.Next is null.
{ // Therefore, instead of looking at h.Next, the `iteratingNode` reference itself is replaced.
preserveRemoveSelf = false; h = h == iteratingNode ? h.Next : iteratingNode;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
else
{
h = h.Next;
}
} }
iteratingNode = null; iteratingNode = null;
@ -97,9 +86,8 @@ namespace Cysharp.Threading.Tasks
LogError(ex); LogError(ex);
} }
preserveRemoveSelf = false;
iteratingNode = null; iteratingNode = null;
var next = h.Next; var next = h == iteratingNode ? h.Next : iteratingNode;
Remove(h); Remove(h);
h = next; h = next;
} }
@ -132,9 +120,8 @@ namespace Cysharp.Threading.Tasks
LogError(ex); LogError(ex);
} }
preserveRemoveSelf = false; var next = h == iteratingNode ? h.Next : iteratingNode;
iteratingNode = null; iteratingNode = null;
var next = h.Next;
Remove(h); Remove(h);
h = next; h = next;
} }
@ -167,9 +154,8 @@ namespace Cysharp.Threading.Tasks
LogError(ex); LogError(ex);
} }
preserveRemoveSelf = false; var next = h == iteratingNode ? h.Next : iteratingNode;
iteratingNode = null; iteratingNode = null;
var next = h.Next;
Remove(h); Remove(h);
h = next; h = next;
} }
@ -241,13 +227,6 @@ namespace Cysharp.Threading.Tasks
{ {
if (handler == null) throw new ArgumentNullException(nameof(handler)); if (handler == null) throw new ArgumentNullException(nameof(handler));
if (iteratingNode != null && iteratingNode == handler)
{
// if remove self, reserve remove self after invoke completed.
preserveRemoveSelf = true;
}
else
{
var prev = handler.Prev; var prev = handler.Prev;
var next = handler.Next; var next = handler.Next;
@ -260,17 +239,19 @@ namespace Cysharp.Threading.Tasks
{ {
head = next; head = next;
} }
else if (handler == iteratingHead)
{
iteratingHead = next;
}
else
{
// when handler is head, prev indicate last so don't use it. // when handler is head, prev indicate last so don't use it.
if (prev != null) else if (prev != null)
{ {
prev.Next = next; prev.Next = next;
} }
if (handler == iteratingNode)
{
iteratingNode = next;
}
if (handler == iteratingHead)
{
iteratingHead = next;
} }
if (head != null) if (head != null)
@ -308,4 +289,3 @@ namespace Cysharp.Threading.Tasks
} }
} }
} }
}