Files
MycLib/Src/Myc.Futures.pas
T
Michael Schimmel 644b6074d6 Chart
2025-07-03 21:27:10 +02:00

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.