diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/ArrayUtil.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/ArrayUtil.cs index fc7a808..883700d 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/ArrayUtil.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/ArrayUtil.cs @@ -68,6 +68,55 @@ namespace Cysharp.Threading.Tasks.Internal return (buffer, index); } } + + public static void Swap(IList array, int indexA, int indexB) + { + var tmp = array[indexA]; + array[indexA] = array[indexB]; + array[indexB] = tmp; + } + + /// + /// Returns the index of the first element satisfying the . + /// Returns -1 if no such element exists. + /// + /// The array to search. + /// The predicate use to search the array. + /// The type of elements in the array. + /// Index of the first element satisfying the otherwise returns -1. + public static int FirstIndexOf(IReadOnlyList array, Func predicate) + { + for (var i = 0; i < array.Count; ++i) + { + if (!predicate(array[i])) continue; + return i; + } + + return -1; + } + + /// + /// Reorders the elements in in such a way that all elements for which the + /// returns true precede the elements for which returns false. + /// Relative order of the elements is not preserved. + /// + /// The array to partition. + /// The predicate that determine how the elements are partitioned. + /// The type of the elements in the array. + /// Return the index of first element of the second group. + public static int Partition(T[] array, Func predicate) + { + var pivot = FirstIndexOf(array, element => !predicate(element)); + if (pivot == -1) return array.Length; + for (var i = pivot + 1; i < array.Length; ++i) + { + if (!predicate(array[i])) continue; + Swap(array, pivot, i); + ++pivot; + } + + return pivot; + } } } diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs index 621ba5a..23de931 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs @@ -1,5 +1,4 @@ - -using System; +using System; using UnityEngine; namespace Cysharp.Threading.Tasks.Internal @@ -131,6 +130,7 @@ namespace Cysharp.Threading.Tasks.Internal void PostLateUpdate() => RunCore(); void LastPostLateUpdate() => RunCore(); + [System.Diagnostics.DebuggerHidden] void RunCore() { @@ -141,85 +141,29 @@ namespace Cysharp.Threading.Tasks.Internal lock (arrayLock) { - var j = tail - 1; - - // eliminate array-bound check for i - for (int i = 0; i < loopItems.Length; i++) + var pivot = ArrayUtil.Partition(loopItems, playerLoopItem => { - var action = loopItems[i]; - if (action != null) + try + { + return playerLoopItem != null && playerLoopItem.MoveNext(); + } + catch (Exception e) { try { - if (!action.MoveNext()) - { - loopItems[i] = null; - } - else - { - continue; // next i - } + unhandledExceptionCallback(e); + return false; } - catch (Exception ex) + catch { - loopItems[i] = null; - try - { - unhandledExceptionCallback(ex); - } - catch { } + return false; } } - - // find null, loop from tail - while (i < j) - { - var fromTail = loopItems[j]; - if (fromTail != null) - { - try - { - if (!fromTail.MoveNext()) - { - loopItems[j] = null; - j--; - continue; // next j - } - else - { - // swap - loopItems[i] = fromTail; - loopItems[j] = null; - j--; - goto NEXT_LOOP; // next i - } - } - catch (Exception ex) - { - loopItems[j] = null; - j--; - try - { - unhandledExceptionCallback(ex); - } - catch { } - continue; // next j - } - } - else - { - j--; - } - } - - tail = i; // loop end - break; // LOOP END - - NEXT_LOOP: - continue; - } - - + }); + + for (var i = pivot; i < loopItems.Length; ++i) + loopItems[i] = null; + lock (runningAndQueueLock) { running = false;