221 lines
5.5 KiB
ObjectPascal
221 lines
5.5 KiB
ObjectPascal
unit Myc.Lazy;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
Myc.Signals;
|
|
|
|
type
|
|
TMutable<T> = record
|
|
type
|
|
IMutable = interface
|
|
{$REGION 'property access'}
|
|
function GetChanged: TSignal;
|
|
function GetValue: T;
|
|
{$ENDREGION}
|
|
property Changed: TSignal read GetChanged;
|
|
property Value: T read GetValue;
|
|
end;
|
|
|
|
{$REGION 'private'}
|
|
strict private
|
|
class var
|
|
FNull: IMutable;
|
|
class constructor CreateClass;
|
|
|
|
private
|
|
FMutable: IMutable;
|
|
function GetChanged: TSignal; inline;
|
|
function GetValue: T; inline;
|
|
{$ENDREGION}
|
|
public
|
|
constructor Create(const AMutable: IMutable);
|
|
class operator Initialize(out Dest: TMutable<T>);
|
|
class operator Implicit(const A: IMutable): TMutable<T>; overload;
|
|
class operator Implicit(const A: TMutable<T>): IMutable; overload;
|
|
|
|
class property Null: IMutable read FNull;
|
|
|
|
class function Construct(const Changing: TSignal; const Proc: TFunc<T>): TMutable<T>; overload; static;
|
|
class function Constant(const Value: T): TMutable<T>; overload; static;
|
|
|
|
property Value: T read GetValue;
|
|
property Changed: TSignal read GetChanged;
|
|
end;
|
|
|
|
TWriteable<T> = record
|
|
type
|
|
IWriteable = interface(TMutable<T>.IMutable)
|
|
procedure SetValue(const Value: T);
|
|
function Exchange(const Value: T): T;
|
|
end;
|
|
|
|
{$REGION 'private'}
|
|
private
|
|
FWriteable: IWriteable;
|
|
function GetChanged: TSignal; inline;
|
|
function GetValue: T; inline;
|
|
procedure SetValue(const Value: T);
|
|
{$ENDREGION}
|
|
public
|
|
constructor Create(const AWriteable: IWriteable);
|
|
class operator Implicit(const A: IWriteable): TWriteable<T>; overload;
|
|
class operator Implicit(const A: TWriteable<T>): IWriteable; overload;
|
|
|
|
class function CreateWriteable: TWriteable<T>; overload; static;
|
|
class function CreateWriteable(const Init: T): TWriteable<T>; overload; static;
|
|
|
|
function Protect: TWriteable<T>;
|
|
|
|
function AsMutable: TMutable<T>;
|
|
|
|
property Value: T read GetValue write SetValue;
|
|
property Changed: TSignal read GetChanged;
|
|
end;
|
|
|
|
TLazy<T> = record
|
|
private
|
|
FMutable: TMutable<T>;
|
|
FChanged: TFlag;
|
|
FChangeState: TSignal.TSubscription;
|
|
function GetValue: T; inline;
|
|
public
|
|
constructor Create(const AMutable: TMutable<T>);
|
|
function Update: Boolean;
|
|
property Value: T read GetValue;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Myc.Core.Lazy;
|
|
|
|
{ TMutable<T> }
|
|
|
|
constructor TMutable<T>.Create(const AMutable: IMutable);
|
|
begin
|
|
if Assigned(AMutable) then
|
|
FMutable := AMutable;
|
|
end;
|
|
|
|
class constructor TMutable<T>.CreateClass;
|
|
begin
|
|
FNull := TMycNullMutable<T>.Create(Default(T));
|
|
end;
|
|
|
|
class function TMutable<T>.Constant(const Value: T): TMutable<T>;
|
|
begin
|
|
Result := TMycNullMutable<T>.Create(Value);
|
|
end;
|
|
|
|
class function TMutable<T>.Construct(const Changing: TSignal; const Proc: TFunc<T>): TMutable<T>;
|
|
begin
|
|
Result := TMycFuncMutable<T>.Create(Changing, Proc);
|
|
end;
|
|
|
|
function TMutable<T>.GetChanged: TSignal;
|
|
begin
|
|
Result := FMutable.Changed;
|
|
end;
|
|
|
|
function TMutable<T>.GetValue: T;
|
|
begin
|
|
Result := FMutable.Value;
|
|
end;
|
|
|
|
class operator TMutable<T>.Implicit(const A: TMutable<T>): IMutable;
|
|
begin
|
|
Result := A.FMutable;
|
|
end;
|
|
|
|
class operator TMutable<T>.Implicit(const A: IMutable): TMutable<T>;
|
|
begin
|
|
Result.Create(A);
|
|
end;
|
|
|
|
class operator TMutable<T>.Initialize(out Dest: TMutable<T>);
|
|
begin
|
|
Dest.FMutable := FNull;
|
|
end;
|
|
|
|
{ TWriteable<T> }
|
|
|
|
constructor TWriteable<T>.Create(const AWriteable: IWriteable);
|
|
begin
|
|
FWriteable := AWriteable;
|
|
Assert(Assigned(FWriteable));
|
|
end;
|
|
|
|
function TWriteable<T>.AsMutable: TMutable<T>;
|
|
begin
|
|
Result.Create(FWriteable);
|
|
end;
|
|
|
|
class function TWriteable<T>.CreateWriteable: TWriteable<T>;
|
|
begin
|
|
Result := CreateWriteable(Default(T));
|
|
end;
|
|
|
|
class function TWriteable<T>.CreateWriteable(const Init: T): TWriteable<T>;
|
|
begin
|
|
Result := TMycWriteableMutable<T>.Create(Init);
|
|
end;
|
|
|
|
function TWriteable<T>.GetChanged: TSignal;
|
|
begin
|
|
Result := FWriteable.Changed;
|
|
end;
|
|
|
|
function TWriteable<T>.GetValue: T;
|
|
begin
|
|
Result := FWriteable.Value;
|
|
end;
|
|
|
|
function TWriteable<T>.Protect: TWriteable<T>;
|
|
begin
|
|
if not (FWriteable is TMycProtectedMutable<T>) then
|
|
Result := TMycProtectedMutable<T>.Create(FWriteable)
|
|
else
|
|
Result := FWriteable;
|
|
end;
|
|
|
|
procedure TWriteable<T>.SetValue(const Value: T);
|
|
begin
|
|
FWriteable.SetValue(Value);
|
|
end;
|
|
|
|
class operator TWriteable<T>.Implicit(const A: IWriteable): TWriteable<T>;
|
|
begin
|
|
Result.Create(A);
|
|
end;
|
|
|
|
class operator TWriteable<T>.Implicit(const A: TWriteable<T>): IWriteable;
|
|
begin
|
|
Result := A.FWriteable;
|
|
end;
|
|
|
|
{ TLazy<T> }
|
|
|
|
constructor TLazy<T>.Create(const AMutable: TMutable<T>);
|
|
begin
|
|
FMutable := AMutable;
|
|
FChanged := TFlag.CreateFlag;
|
|
FChanged.Notify;
|
|
FChangeState := AMutable.Changed.Subscribe(FChanged);
|
|
end;
|
|
|
|
function TLazy<T>.GetValue: T;
|
|
begin
|
|
Result := FMutable.Value;
|
|
end;
|
|
|
|
function TLazy<T>.Update: Boolean;
|
|
begin
|
|
Result := FChanged.State.IsSet;
|
|
if Result then
|
|
FChanged.Reset;
|
|
end;
|
|
|
|
end.
|