mirror of
https://github.com/Ellpeck/Coroutine.git
synced 2024-11-21 21:33:29 +01:00
overhaul the coroutine system to avoid boxing
This commit is contained in:
parent
ae6e4924ec
commit
b4874dd365
7 changed files with 75 additions and 101 deletions
|
@ -4,12 +4,14 @@ using System.Collections.Generic;
|
|||
namespace Coroutine {
|
||||
public class ActiveCoroutine {
|
||||
|
||||
private readonly IEnumerator<IWait> enumerator;
|
||||
private readonly IEnumerator<Wait> enumerator;
|
||||
private Wait current;
|
||||
|
||||
public bool IsFinished { get; private set; }
|
||||
public bool WasCanceled { get; private set; }
|
||||
public FinishCallback OnFinished;
|
||||
|
||||
internal ActiveCoroutine(IEnumerator<IWait> enumerator) {
|
||||
internal ActiveCoroutine(IEnumerator<Wait> enumerator) {
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
|
@ -24,8 +26,7 @@ namespace Coroutine {
|
|||
|
||||
internal bool Tick(double deltaSeconds) {
|
||||
if (!this.WasCanceled) {
|
||||
var curr = this.enumerator.Current;
|
||||
if (curr != null && curr.Tick(deltaSeconds))
|
||||
if (this.current.Tick(deltaSeconds))
|
||||
this.MoveNext();
|
||||
}
|
||||
return this.IsFinished;
|
||||
|
@ -33,22 +34,24 @@ namespace Coroutine {
|
|||
|
||||
internal bool OnEvent(Event evt) {
|
||||
if (!this.WasCanceled) {
|
||||
var curr = this.enumerator.Current;
|
||||
if (curr != null && curr.OnEvent(evt))
|
||||
if (this.current.OnEvent(evt))
|
||||
this.MoveNext();
|
||||
}
|
||||
return this.IsFinished;
|
||||
}
|
||||
|
||||
private void MoveNext() {
|
||||
internal bool MoveNext() {
|
||||
if (!this.enumerator.MoveNext()) {
|
||||
this.IsFinished = true;
|
||||
this.OnFinished?.Invoke(this);
|
||||
return false;
|
||||
}
|
||||
this.current = this.enumerator.Current;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal WaitType GetCurrentType() {
|
||||
return this.enumerator.Current.GetWaitType();
|
||||
internal bool IsWaitingForEvent() {
|
||||
return this.current.IsWaitingForEvent();
|
||||
}
|
||||
|
||||
public delegate void FinishCallback(ActiveCoroutine coroutine);
|
||||
|
|
|
@ -8,19 +8,23 @@ namespace Coroutine {
|
|||
private static readonly List<ActiveCoroutine> TickingCoroutines = new List<ActiveCoroutine>();
|
||||
private static readonly List<ActiveCoroutine> EventCoroutines = new List<ActiveCoroutine>();
|
||||
|
||||
public static ActiveCoroutine Start(IEnumerator<IWait> coroutine) {
|
||||
if (!coroutine.MoveNext())
|
||||
return null;
|
||||
public static ActiveCoroutine Start(IEnumerable<Wait> coroutine) {
|
||||
return Start(coroutine.GetEnumerator());
|
||||
}
|
||||
|
||||
public static ActiveCoroutine Start(IEnumerator<Wait> coroutine) {
|
||||
var inst = new ActiveCoroutine(coroutine);
|
||||
var type = inst.GetCurrentType();
|
||||
if (type == WaitType.Tick)
|
||||
TickingCoroutines.Add(inst);
|
||||
else if (type == WaitType.Event)
|
||||
if (inst.MoveNext()) {
|
||||
if (inst.IsWaitingForEvent()) {
|
||||
EventCoroutines.Add(inst);
|
||||
} else {
|
||||
TickingCoroutines.Add(inst);
|
||||
}
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
public static void InvokeLater(IWait wait, Action action) {
|
||||
public static void InvokeLater(Wait wait, Action action) {
|
||||
Start(InvokeLaterImpl(wait, action));
|
||||
}
|
||||
|
||||
|
@ -29,7 +33,7 @@ namespace Coroutine {
|
|||
var coroutine = TickingCoroutines[i];
|
||||
if (coroutine.Tick(deltaSeconds)) {
|
||||
TickingCoroutines.RemoveAt(i);
|
||||
} else if (coroutine.GetCurrentType() != WaitType.Tick) {
|
||||
} else if (coroutine.IsWaitingForEvent()) {
|
||||
TickingCoroutines.RemoveAt(i);
|
||||
EventCoroutines.Add(coroutine);
|
||||
}
|
||||
|
@ -41,7 +45,7 @@ namespace Coroutine {
|
|||
var coroutine = EventCoroutines[i];
|
||||
if (coroutine.OnEvent(evt)) {
|
||||
EventCoroutines.RemoveAt(i);
|
||||
} else if (coroutine.GetCurrentType() != WaitType.Event) {
|
||||
} else if (!coroutine.IsWaitingForEvent()) {
|
||||
EventCoroutines.RemoveAt(i);
|
||||
TickingCoroutines.Add(coroutine);
|
||||
}
|
||||
|
@ -52,7 +56,7 @@ namespace Coroutine {
|
|||
return TickingCoroutines.Concat(EventCoroutines);
|
||||
}
|
||||
|
||||
private static IEnumerator<IWait> InvokeLaterImpl(IWait wait, Action action) {
|
||||
private static IEnumerator<Wait> InvokeLaterImpl(Wait wait, Action action) {
|
||||
yield return wait;
|
||||
action();
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
namespace Coroutine {
|
||||
public interface IWait {
|
||||
|
||||
WaitType GetWaitType();
|
||||
|
||||
bool Tick(double deltaSeconds);
|
||||
|
||||
bool OnEvent(Event evt);
|
||||
|
||||
}
|
||||
|
||||
public enum WaitType {
|
||||
|
||||
Tick,
|
||||
Event
|
||||
|
||||
}
|
||||
}
|
36
Coroutine/Wait.cs
Normal file
36
Coroutine/Wait.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
|
||||
namespace Coroutine {
|
||||
public struct Wait {
|
||||
|
||||
private readonly Event evt;
|
||||
private double seconds;
|
||||
|
||||
public Wait(Event evt) {
|
||||
this.evt = evt;
|
||||
this.seconds = 0;
|
||||
}
|
||||
|
||||
public Wait(double seconds) {
|
||||
this.seconds = seconds;
|
||||
this.evt = null;
|
||||
}
|
||||
|
||||
public Wait(TimeSpan time) : this(time.TotalSeconds) {
|
||||
}
|
||||
|
||||
internal bool Tick(double deltaSeconds) {
|
||||
this.seconds -= deltaSeconds;
|
||||
return this.seconds <= 0;
|
||||
}
|
||||
|
||||
internal bool OnEvent(Event evt) {
|
||||
return evt == this.evt;
|
||||
}
|
||||
|
||||
internal bool IsWaitingForEvent() {
|
||||
return this.evt != null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Coroutine {
|
||||
public struct WaitEvent : IWait {
|
||||
|
||||
private readonly Event evt;
|
||||
|
||||
public WaitEvent(Event evt) {
|
||||
this.evt = evt;
|
||||
}
|
||||
|
||||
public WaitType GetWaitType() {
|
||||
return WaitType.Event;
|
||||
}
|
||||
|
||||
public bool Tick(double deltaSeconds) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool OnEvent(Event evt) {
|
||||
return evt == this.evt;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Coroutine {
|
||||
public struct WaitSeconds : IWait {
|
||||
|
||||
private double seconds;
|
||||
|
||||
public WaitSeconds(double seconds) {
|
||||
this.seconds = seconds;
|
||||
}
|
||||
|
||||
public WaitType GetWaitType() {
|
||||
return WaitType.Tick;
|
||||
}
|
||||
|
||||
public bool Tick(double deltaSeconds) {
|
||||
this.seconds -= deltaSeconds;
|
||||
return this.seconds <= 0;
|
||||
}
|
||||
|
||||
public bool OnEvent(Event evt) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -14,11 +14,11 @@ namespace Test {
|
|||
|
||||
CoroutineHandler.Start(EmptyCoroutine());
|
||||
|
||||
CoroutineHandler.InvokeLater(new WaitSeconds(10), () => {
|
||||
CoroutineHandler.InvokeLater(new Wait(10), () => {
|
||||
Console.WriteLine("Raising test event");
|
||||
CoroutineHandler.RaiseEvent(TestEvent);
|
||||
});
|
||||
CoroutineHandler.InvokeLater(new WaitEvent(TestEvent), () => Console.WriteLine("Test event received"));
|
||||
CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("Test event received"));
|
||||
|
||||
var lastTime = DateTime.Now;
|
||||
while (true) {
|
||||
|
@ -29,24 +29,24 @@ namespace Test {
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerator<IWait> WaitSeconds() {
|
||||
private static IEnumerator<Wait> WaitSeconds() {
|
||||
Console.WriteLine("First thing " + DateTime.Now);
|
||||
yield return new WaitSeconds(1);
|
||||
yield return new Wait(1);
|
||||
Console.WriteLine("After 1 second " + DateTime.Now);
|
||||
yield return new WaitSeconds(9);
|
||||
yield return new Wait(9);
|
||||
Console.WriteLine("After 10 seconds " + DateTime.Now);
|
||||
yield return new WaitSeconds(5);
|
||||
yield return new Wait(5);
|
||||
Console.WriteLine("After 5 more seconds " + DateTime.Now);
|
||||
yield return new WaitSeconds(10);
|
||||
yield return new Wait(10);
|
||||
Console.WriteLine("After 10 more seconds " + DateTime.Now);
|
||||
|
||||
yield return new WaitSeconds(20);
|
||||
yield return new Wait(20);
|
||||
Console.WriteLine("First coroutine done");
|
||||
}
|
||||
|
||||
private static IEnumerator<IWait> PrintEvery10Seconds(ActiveCoroutine first) {
|
||||
private static IEnumerator<Wait> PrintEvery10Seconds(ActiveCoroutine first) {
|
||||
while (true) {
|
||||
yield return new WaitSeconds(10);
|
||||
yield return new Wait(10);
|
||||
Console.WriteLine("The time is " + DateTime.Now);
|
||||
if (first.IsFinished) {
|
||||
Console.WriteLine("By the way, the first coroutine has finished!");
|
||||
|
@ -55,7 +55,7 @@ namespace Test {
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerator<IWait> EmptyCoroutine() {
|
||||
private static IEnumerator<Wait> EmptyCoroutine() {
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue