ProtectedMutable

This commit is contained in:
Michael Schimmel
2025-06-25 10:44:33 +02:00
parent e1159e883b
commit dce0d83e18
6 changed files with 110 additions and 100 deletions
+33 -55
View File
@@ -45,8 +45,8 @@ type
SymbolsComboBox: TComboBox; SymbolsComboBox: TComboBox;
LoadButton: TButton; LoadButton: TButton;
FlowLayout: TFlowLayout; FlowLayout: TFlowLayout;
ChartButton: TButton; ChartButton: TButton;
StopButton: TButton; StopButton: TButton;
procedure RandomButtonClick(Sender: TObject); procedure RandomButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject); procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject); procedure FormDestroy(Sender: TObject);
@@ -214,36 +214,41 @@ begin
var Symbol := FSymbols.WaitFor[SymbolsComboBox.ItemIndex]; var Symbol := FSymbols.WaitFor[SymbolsComboBox.ItemIndex];
var currPathData := TMutable<IObjectRef<TPathData>>.CreateProtected; var currPathData := TMutable<IObjectRef<TPathData>>.CreateWriteable.Protect;
var currLog := TMutable<String>.CreateProtected; var currLog := TMutable<String>.CreateWriteable.Protect;
const width = 1000; const width = 1000;
const incsize = 100; const incsize = 100;
begin
var arr := TDataSeries<TAskBidItem>.CreateWriteable(width);
var done :=
FServer.ProcessData(
Symbol,
FTerminate.Signal,
procedure(const Values: TArray<TDataPoint<TAskBidItem>>; const Terminated: TState)
begin
arr.Add(Values);
currLog.Value := arr.TotalCount.ToString;
var PathData := TPathData.Create; TaskManager.RunTask(
var Prices := arr; nil,
if Prices.Count > 0 then procedure
begin
var arr := TDataSeries<TAskBidItem>.CreateWriteable(width);
var done :=
FServer.ProcessData(
Symbol,
FTerminate.Signal,
procedure(const Values: TArray<TDataPoint<TAskBidItem>>; const Terminated: TState)
begin begin
PathData.MoveTo(PointF(Prices.Count - 1, Prices[0].Data.Ask)); arr.Add(Values);
for var i := 1 to Prices.Count - 1 do currLog.Value := arr.TotalCount.ToString;
PathData.LineTo(PointF(Prices.Count - i - 1, Prices[i].Data.Ask));
end;
currPathData.Value := TObjectRef<TPathData>.Create(PathData); var PathData := TPathData.Create;
end var Prices := arr;
); if Prices.Count > 0 then
FLoadDone := TState.All([FLoadDone, done]); begin
end; PathData.MoveTo(PointF(Prices.Count - 1, Prices[0].Data.Ask));
for var i := 1 to Prices.Count - 1 do
PathData.LineTo(PointF(Prices.Count - i - 1, Prices[i].Data.Ask));
end;
currPathData.Value := TObjectRef<TPathData>.Create(PathData);
end
);
FLoadDone := TState.All([FLoadDone, done]);
end
);
LogMemo.AddIdleHandler(currLog.Changed, procedure begin LogMemo.Lines.Add(Symbol + ': ' + currLog.Value); end); LogMemo.AddIdleHandler(currLog.Changed, procedure begin LogMemo.Lines.Add(Symbol + ': ' + currLog.Value); end);
@@ -251,39 +256,12 @@ begin
currPathData.Changed, currPathData.Changed,
procedure procedure
begin begin
if currPathData.Value<>nil then if currPathData.Value <> nil then
begin begin
Path1.Data.Assign( currPathData.Value.Obj ); Path1.Data.Assign(currPathData.Value.Obj);
end;
end );
(*
FLoadDone := TState.All([FLoadDone, done]);
Path1.AddIdleHandler(
curr.Changed,
procedure
begin
var Prices := curr.Value;
if Prices.Count > 0 then
begin
Path1.BeginUpdate;
try
Path1.Data.Clear;
Path1.Data.MoveTo(PointF(Path1.Width - 1, Prices[0].Data.Ask));
for var i := 1 to Prices.Count - 1 do
begin
Path1.Data.LineTo(PointF(Path1.Width - i - 1, Prices[i].Data.Ask));
end;
finally
Path1.EndUpdate;
end;
end; end;
end end
); );
*)
end; end;
end. end.
+41 -22
View File
@@ -46,6 +46,7 @@ type
function GetChanged: TSignal; function GetChanged: TSignal;
function GetValue: T; function GetValue: T;
function GetWriter: TMutable<T>.IWriter; function GetWriter: TMutable<T>.IWriter;
function Exchange(const Value: T): T;
public public
constructor Create(const AValue: T); constructor Create(const AValue: T);
procedure SetValue(const Value: T); procedure SetValue(const Value: T);
@@ -80,19 +81,19 @@ type
constructor Create(const AChanged: TSignal.ISignal; const AProc: TFunc<T>); constructor Create(const AChanged: TSignal.ISignal; const AProc: TFunc<T>);
end; end;
TMycProtectedWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriter) TMycProtectedMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriter)
private private
FValue: T; FMutable: TMutable<T>.IMutable;
FChanged: TEvent;
FLock: Integer; FLock: Integer;
protected protected
function Exchange(const Value: T): T;
function GetChanged: TSignal; function GetChanged: TSignal;
function GetValue: T; function GetValue: T;
function GetWriter: TMutable<T>.IWriter; function GetWriter: TMutable<T>.IWriter;
procedure Lock; inline; procedure Lock; inline;
procedure Release; inline; procedure Release; inline;
public public
constructor Create(const AValue: T); constructor Create(const AMutable: TMutable<T>.IMutable);
procedure SetValue(const Value: T); procedure SetValue(const Value: T);
end; end;
@@ -149,6 +150,12 @@ begin
FChanged := TEvent.CreateEvent; FChanged := TEvent.CreateEvent;
end; end;
function TMycWriteableMutable<T>.Exchange(const Value: T): T;
begin
Result := FValue;
FValue := Value;
end;
function TMycWriteableMutable<T>.GetChanged: TSignal; function TMycWriteableMutable<T>.GetChanged: TSignal;
begin begin
Result := FChanged.Signal; Result := FChanged.Signal;
@@ -239,52 +246,64 @@ begin
Result := FProc(); Result := FProc();
end; end;
{ TMycProtectedWriteableMutable<T> } { TMycProtectedMutable<T> }
constructor TMycProtectedWriteableMutable<T>.Create(const AValue: T); constructor TMycProtectedMutable<T>.Create(const AMutable: TMutable<T>.IMutable);
begin begin
inherited Create; inherited Create;
FValue := AValue; FMutable := AMutable;
FChanged := TEvent.CreateEvent;
end; end;
function TMycProtectedWriteableMutable<T>.GetChanged: TSignal; function TMycProtectedMutable<T>.Exchange(const Value: T): T;
begin
Result := FChanged.Signal;
end;
function TMycProtectedWriteableMutable<T>.GetValue: T;
begin begin
Lock; Lock;
try try
Result := FValue; Assert(FMutable.Writer <> nil);
FMutable.Writer.Exchange(Value);
finally finally
Release; Release;
end; end;
end; end;
function TMycProtectedWriteableMutable<T>.GetWriter: TMutable<T>.IWriter; function TMycProtectedMutable<T>.GetChanged: TSignal;
begin begin
Result := Self; Result := FMutable.Changed;
end; end;
procedure TMycProtectedWriteableMutable<T>.Lock; function TMycProtectedMutable<T>.GetValue: T;
begin
Lock;
try
Result := FMutable.Value;
finally
Release;
end;
end;
function TMycProtectedMutable<T>.GetWriter: TMutable<T>.IWriter;
begin
Result := nil;
if FMutable.Writer <> nil then
Result := Self;
end;
procedure TMycProtectedMutable<T>.Lock;
begin begin
while AtomicExchange(FLock, 1) = 1 do while AtomicExchange(FLock, 1) = 1 do
YieldProcessor; YieldProcessor;
end; end;
procedure TMycProtectedWriteableMutable<T>.Release; procedure TMycProtectedMutable<T>.Release;
begin begin
AtomicExchange(FLock, 0); AtomicExchange(FLock, 0);
end; end;
procedure TMycProtectedWriteableMutable<T>.SetValue(const Value: T); procedure TMycProtectedMutable<T>.SetValue(const Value: T);
begin begin
Lock; Lock;
try try
FValue := Value; Assert(FMutable.Writer <> nil);
FChanged.Notify; FMutable.Writer.SetValue(Value);
finally finally
Release; Release;
end; end;
+1 -1
View File
@@ -180,7 +180,7 @@ end;
function TObjectRef<T>.Pop: T; function TObjectRef<T>.Pop: T;
begin begin
Result := FObj; Result := FObj;
FreeAndNil( FObj ); FreeAndNil(FObj);
end; end;
end. end.
+14 -9
View File
@@ -11,6 +11,7 @@ type
type type
IWriter = interface IWriter = interface
procedure SetValue(const Value: T); procedure SetValue(const Value: T);
function Exchange(const Value: T): T;
end; end;
IMutable = interface IMutable = interface
@@ -46,9 +47,10 @@ type
class property Null: IMutable read FNull; class property Null: IMutable read FNull;
class function Construct(const Changing: TSignal; const Proc: TFunc<T>): TMutable<T>; overload; static; class function Construct(const Changing: TSignal; const Proc: TFunc<T>): TMutable<T>; overload; static;
class function CreateProtected: TMutable<T>; overload; static;
class function CreateWriteable: TMutable<T>; overload; static; class function CreateWriteable: TMutable<T>; overload; static;
function Protect: TMutable<T>;
property Value: T read GetValue write SetValue; property Value: T read GetValue write SetValue;
property Changed: TSignal read GetChanged; property Changed: TSignal read GetChanged;
property IsWriteable: Boolean read GetIsWriteable; property IsWriteable: Boolean read GetIsWriteable;
@@ -112,11 +114,6 @@ begin
Result := TMycFuncMutable<T>.Create(Changing, Proc); Result := TMycFuncMutable<T>.Create(Changing, Proc);
end; end;
class function TMutable<T>.CreateProtected: TMutable<T>;
begin
Result := TMycProtectedWriteableMutable<T>.Create(Default(T));
end;
class function TMutable<T>.CreateWriteable: TMutable<T>; class function TMutable<T>.CreateWriteable: TMutable<T>;
begin begin
Result := TMycWriteableMutable<T>.Create(Default(T)); Result := TMycWriteableMutable<T>.Create(Default(T));
@@ -129,7 +126,7 @@ end;
function TMutable<T>.GetIsWriteable: Boolean; function TMutable<T>.GetIsWriteable: Boolean;
begin begin
Result := Assigned( FMutable.Writer ); Result := Assigned(FMutable.Writer);
end; end;
function TMutable<T>.GetValue: T; function TMutable<T>.GetValue: T;
@@ -137,10 +134,18 @@ begin
Result := FMutable.Value; Result := FMutable.Value;
end; end;
function TMutable<T>.Protect: TMutable<T>;
begin
if not (FMutable is TMycProtectedMutable<T>) then
Result := TMycProtectedMutable<T>.Create(FMutable)
else
Result := FMutable;
end;
procedure TMutable<T>.SetValue(const Value: T); procedure TMutable<T>.SetValue(const Value: T);
begin begin
Assert( IsWriteable ); Assert(IsWriteable);
FMutable.Writer.SetValue( Value ); FMutable.Writer.SetValue(Value);
end; end;
class operator TMutable<T>.Implicit(const A: TMutable<T>): IMutable; class operator TMutable<T>.Implicit(const A: TMutable<T>): IMutable;
+4 -4
View File
@@ -116,13 +116,13 @@ end;
procedure TDataSeries<T>.Add(const Data: array of TDataPoint<T>; NumToAdd: Integer = -1); procedure TDataSeries<T>.Add(const Data: array of TDataPoint<T>; NumToAdd: Integer = -1);
begin begin
Assert( IsWriteable ); Assert(IsWriteable);
FDataSeries.Writer.Add( Data, NumToAdd ); FDataSeries.Writer.Add(Data, NumToAdd);
end; end;
procedure TDataSeries<T>.Clear; procedure TDataSeries<T>.Clear;
begin begin
Assert( IsWriteable ); Assert(IsWriteable);
FDataSeries.Writer.Clear; FDataSeries.Writer.Clear;
end; end;
@@ -173,7 +173,7 @@ end;
function TDataSeries<T>.GetIsWriteable: Boolean; function TDataSeries<T>.GetIsWriteable: Boolean;
begin begin
Result := Assigned( FDataSeries.Writer ); Result := Assigned(FDataSeries.Writer);
end; end;
function TDataSeries<T>.GetTime(Idx: Int64): TDateTime; function TDataSeries<T>.GetTime(Idx: Int64): TDateTime;
+17 -9
View File
@@ -101,8 +101,12 @@ type
// Used by cache to actually load an uncached file. // Used by cache to actually load an uncached file.
function DoLoad(const FileName: string): TFuture<TArray<TDataPoint<T>>>; function DoLoad(const FileName: string): TFuture<TArray<TDataPoint<T>>>;
function ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture<TArray<TDataPoint<T>>>; Terminated: TState; Proc: TDataProc<T>): function ProcessFile(
TState; FileInfo: TAuraDataFile;
const DataFile: TFuture<TArray<TDataPoint<T>>>;
Terminated: TState;
Proc: TDataProc<T>
): TState;
strict private strict private
class var class var
@@ -394,10 +398,10 @@ begin
Result := Result :=
FindFirstFile(Symbol) FindFirstFile(Symbol)
.Chain( .Chain(
function(const FirstFileInfo: TAuraDataFile): TState function(const FirstFileInfo: TAuraDataFile): TState
begin begin
Result := ProcessFile(FirstFileInfo, LoadDataFile(FirstFileInfo), terminated, capProc); Result := ProcessFile(FirstFileInfo, LoadDataFile(FirstFileInfo), terminated, capProc);
end); end);
end; end;
function TAuraDataServer<T>.LoadDataFile(const DataFile: TAuraDataFile): TFuture<TArray<TDataPoint<T>>>; function TAuraDataServer<T>.LoadDataFile(const DataFile: TAuraDataFile): TFuture<TArray<TDataPoint<T>>>;
@@ -406,15 +410,19 @@ begin
Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName); Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName);
end; end;
function TAuraDataServer<T>.ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture<TArray<TDataPoint<T>>>; Terminated: TState; Proc: function TAuraDataServer<T>.ProcessFile(
TDataProc<T>): TState; FileInfo: TAuraDataFile;
const DataFile: TFuture<TArray<TDataPoint<T>>>;
Terminated: TState;
Proc: TDataProc<T>
): TState;
begin begin
if not FileInfo.IsValid or Terminated.IsSet then if not FileInfo.IsValid or Terminated.IsSet then
exit(TState.Null); exit(TState.Null);
// Read ahead the next file, while processing the current one // Read ahead the next file, while processing the current one
var nextFileInfo := FileInfo.GetNextFile; var nextFileInfo := FileInfo.GetNextFile;
var nextFile := LoadDataFile( nextFileInfo ); var nextFile := LoadDataFile(nextFileInfo);
Result := Result :=
DataFile.Chain( DataFile.Chain(