rename UniTask to DepthFirstScheduler

This commit is contained in:
ousttrue
2018-08-09 12:44:08 +09:00
parent 000248e729
commit af96524b4a
27 changed files with 16 additions and 19 deletions

View File

@@ -0,0 +1,177 @@
using System;
using System.Collections;
namespace DepthFirstScheduler
{
public enum ExecutionStatus
{
Unknown,
Done,
Continue, // coroutine or schedulable
Error,
}
public interface IFunctor<T>
{
T GetResult();
Exception GetError();
ExecutionStatus Execute();
}
#region Functor
public class Functor<T> : IFunctor<T>
{
T m_result;
public T GetResult()
{
return m_result;
}
Exception m_error;
public Exception GetError()
{
return m_error;
}
Action m_pred;
public Functor(Func<T> func)
{
m_pred = () => m_result = func();
}
public ExecutionStatus Execute()
{
try
{
m_pred();
return ExecutionStatus.Done;
}
catch (Exception ex)
{
m_error = ex;
return ExecutionStatus.Error;
}
}
}
public static class Functor
{
/// <summary>
/// 引数の型を隠蔽した実行器を生成する
/// </summary>
/// <typeparam name="S">引数の型</typeparam>
/// <typeparam name="T">結果の型</typeparam>
/// <param name="arg"></param>
/// <param name="pred"></param>
/// <returns></returns>
public static Functor<T> Create<S, T>(Func<S> arg, Func<S, T> pred)
{
return new Functor<T>(() => pred(arg()));
}
}
#endregion
#region CoroutineFunctor
public class CoroutineFunctor<T> : IFunctor<T>
{
T m_result;
public T GetResult()
{
return m_result;
}
Exception m_error;
public Exception GetError()
{
return m_error;
}
Func<T> m_arg;
Func<T, IEnumerator> m_starter;
IEnumerator m_it;
public CoroutineFunctor(Func<T> arg, Func<T, IEnumerator> starter)
{
m_arg = arg;
m_starter = starter;
}
public ExecutionStatus Execute()
{
if (m_it == null)
{
m_result = m_arg();
m_it = m_starter(m_result);
}
try
{
if (m_it.MoveNext())
{
return ExecutionStatus.Continue;
}
else
{
return ExecutionStatus.Done;
}
}
catch(Exception ex)
{
m_error = ex;
return ExecutionStatus.Error;
}
}
}
public static class CoroutineFunctor
{
public static CoroutineFunctor<T> Create<T>(Func<T> arg, Func<T, IEnumerator> starter)
{
return new CoroutineFunctor<T>(arg, starter);
}
}
#endregion
/*
public class SchedulableFunctor<T> : IFunctor<T>
{
Schedulable<T> m_schedulable;
Func<Schedulable<T>> m_starter;
TaskChain m_chain;
public SchedulableFunctor(Func<Schedulable<T>> starter)
{
m_starter = starter;
}
public ExecutionStatus Execute()
{
if (m_chain == null)
{
m_schedulable = m_starter();
m_chain = TaskChain.Schedule(m_schedulable, ex => m_error = ex);
}
return m_chain.Next();
}
Exception m_error;
public Exception GetError()
{
return m_error;
}
public T GetResult()
{
return m_schedulable.Func.GetResult();
}
}
public static class SchedulableFunctor
{
public static SchedulableFunctor<T> Create<T>(Func<Schedulable<T>> starter)
{
return new SchedulableFunctor<T>(starter);
}
}
*/
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c320f3f577dde634a871dc88266c2a20
timeCreated: 1520084196
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using System.Collections;
using System.Collections.Generic;
namespace DepthFirstScheduler
{
public class LockQueue<T> where T : class
{
List<T> m_queue = new List<T>();
public int Count
{
get
{
lock (((ICollection)m_queue).SyncRoot)
{
return m_queue.Count;
}
}
}
public void Enqueue(T t)
{
lock (((ICollection)m_queue).SyncRoot)
{
m_queue.Add(t);
}
}
public T Dequeue(out int remain)
{
lock (((ICollection)m_queue).SyncRoot)
{
if (m_queue.Count == 0)
{
remain = 0;
return null;
}
var item = m_queue[0];
m_queue.RemoveAt(0);
remain = m_queue.Count;
return item;
}
}
public T Dequeue()
{
lock (((ICollection)m_queue).SyncRoot)
{
if (m_queue.Count == 0) return null;
var item = m_queue[0];
m_queue.RemoveAt(0);
return item;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f6b1eb436e400704ab6e2ad6eff29f4b
timeCreated: 1519978475
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace DepthFirstScheduler
{
/// <summary>
/// UniRxのMainThreadDispatcherを参考にした。
/// * https://github.com/neuecc/UniRx/blob/master/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs
/// </summary>
public class MainThreadDispatcher : MonoBehaviour
{
[Header("Debug")]
public int TaskCount;
IEnumerable<Transform> Ancestors(Transform t)
{
yield return t;
if (t.parent != null)
{
foreach (var x in Ancestors(t.parent))
{
yield return x;
}
}
}
private void Update()
{
TaskCount = Scheduler.MainThread.UpdateAndGetTaskCount();
}
static MainThreadDispatcher instance;
static bool initialized;
static bool isQuitting = false;
public static bool IsInitialized
{
get { return initialized && instance != null; }
}
[ThreadStatic]
static object mainThreadToken;
public static MainThreadDispatcher Instance
{
get
{
Initialize();
return instance;
}
}
public static void Initialize()
{
if (!initialized)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
return;
}
#endif
MainThreadDispatcher dispatcher = null;
try
{
dispatcher = GameObject.FindObjectOfType<MainThreadDispatcher>();
}
catch
{
// Throw exception when calling from a worker thread.
var ex = new Exception("UniRx requires a MainThreadDispatcher component created on the main thread. Make sure it is added to the scene before calling UniRx from a worker thread.");
UnityEngine.Debug.LogException(ex);
throw ex;
}
if (isQuitting)
{
// don't create new instance after quitting
// avoid "Some objects were not cleaned up when closing the scene find target" error.
return;
}
if (dispatcher == null)
{
// awake call immediately from UnityEngine
new GameObject("MainThreadDispatcher").AddComponent<MainThreadDispatcher>();
}
else
{
dispatcher.Awake(); // force awake
}
}
}
public static bool IsInMainThread
{
get
{
return (mainThreadToken != null);
}
}
void Awake()
{
if (instance == null)
{
Debug.Log("Initialize UniTask.MainThredDispatcher");
instance = this;
mainThreadToken = new object();
initialized = true;
DontDestroyOnLoad(gameObject);
}
else
{
if (this != instance)
{
Debug.LogWarning("There is already a MainThreadDispatcher in the scene.");
}
}
}
void OnDestroy()
{
if (instance == this)
{
instance = GameObject.FindObjectOfType<MainThreadDispatcher>();
initialized = instance != null;
}
if (Scheduler.SingleWorkerThread != null)
{
Scheduler.SingleWorkerThread.Dispose();
}
}
void OnApplicationQuit()
{
isQuitting = true;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b030a9507e46dd3488c080be0227b219
timeCreated: 1519977925
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Threading;
namespace DepthFirstScheduler
{
/// <summary>
/// http://blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx
///
/// <20>I<EFBFBD><49><EFBFBD><EFBFBD><EFBFBD>ʒm<CA92><6D><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD>null<6C>𓊓<EFBFBD><F0938A93><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD>
/// </summary>
/// <typeparam name="T"></typeparam>
public class MonitorQueue<T>
where T : class
{
private Int32 _count = 0;
public Int32 Count
{
get
{
return _count;
}
}
private Queue<T> _queue = new Queue<T>();
public T Dequeue()
{
lock (_queue)
{
while (_count <= 0) Monitor.Wait(_queue);
_count--;
return _queue.Dequeue();
}
}
public void Enqueue(T data)
{
lock (_queue)
{
_queue.Enqueue(data);
_count++;
Monitor.Pulse(_queue);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5e968e04ff53e1c4a9a2869b7cf76055
timeCreated: 1519990411
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,243 @@
using System;
using System.Collections;
using System.Collections.Generic;
#if (NET_4_6 && UNITY_2017_1_OR_NEWER)
using System.Threading.Tasks;
#endif
namespace DepthFirstScheduler
{
public interface ISchedulable
{
/// <returns>実行が終了したかCoroutineの実行が一回で終わらない場合がある</returns>
ExecutionStatus Execute();
Exception GetError();
IScheduler Schedulder { get; }
ISchedulable Parent { get; set; }
void AddChild(ISchedulable child);
IEnumerable<ISchedulable> Traverse();
}
public static class ISchedulableExtensions
{
public static ISchedulable GetRoot(this ISchedulable self)
{
var current = self;
while (current.Parent != null)
{
current = current.Parent;
}
return current;
}
}
public class Schedulable<T> : ISchedulable
{
List<ISchedulable> m_children = new List<ISchedulable>();
public void AddChild(ISchedulable child)
{
child.Parent = this;
m_children.Add(child);
}
public IEnumerable<ISchedulable> Traverse()
{
yield return this;
foreach (var child in m_children)
{
foreach (var x in child.Traverse())
{
yield return x;
}
}
}
public ISchedulable Parent
{
get;
set;
}
public IScheduler Schedulder
{
get;
private set;
}
public IFunctor<T> Func
{
get;
private set;
}
public Exception GetError()
{
return Func.GetError();
}
public Schedulable()
{
}
public Schedulable(IScheduler scheduler, IFunctor<T> func)
{
Schedulder = scheduler;
Func = func;
}
public ExecutionStatus Execute()
{
if (Func == null)
{
return ExecutionStatus.Done;
}
return Func.Execute();
}
public Schedulable<Unit> AddTask(IScheduler scheduler, Action pred)
{
return AddTask(scheduler, () => { pred(); return Unit.Default; });
}
public Schedulable<U> AddTask<U>(IScheduler scheduler, Func<U> pred)
{
var schedulable = new Schedulable<U>(scheduler, Functor.Create(() => Unit.Default, _ => pred()));
AddChild(schedulable);
return schedulable;
}
public Schedulable<T> AddCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
{
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
var schedulable = new Schedulable<T>(scheduler, func);
AddChild(schedulable);
return schedulable;
}
public Schedulable<Unit> ContinueWith(IScheduler scheduler, Action<T> pred)
{
return ContinueWith(scheduler, t => { pred(t); return Unit.Default; });
}
public Schedulable<U> ContinueWith<U>(IScheduler scheduler, Func<T, U> pred)
{
Func<T> getResult = null;
if (Func != null)
{
getResult = Func.GetResult;
}
var func = Functor.Create(getResult, pred);
var schedulable = new Schedulable<U>(scheduler, func);
Parent.AddChild(schedulable);
return schedulable;
}
public Schedulable<T> ContinueWithCoroutine(IScheduler scheduler, Func<IEnumerator> starter)
{
var func = CoroutineFunctor.Create(() => default(T), _ => starter());
var schedulable = new Schedulable<T>(scheduler, func);
Parent.AddChild(schedulable);
return schedulable;
}
public Schedulable<Unit> OnExecute(IScheduler scheduler, Action<Schedulable<Unit>> pred)
{
Func<T> getResult = null;
if (Func != null)
{
getResult = Func.GetResult;
}
var schedulable = new Schedulable<Unit>();
schedulable.Func = Functor.Create(getResult, _ => { pred(schedulable); return Unit.Default; });
Parent.AddChild(schedulable);
return schedulable;
}
/*
public ISchedulable<U> ContinueWithNested<U>(Func<T, ISchedulable<U>> starter, IScheduler scheduler)
{
var func = SchedulableFunctor.Create(() => starter(Func.GetResult()));
return new Schedulable<U>(scheduler, func, this);
}
*/
}
public static class Schedulable
{
public static Schedulable<Unit> Create()
{
return new Schedulable<Unit>();
}
}
public static class SchedulableExtensions
{
public static void Subscribe<T>(
this Schedulable<T> schedulable,
IScheduler scheduler,
Action<T> onCompleted,
Action<Exception> onError)
{
schedulable.ContinueWith(scheduler, onCompleted);
TaskChain.Schedule(schedulable.GetRoot(), onError);
}
#if (NET_4_6 && UNITY_2017_1_OR_NEWER)
public static Task<T> ToTask<T>(this Schedulable<T> schedulable)
{
return ToTask(schedulable, Scheduler.MainThread);
}
public static Task<T> ToTask<T>(this Schedulable<T> schedulable, IScheduler scheduler)
{
var tcs = new TaskCompletionSource<T>();
schedulable.Subscribe(scheduler, r => tcs.TrySetResult(r), ex => tcs.TrySetException(ex));
return tcs.Task;
}
#endif
/*
public static ISchedulable<Unit> Sequencial<T>(IEnumerable<ISchedulable<T>> schedulables, Action<T> mergePred)
{
var it = schedulables.GetEnumerator();
ISchedulable<Unit> last = Schedulable.Start(null, () => Unit.Default);
while (it.MoveNext())
{
var current = it.Current;
var merger = current.ContinueWith(result =>
{
mergePred(result);
return Unit.Default;
});
if (last != null)
{
// 連結
current.EnumParents().Last().Parent = last;
}
last = merger;
}
return last;
}
*/
/*
public static ISchedulable<S> MergeCollection<S, T, U>(this ISchedulable<S> schedulable,
Func<S, IEnumerable<T>> extractor,
Func<S, T, U> pred,
Action<S, U> merger,
IScheduler scheduler = null)
{
return schedulable.ContinueWithNested(x =>
{
var schedulables = extractor(x).Select(y => Schedulable.Start(scheduler, () => pred(x, y)));
return Sequencial(schedulables, z => merger(x, z)).ContinueWith(_ => x);
}, scheduler);
}
*/
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 45e21e7db278f344fbaeffc4c4b82b1e
timeCreated: 1519981307
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
using System;
namespace DepthFirstScheduler
{
public interface IScheduler : IDisposable
{
void Enqueue(TaskChain item);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5a160dc164df4094dbbc892055ac82ae
timeCreated: 1520084097
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0700fb042f010694782d238049678651
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace DepthFirstScheduler
{
public static partial class Scheduler
{
private static IScheduler currentThread;
public static IScheduler CurrentThread
{
get { return currentThread ?? (currentThread = new CurrentThreadScheduler()); }
}
public class CurrentThreadScheduler : IScheduler
{
[ThreadStatic]
private static Queue<TaskChain> queue;
private static Queue<TaskChain> GetQueue()
{
return queue;
}
private static void SetQueue(Queue<TaskChain> newQueue)
{
queue = newQueue;
}
public void Enqueue(TaskChain item)
{
var q = GetQueue();
if (q == null)
{
q = new Queue<TaskChain>(5);
q.Enqueue(item);
SetQueue(q);
try
{
Trampoline.Run(q);
}
finally
{
SetQueue(null);
}
}
else
{
q.Enqueue(item);
}
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
var queue = GetQueue();
if (queue != null) queue.Clear();
SetQueue(null);
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
static class Trampoline
{
public static void Run(Queue<TaskChain> queue)
{
while (queue.Count > 0)
{
var chain = queue.Dequeue();
while (true)
{
var status = chain.Next();
if (status != ExecutionStatus.Continue)
{
break;
}
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21979cc7137a17d4ea8b6202381a02d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
namespace DepthFirstScheduler
{
public static partial class Scheduler
{
private static StepScheduler mainThread;
public static StepScheduler MainThread
{
get
{
if (mainThread != null) return mainThread;
mainThread = new StepScheduler();
MainThreadDispatcher.Initialize();
return mainThread;
}
}
public class StepScheduler : IScheduler
{
LockQueue<TaskChain> m_taskQueue = new LockQueue<TaskChain>();
public void Enqueue(TaskChain item)
{
m_taskQueue.Enqueue(item);
}
TaskChain m_chain;
public int UpdateAndGetTaskCount()
{
if (m_chain != null)
{
var status = m_chain.Next();
if (status == ExecutionStatus.Continue)
{
// m_item継続中
return m_taskQueue.Count;
}
m_chain = null;
}
int count;
m_chain = m_taskQueue.Dequeue(out count);
return count;
}
public void Dispose()
{
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 84161938c020c37419bc79f021f849fb
timeCreated: 1520062584
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using System;
namespace DepthFirstScheduler
{
public static partial class Scheduler
{
private static IScheduler threadPool;
public static IScheduler ThreadPool
{
get { return threadPool ?? (threadPool = new ThreadPoolScheduler()); }
}
public class ThreadPoolScheduler : IScheduler
{
public void Enqueue(TaskChain item)
{
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
{
if (item == null)
{
return;
}
while (true)
{
var status = item.Next();
if (status != ExecutionStatus.Continue)
{
break;
}
}
});
}
public void Dispose()
{
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d8a8d78a486bbdf4b95ae83d02b480d8
timeCreated: 1524110819
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,101 @@
using System;
using System.Threading;
namespace DepthFirstScheduler
{
public static partial class Scheduler
{
private static IScheduler singleWorkerThread;
public static IScheduler SingleWorkerThread
{
get { return singleWorkerThread ?? (singleWorkerThread = new ThreadScheduler()); }
}
public class ThreadScheduler : IScheduler
{
MonitorQueue<TaskChain> m_queue = new MonitorQueue<TaskChain>();
Thread m_thread;
public ThreadScheduler()
{
// start worker thread
m_thread = new Thread(new ParameterizedThreadStart(Worker));
m_thread.Start(m_queue);
}
static void Worker(Object arg)
{
MonitorQueue<TaskChain> queue = (MonitorQueue<TaskChain>)arg;
while (true)
{
var chain = queue.Dequeue();
if (chain == null)
{
break;
}
while (true)
{
var status = chain.Next();
if (status != ExecutionStatus.Continue)
{
break;
}
}
}
// end
}
public void Enqueue(TaskChain item)
{
m_queue.Enqueue(item);
}
#region IDisposable Support
private bool disposedValue = false; // 重複する呼び出しを検出するには
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: マネージ状態を破棄します (マネージ オブジェクト)。
if (m_thread != null)
{
m_queue.Enqueue(null);
m_thread.Join();
m_thread = null;
}
}
// TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下のファイナライザーをオーバーライドします。
// TODO: 大きなフィールドを null に設定します。
disposedValue = true;
}
}
// TODO: 上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。
// ~ThreadScheduler() {
// // このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
// Dispose(false);
// }
// このコードは、破棄可能なパターンを正しく実装できるように追加されました。
public void Dispose()
{
// このコードを変更しないでください。クリーンアップ コードを上の Dispose(bool disposing) に記述します。
Dispose(true);
// TODO: 上のファイナライザーがオーバーライドされる場合は、次の行のコメントを解除してください。
// GC.SuppressFinalize(this);
}
#endregion
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8df1de98bdc0b534bbe68e8f2f8a858f
timeCreated: 1520062592
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
using System;
using System.Linq;
using System.Collections.Generic;
namespace DepthFirstScheduler
{
public enum ChainStatus
{
Unknown,
Continue,
Done,
Error,
}
public class TaskChain
{
public IEnumerator<ISchedulable> Enumerator;
public Action<Exception> OnError;
public ChainStatus ChainStatus;
public static TaskChain Schedule(ISchedulable schedulable, Action<Exception> onError)
{
var item = new TaskChain
{
Enumerator = schedulable.Traverse().GetEnumerator(),
OnError = onError
};
if (item.Enumerator.MoveNext())
{
if (item.Enumerator.Current.Schedulder == null)
{
// default
Scheduler.MainThread.Enqueue(item);
}
else
{
item.Enumerator.Current.Schedulder.Enqueue(item);
}
}
return item;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public ExecutionStatus Next()
{
if (this.ChainStatus == ChainStatus.Done
|| this.ChainStatus== ChainStatus.Error)
{
return ExecutionStatus.Done;
}
{
var status = Enumerator.Current.Execute();
if (status == ExecutionStatus.Error)
{
ChainStatus = ChainStatus.Error;
OnError(Enumerator.Current.GetError());
}
if (status == ExecutionStatus.Continue)
{
// 中断(coroutine)
ChainStatus = ChainStatus.Continue;
return ExecutionStatus.Continue;
}
}
if (!Enumerator.MoveNext())
{
// 終了
ChainStatus = ChainStatus.Done;
return ExecutionStatus.Done;
}
if (Enumerator.Current.Schedulder != null)
{
// Scheduleして中断
ChainStatus = ChainStatus.Continue;
Enumerator.Current.Schedulder.Enqueue(this);
return ExecutionStatus.Done;
}
return Next();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 38fc7e076ba93a847ad72d3d459d06b6
timeCreated: 1520084019
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
using System;
namespace DepthFirstScheduler
{
[Serializable]
public struct Unit : IEquatable<Unit>
{
static readonly Unit @default = new Unit();
public static Unit Default { get { return @default; } }
public static bool operator ==(Unit first, Unit second)
{
return true;
}
public static bool operator !=(Unit first, Unit second)
{
return false;
}
public bool Equals(Unit other)
{
return true;
}
public override bool Equals(object obj)
{
return obj is Unit;
}
public override int GetHashCode()
{
return 0;
}
public override string ToString()
{
return "()";
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 98bd42f8c3a895d4bac6cbcf523878bb
timeCreated: 1520081817
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: