242 lines
6.6 KiB
ObjectPascal
242 lines
6.6 KiB
ObjectPascal
unit Myc.Futures;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
Myc.Signals,
|
|
Myc.TaskManager;
|
|
|
|
type
|
|
// Represents the eventual Value of an asynchronous operation.
|
|
TFuture<T> = record
|
|
type
|
|
IFuture = interface
|
|
{$REGION 'property access'}
|
|
function GetValue: T;
|
|
function GetDone: TState;
|
|
{$ENDREGION}
|
|
// Provides access to the computed Value.
|
|
property Value: T read GetValue;
|
|
// Provides access to the completion state.
|
|
property Done: TState read GetDone;
|
|
end;
|
|
|
|
TFuncConst<S, TResult> = reference to function(const Arg1: S): TResult;
|
|
TProcConst<S, TResult> = reference to function(const Arg1: S): TResult;
|
|
|
|
{$REGION 'private'}
|
|
strict private
|
|
class var
|
|
FNull: IFuture;
|
|
|
|
class constructor CreateClass;
|
|
private
|
|
FFuture: IFuture;
|
|
function GetDone: TState.IState; inline;
|
|
function GetValue: T; inline;
|
|
{$ENDREGION}
|
|
public
|
|
constructor Create(const AFuture: IFuture);
|
|
|
|
class operator Initialize(out Dest: TFuture<T>);
|
|
class operator Implicit(const A: IFuture): TFuture<T>; overload;
|
|
class operator Implicit(const A: TFuture<T>): IFuture; overload;
|
|
|
|
class function Construct(const Proc: TFunc<T>): TFuture<T>; overload; static;
|
|
class function Construct(const Gate: TState; const Proc: TFunc<T>): TFuture<T>; overload; static;
|
|
class function Construct(const ConstVal: T): TFuture<T>; overload; static;
|
|
|
|
class property Null: IFuture read FNull;
|
|
|
|
procedure Manage;
|
|
|
|
function Chain<S>(const Proc: TFunc<T, S>): TFuture<S>; overload;
|
|
function Chain<S>(const Proc: TFuncConst<T, S>): TFuture<S>; overload;
|
|
function Chain(const Proc: TProcConst<T, TState>): TState; overload;
|
|
function WaitFor: T;
|
|
|
|
class function WhenAll<S>(const Futures: TArray<IFuture>; const Func: TFuncConst<TArray<T>, S>): TFuture<S>; static; experimental;
|
|
|
|
property Done: TState.IState read GetDone;
|
|
property Value: T read GetValue;
|
|
end;
|
|
|
|
TFuture = record
|
|
public
|
|
class function FromArray<T>(const Arr: TArray<TFuture<T>>): TFuture<TArray<T>>; static;
|
|
end;
|
|
|
|
IObjectRef<T: class> = interface
|
|
function GetObj: T;
|
|
function Pop: T;
|
|
property Obj: T read GetObj;
|
|
end;
|
|
|
|
TObjectRef<T: class> = class(TInterfacedObject, IObjectRef<T>)
|
|
private
|
|
FObj: T;
|
|
function GetObj: T;
|
|
public
|
|
constructor Create(const ARef: T);
|
|
destructor Destroy; override;
|
|
function Pop: T;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Myc.Core.Futures;
|
|
|
|
constructor TFuture<T>.Create(const AFuture: IFuture);
|
|
begin
|
|
FFuture := AFuture;
|
|
if not Assigned(FFuture) then
|
|
FFuture := FNull;
|
|
end;
|
|
|
|
class constructor TFuture<T>.CreateClass;
|
|
begin
|
|
FNull := TMycNullFuture<T>.Create(Default(T));
|
|
end;
|
|
|
|
function TFuture<T>.Chain(const Proc: TProcConst<T, TState>): TState;
|
|
begin
|
|
var cFuture := FFuture;
|
|
|
|
Result := TaskManager.RunTask(cFuture.Done, function: TState begin Result := Proc(cFuture.Value); end);
|
|
end;
|
|
|
|
function TFuture<T>.Chain<S>(const Proc: TFunc<T, S>): TFuture<S>;
|
|
begin
|
|
var cFuture := FFuture;
|
|
Result := TFuture<S>.Construct(cFuture.Done, function: S begin Result := Proc(cFuture.Value); end);
|
|
end;
|
|
|
|
function TFuture<T>.Chain<S>(const Proc: TFuncConst<T, S>): TFuture<S>;
|
|
begin
|
|
var cFuture := FFuture;
|
|
Result := TFuture<S>.Construct(cFuture.Done, function: S begin Result := Proc(cFuture.Value); end);
|
|
end;
|
|
|
|
class function TFuture<T>.Construct(const Proc: TFunc<T>): TFuture<T>;
|
|
begin
|
|
Result := TMycGateFuncFuture<T>.Create(TaskManager, nil, Proc);
|
|
end;
|
|
|
|
class function TFuture<T>.Construct(const Gate: TState; const Proc: TFunc<T>): TFuture<T>;
|
|
begin
|
|
Result := TMycGateFuncFuture<T>.Create(TaskManager, Gate, Proc);
|
|
end;
|
|
|
|
class function TFuture<T>.Construct(const ConstVal: T): TFuture<T>;
|
|
begin
|
|
Result := TMycNullFuture<T>.Create(ConstVal);
|
|
end;
|
|
|
|
function TFuture<T>.GetDone: TState.IState;
|
|
begin
|
|
Result := FFuture.Done;
|
|
end;
|
|
|
|
function TFuture<T>.GetValue: T;
|
|
begin
|
|
Result := FFuture.Value;
|
|
end;
|
|
|
|
procedure TFuture<T>.Manage;
|
|
begin
|
|
if GetTypeKind(T) = tkClass then
|
|
FFuture := TMycFutureManaged<T>.Create(FFuture);
|
|
end;
|
|
|
|
function TFuture<T>.WaitFor: T;
|
|
begin
|
|
TaskManager.WaitFor(FFuture.Done);
|
|
Result := FFuture.Value;
|
|
end;
|
|
|
|
class function TFuture<T>.WhenAll<S>(const Futures: TArray<IFuture>; const Func: TFuncConst<TArray<T>, S>): TFuture<S>;
|
|
var
|
|
DoneStates: TArray<TState>;
|
|
begin
|
|
SetLength(DoneStates, Length(Futures));
|
|
for var i := 0 to High(DoneStates) do
|
|
DoneStates[i] := Futures[i].Done;
|
|
var cFutures := Futures;
|
|
Result :=
|
|
TFuture<S>.Construct(
|
|
TState.All(DoneStates),
|
|
function: S
|
|
var
|
|
Vals: TArray<T>;
|
|
begin
|
|
SetLength(Vals, Length(cFutures));
|
|
for var i := 0 to High(Vals) do
|
|
Vals[i] := Futures[i].Value;
|
|
Result := Func(Vals);
|
|
end
|
|
);
|
|
end;
|
|
|
|
class operator TFuture<T>.Implicit(const A: IFuture): TFuture<T>;
|
|
begin
|
|
Result.Create(A);
|
|
end;
|
|
|
|
class operator TFuture<T>.Implicit(const A: TFuture<T>): IFuture;
|
|
begin
|
|
Result := A.FFuture;
|
|
end;
|
|
|
|
class operator TFuture<T>.Initialize(out Dest: TFuture<T>);
|
|
begin
|
|
Dest.FFuture := FNull;
|
|
end;
|
|
|
|
constructor TObjectRef<T>.Create(const ARef: T);
|
|
begin
|
|
inherited Create;
|
|
FObj := ARef;
|
|
end;
|
|
|
|
destructor TObjectRef<T>.Destroy;
|
|
begin
|
|
FObj.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TObjectRef<T>.GetObj: T;
|
|
begin
|
|
Result := FObj;
|
|
end;
|
|
|
|
function TObjectRef<T>.Pop: T;
|
|
begin
|
|
Result := FObj;
|
|
FreeAndNil(FObj);
|
|
end;
|
|
|
|
class function TFuture.FromArray<T>(const Arr: TArray<TFuture<T>>): TFuture<TArray<T>>;
|
|
var
|
|
DoneStates: TArray<TState>;
|
|
begin
|
|
var cFutures := Arr;
|
|
SetLength(DoneStates, Length(cFutures));
|
|
for var i := 0 to High(DoneStates) do
|
|
DoneStates[i] := cFutures[i].Done;
|
|
|
|
Result :=
|
|
TFuture<TArray<T>>.Construct(
|
|
TState.All(DoneStates),
|
|
function: TArray<T>
|
|
begin
|
|
SetLength(Result, Length(cFutures));
|
|
for var i := 0 to High(Result) do
|
|
Result[i] := cFutures[i].Value;
|
|
end
|
|
);
|
|
end;
|
|
|
|
end.
|