mirror of
https://github.com/Ellpeck/Coroutine.git
synced 2024-11-22 05:43: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 {
|
namespace Coroutine {
|
||||||
public class ActiveCoroutine {
|
public class ActiveCoroutine {
|
||||||
|
|
||||||
private readonly IEnumerator<IWait> enumerator;
|
private readonly IEnumerator<Wait> enumerator;
|
||||||
|
private Wait current;
|
||||||
|
|
||||||
public bool IsFinished { get; private set; }
|
public bool IsFinished { get; private set; }
|
||||||
public bool WasCanceled { get; private set; }
|
public bool WasCanceled { get; private set; }
|
||||||
public FinishCallback OnFinished;
|
public FinishCallback OnFinished;
|
||||||
|
|
||||||
internal ActiveCoroutine(IEnumerator<IWait> enumerator) {
|
internal ActiveCoroutine(IEnumerator<Wait> enumerator) {
|
||||||
this.enumerator = enumerator;
|
this.enumerator = enumerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +26,7 @@ namespace Coroutine {
|
||||||
|
|
||||||
internal bool Tick(double deltaSeconds) {
|
internal bool Tick(double deltaSeconds) {
|
||||||
if (!this.WasCanceled) {
|
if (!this.WasCanceled) {
|
||||||
var curr = this.enumerator.Current;
|
if (this.current.Tick(deltaSeconds))
|
||||||
if (curr != null && curr.Tick(deltaSeconds))
|
|
||||||
this.MoveNext();
|
this.MoveNext();
|
||||||
}
|
}
|
||||||
return this.IsFinished;
|
return this.IsFinished;
|
||||||
|
@ -33,22 +34,24 @@ namespace Coroutine {
|
||||||
|
|
||||||
internal bool OnEvent(Event evt) {
|
internal bool OnEvent(Event evt) {
|
||||||
if (!this.WasCanceled) {
|
if (!this.WasCanceled) {
|
||||||
var curr = this.enumerator.Current;
|
if (this.current.OnEvent(evt))
|
||||||
if (curr != null && curr.OnEvent(evt))
|
|
||||||
this.MoveNext();
|
this.MoveNext();
|
||||||
}
|
}
|
||||||
return this.IsFinished;
|
return this.IsFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MoveNext() {
|
internal bool MoveNext() {
|
||||||
if (!this.enumerator.MoveNext()) {
|
if (!this.enumerator.MoveNext()) {
|
||||||
this.IsFinished = true;
|
this.IsFinished = true;
|
||||||
this.OnFinished?.Invoke(this);
|
this.OnFinished?.Invoke(this);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
this.current = this.enumerator.Current;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal WaitType GetCurrentType() {
|
internal bool IsWaitingForEvent() {
|
||||||
return this.enumerator.Current.GetWaitType();
|
return this.current.IsWaitingForEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void FinishCallback(ActiveCoroutine coroutine);
|
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> TickingCoroutines = new List<ActiveCoroutine>();
|
||||||
private static readonly List<ActiveCoroutine> EventCoroutines = new List<ActiveCoroutine>();
|
private static readonly List<ActiveCoroutine> EventCoroutines = new List<ActiveCoroutine>();
|
||||||
|
|
||||||
public static ActiveCoroutine Start(IEnumerator<IWait> coroutine) {
|
public static ActiveCoroutine Start(IEnumerable<Wait> coroutine) {
|
||||||
if (!coroutine.MoveNext())
|
return Start(coroutine.GetEnumerator());
|
||||||
return null;
|
}
|
||||||
|
|
||||||
|
public static ActiveCoroutine Start(IEnumerator<Wait> coroutine) {
|
||||||
var inst = new ActiveCoroutine(coroutine);
|
var inst = new ActiveCoroutine(coroutine);
|
||||||
var type = inst.GetCurrentType();
|
if (inst.MoveNext()) {
|
||||||
if (type == WaitType.Tick)
|
if (inst.IsWaitingForEvent()) {
|
||||||
TickingCoroutines.Add(inst);
|
EventCoroutines.Add(inst);
|
||||||
else if (type == WaitType.Event)
|
} else {
|
||||||
EventCoroutines.Add(inst);
|
TickingCoroutines.Add(inst);
|
||||||
|
}
|
||||||
|
}
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InvokeLater(IWait wait, Action action) {
|
public static void InvokeLater(Wait wait, Action action) {
|
||||||
Start(InvokeLaterImpl(wait, action));
|
Start(InvokeLaterImpl(wait, action));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +33,7 @@ namespace Coroutine {
|
||||||
var coroutine = TickingCoroutines[i];
|
var coroutine = TickingCoroutines[i];
|
||||||
if (coroutine.Tick(deltaSeconds)) {
|
if (coroutine.Tick(deltaSeconds)) {
|
||||||
TickingCoroutines.RemoveAt(i);
|
TickingCoroutines.RemoveAt(i);
|
||||||
} else if (coroutine.GetCurrentType() != WaitType.Tick) {
|
} else if (coroutine.IsWaitingForEvent()) {
|
||||||
TickingCoroutines.RemoveAt(i);
|
TickingCoroutines.RemoveAt(i);
|
||||||
EventCoroutines.Add(coroutine);
|
EventCoroutines.Add(coroutine);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +45,7 @@ namespace Coroutine {
|
||||||
var coroutine = EventCoroutines[i];
|
var coroutine = EventCoroutines[i];
|
||||||
if (coroutine.OnEvent(evt)) {
|
if (coroutine.OnEvent(evt)) {
|
||||||
EventCoroutines.RemoveAt(i);
|
EventCoroutines.RemoveAt(i);
|
||||||
} else if (coroutine.GetCurrentType() != WaitType.Event) {
|
} else if (!coroutine.IsWaitingForEvent()) {
|
||||||
EventCoroutines.RemoveAt(i);
|
EventCoroutines.RemoveAt(i);
|
||||||
TickingCoroutines.Add(coroutine);
|
TickingCoroutines.Add(coroutine);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +56,7 @@ namespace Coroutine {
|
||||||
return TickingCoroutines.Concat(EventCoroutines);
|
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;
|
yield return wait;
|
||||||
action();
|
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.Start(EmptyCoroutine());
|
||||||
|
|
||||||
CoroutineHandler.InvokeLater(new WaitSeconds(10), () => {
|
CoroutineHandler.InvokeLater(new Wait(10), () => {
|
||||||
Console.WriteLine("Raising test event");
|
Console.WriteLine("Raising test event");
|
||||||
CoroutineHandler.RaiseEvent(TestEvent);
|
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;
|
var lastTime = DateTime.Now;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -29,24 +29,24 @@ namespace Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerator<IWait> WaitSeconds() {
|
private static IEnumerator<Wait> WaitSeconds() {
|
||||||
Console.WriteLine("First thing " + DateTime.Now);
|
Console.WriteLine("First thing " + DateTime.Now);
|
||||||
yield return new WaitSeconds(1);
|
yield return new Wait(1);
|
||||||
Console.WriteLine("After 1 second " + DateTime.Now);
|
Console.WriteLine("After 1 second " + DateTime.Now);
|
||||||
yield return new WaitSeconds(9);
|
yield return new Wait(9);
|
||||||
Console.WriteLine("After 10 seconds " + DateTime.Now);
|
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);
|
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);
|
Console.WriteLine("After 10 more seconds " + DateTime.Now);
|
||||||
|
|
||||||
yield return new WaitSeconds(20);
|
yield return new Wait(20);
|
||||||
Console.WriteLine("First coroutine done");
|
Console.WriteLine("First coroutine done");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerator<IWait> PrintEvery10Seconds(ActiveCoroutine first) {
|
private static IEnumerator<Wait> PrintEvery10Seconds(ActiveCoroutine first) {
|
||||||
while (true) {
|
while (true) {
|
||||||
yield return new WaitSeconds(10);
|
yield return new Wait(10);
|
||||||
Console.WriteLine("The time is " + DateTime.Now);
|
Console.WriteLine("The time is " + DateTime.Now);
|
||||||
if (first.IsFinished) {
|
if (first.IsFinished) {
|
||||||
Console.WriteLine("By the way, the first coroutine has finished!");
|
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;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue