holopy3/Assets/UniGLTF/DepthFirstScheduler/Schedulable.cs
Lena Biresch 490ef558ef CleanUp
2021-01-28 13:07:52 +01:00

241 lines
6.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 NoParentException: Exception
{
public NoParentException():base("No parent task can't ContinueWith or OnExecute. First AddTask")
{
}
}
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();
}
/// <summary>
/// スケジュールされたタスクをすべて即時に実行する
/// </summary>
public void ExecuteAll()
{
foreach (var x in this.GetRoot().Traverse())
{
while (true)
{
var status = x.Execute();
if (status != ExecutionStatus.Continue)
{
if (status == ExecutionStatus.Error)
{
throw x.GetError();
}
break;
}
// Coroutineタスクが継続している
}
}
}
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)
{
if (Parent == null)
{
throw new NoParentException();
}
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)
{
if (Parent == null)
{
throw new NoParentException();
}
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)
{
if (Parent == null)
{
throw new NoParentException();
}
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 static class Schedulable
{
public static Schedulable<Unit> Create()
{
return new Schedulable<Unit>().AddTask(Scheduler.CurrentThread, () =>
{
});
}
}
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
}
}