| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 | using System;using System.Runtime.CompilerServices;using UnityEngine;namespace UnityAsync{	public partial class AsyncManager	{		partial class ContinuationProcessorGroup		{			const int MaxQueueSize = 1 << 16;			class ContinuationProcessor<T> : IContinuationProcessor where T : IAwaitInstructionAwaiter			{				public static ContinuationProcessor<T> instance;				T[] currentQueue, futureQueue;				int currentCount, currentIndex, futureCount, maxIndex;				public ContinuationProcessor(int capacity)				{					AssertQueueSize(capacity);										maxIndex = capacity - 1;										currentQueue = new T[capacity];					futureQueue = new T[capacity];				}				public void Process()				{					currentCount = futureCount;					futureCount = 0;										// swap queues					var tmp = currentQueue;					currentQueue = futureQueue;					futureQueue = tmp;					for(; currentIndex < currentCount; ++currentIndex)					{						ref var c = ref currentQueue[currentIndex];						if(!c.Evaluate())						{							// this is hottest path so we don't do a bounds check here (see Add)							futureQueue[futureCount] = c;							++futureCount;						}					}					currentIndex = 0;					currentCount = 0;										Array.Clear(currentQueue, 0, currentCount);				}				[MethodImpl(MethodImplOptions.AggressiveInlining)]				public void Add(in T cont)				{					if(InUnityContext)						AddFast(cont);					else						AddThreadSafe(cont);				}				// only call in UnitySynchronizationContext - not thread safe				[MethodImpl(MethodImplOptions.AggressiveInlining)]				void AddFast(in T cont)				{					try					{						// we might have awaiters yet to be processed this frame; when they are re-added we skip any						// bounds checks as an optimisation, so we need to make sure the queue has enough space to						// re-add them all in case none of them have finished						int potentialFutureCount = futureCount + currentCount - currentIndex;												if(potentialFutureCount >= maxIndex)						{							AssertQueueSize(potentialFutureCount + 1);														int newQueueSize = Math.Min(MaxQueueSize, Math.Max(potentialFutureCount, futureQueue.Length * 3 / 2));													Array.Resize(ref futureQueue, newQueueSize);							Array.Resize(ref currentQueue, newQueueSize);													maxIndex = newQueueSize - 1;						}						futureQueue[futureCount] = cont;						++futureCount;					}					catch(Exception e)					{						Debug.LogException(e);					}				}				// use when you may be adding an awaiter from outside of UnitySynchronizationContext				[MethodImpl(MethodImplOptions.AggressiveInlining)]				async void AddThreadSafe(T cont)				{					await UnitySyncContext;					AddFast(cont);				}				[MethodImpl(MethodImplOptions.AggressiveInlining)]				static void AssertQueueSize(int queueSize)				{					if(queueSize > MaxQueueSize)						throw new InvalidOperationException($"Cannot exceed queue size of {MaxQueueSize}.");				}			}		}	}}
 |