Skip to content

Instantly share code, notes, and snippets.

@paulhayes
Last active October 25, 2018 12:19
Show Gist options
  • Save paulhayes/da8f4c1daa3f3d3a238f0849046e2400 to your computer and use it in GitHub Desktop.
Save paulhayes/da8f4c1daa3f3d3a238f0849046e2400 to your computer and use it in GitHub Desktop.
Concurrent and sequential coroutine helpers. For dual IEnumerators : Sequential, WhileBoth, WhileEither, For n>2 IEnumerators: WhileAny WhileAll Chain. Warning does not work with YieldInstructions
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace CoroutineUtil
{
/* Warning these helper methods can generate plenty of garbage memory, use responsibly */
public class WhileBoth : IEnumerator
{
IEnumerator a;
IEnumerator b;
public WhileBoth (IEnumerator a, IEnumerator b)
{
this.a = a;
this.b = b;
}
public object Current { get { return null; } }
public bool MoveNext()
{
return a.MoveNext() && b.MoveNext();
}
public void Reset() {}
}
public class WhileEither : IEnumerator
{
IEnumerator a;
IEnumerator b;
public WhileEither (IEnumerator a, IEnumerator b)
{
this.a = a;
this.b = b;
}
public object Current { get { return null; } }
public bool MoveNext() {
var aRunning = (a!=null) && a.MoveNext();
var bRunning = (b!=null) && b.MoveNext();
if( aRunning && a.Current is IEnumerator ){
a = new Chain( a.Current as IEnumerator, a );
aRunning = a.MoveNext();
}
if( bRunning && b.Current is IEnumerator ){
b = new Chain( b.Current as IEnumerator, b );
bRunning = b.MoveNext();
}
return aRunning | bRunning;
}
public void Reset() {}
}
public class WhileAny : IEnumerator
{
IEnumerator[] routines;
public WhileAny (params IEnumerator[] routines)
{
this.routines = routines;
}
public object Current { get { return null; } }
public bool MoveNext() {
int len = routines.Length;
bool isRunning = false;
for(int i=0;i<len;i++){
var routine = routines[i];
if( routine == null )
continue;
bool hasNext = routine.MoveNext();
isRunning |= hasNext ;
if( hasNext && routine.Current is IEnumerator ){
var subRoutine = routine.Current as IEnumerator;
if(subRoutine.MoveNext()){
routines[i] = new Sequencial(subRoutine,routine);
}
}
}
return isRunning;
}
public void Reset() {}
}
public class WhileAll : IEnumerator
{
IEnumerator[] routines;
public WhileAll (params IEnumerator[] routines)
{
this.routines = routines;
}
public object Current { get { return null; } }
public bool MoveNext() {
int len = routines.Length;
bool isRunning = true;
for(int i=0;i<len;i++){
var routine = routines[i];
bool hasNext = routine.MoveNext();
isRunning &= hasNext ;
if( hasNext && routine.Current is IEnumerator ){
var subRoutine = routine.Current as IEnumerator;
if(subRoutine.MoveNext()){
routines[i] = new Sequencial(subRoutine,routine);
}
}
}
return isRunning;
}
public void Reset() {}
}
public class Sequencial : IEnumerator
{
IEnumerator a;
IEnumerator b;
public Sequencial (IEnumerator a, IEnumerator b)
{
this.a = a;
this.b = b;
}
public object Current { get { return null; } }
public bool MoveNext()
{
var aRunning = a.MoveNext();
if( aRunning ){
if(a.Current is IEnumerator){
a = new Sequencial(a.Current as IEnumerator,a);
aRunning = a.MoveNext();
}
}
if(!aRunning) {
var bRunning = b.MoveNext();
if(bRunning && b.Current is IEnumerator){
b = new Sequencial(b.Current as IEnumerator,b);
bRunning = b.MoveNext();
}
return bRunning;
}
return aRunning;
}
public void Reset()
{
}
}
public class Chain : IEnumerator
{
IEnumerator[] chain;
int index;
public Chain (params IEnumerator[] chain)
{
index = 0;
this.chain = chain;
}
public object Current { get { return chain[index].Current; } }
public bool MoveNext()
{
while( !chain[index].MoveNext() ) {
index++;
if( index >= chain.Length){
return false;
}
}
return true;
}
public void Reset() {}
}
public static class CoroutineUtil
{
public static IEnumerator WaitForSeconds(float duration, bool unscaled = false)
{
float t = 0;
while( t < duration ){
t += unscaled ? Time.unscaledDeltaTime : Time.deltaTime;
yield return null;
}
}
public static IEnumerator WrapCustomYield(CustomYieldInstruction custom)
{
while(custom.keepWaiting){
yield return null;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment