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;
LoadButton: TButton;
FlowLayout: TFlowLayout;
ChartButton: TButton;
StopButton: TButton;
ChartButton: TButton;
StopButton: TButton;
procedure RandomButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@@ -214,36 +214,41 @@ begin
var Symbol := FSymbols.WaitFor[SymbolsComboBox.ItemIndex];
var currPathData := TMutable<IObjectRef<TPathData>>.CreateProtected;
var currLog := TMutable<String>.CreateProtected;
var currPathData := TMutable<IObjectRef<TPathData>>.CreateWriteable.Protect;
var currLog := TMutable<String>.CreateWriteable.Protect;
const width = 1000;
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;
var Prices := arr;
if Prices.Count > 0 then
TaskManager.RunTask(
nil,
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
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;
arr.Add(Values);
currLog.Value := arr.TotalCount.ToString;
currPathData.Value := TObjectRef<TPathData>.Create(PathData);
end
);
FLoadDone := TState.All([FLoadDone, done]);
end;
var PathData := TPathData.Create;
var Prices := arr;
if Prices.Count > 0 then
begin
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);
@@ -251,39 +256,12 @@ begin
currPathData.Changed,
procedure
begin
if currPathData.Value<>nil then
if currPathData.Value <> nil then
begin
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;
Path1.Data.Assign(currPathData.Value.Obj);
end;
end
);
*)
end;
end.
+41 -22
View File
@@ -46,6 +46,7 @@ type
function GetChanged: TSignal;
function GetValue: T;
function GetWriter: TMutable<T>.IWriter;
function Exchange(const Value: T): T;
public
constructor Create(const AValue: T);
procedure SetValue(const Value: T);
@@ -80,19 +81,19 @@ type
constructor Create(const AChanged: TSignal.ISignal; const AProc: TFunc<T>);
end;
TMycProtectedWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriter)
TMycProtectedMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriter)
private
FValue: T;
FChanged: TEvent;
FMutable: TMutable<T>.IMutable;
FLock: Integer;
protected
function Exchange(const Value: T): T;
function GetChanged: TSignal;
function GetValue: T;
function GetWriter: TMutable<T>.IWriter;
procedure Lock; inline;
procedure Release; inline;
public
constructor Create(const AValue: T);
constructor Create(const AMutable: TMutable<T>.IMutable);
procedure SetValue(const Value: T);
end;
@@ -149,6 +150,12 @@ begin
FChanged := TEvent.CreateEvent;
end;
function TMycWriteableMutable<T>.Exchange(const Value: T): T;
begin
Result := FValue;
FValue := Value;
end;
function TMycWriteableMutable<T>.GetChanged: TSignal;
begin
Result := FChanged.Signal;
@@ -239,52 +246,64 @@ begin
Result := FProc();
end;
{ TMycProtectedWriteableMutable<T> }
{ TMycProtectedMutable<T> }
constructor TMycProtectedWriteableMutable<T>.Create(const AValue: T);
constructor TMycProtectedMutable<T>.Create(const AMutable: TMutable<T>.IMutable);
begin
inherited Create;
FValue := AValue;
FChanged := TEvent.CreateEvent;
FMutable := AMutable;
end;
function TMycProtectedWriteableMutable<T>.GetChanged: TSignal;
begin
Result := FChanged.Signal;
end;
function TMycProtectedWriteableMutable<T>.GetValue: T;
function TMycProtectedMutable<T>.Exchange(const Value: T): T;
begin
Lock;
try
Result := FValue;
Assert(FMutable.Writer <> nil);
FMutable.Writer.Exchange(Value);
finally
Release;
end;
end;
function TMycProtectedWriteableMutable<T>.GetWriter: TMutable<T>.IWriter;
function TMycProtectedMutable<T>.GetChanged: TSignal;
begin
Result := Self;
Result := FMutable.Changed;
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
while AtomicExchange(FLock, 1) = 1 do
YieldProcessor;
end;
procedure TMycProtectedWriteableMutable<T>.Release;
procedure TMycProtectedMutable<T>.Release;
begin
AtomicExchange(FLock, 0);
end;
procedure TMycProtectedWriteableMutable<T>.SetValue(const Value: T);
procedure TMycProtectedMutable<T>.SetValue(const Value: T);
begin
Lock;
try
FValue := Value;
FChanged.Notify;
Assert(FMutable.Writer <> nil);
FMutable.Writer.SetValue(Value);
finally
Release;
end;
+1 -1
View File
@@ -180,7 +180,7 @@ end;
function TObjectRef<T>.Pop: T;
begin
Result := FObj;
FreeAndNil( FObj );
FreeAndNil(FObj);
end;
end.
+14 -9
View File
@@ -11,6 +11,7 @@ type
type
IWriter = interface
procedure SetValue(const Value: T);
function Exchange(const Value: T): T;
end;
IMutable = interface
@@ -46,9 +47,10 @@ type
class property Null: IMutable read FNull;
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;
function Protect: TMutable<T>;
property Value: T read GetValue write SetValue;
property Changed: TSignal read GetChanged;
property IsWriteable: Boolean read GetIsWriteable;
@@ -112,11 +114,6 @@ begin
Result := TMycFuncMutable<T>.Create(Changing, Proc);
end;
class function TMutable<T>.CreateProtected: TMutable<T>;
begin
Result := TMycProtectedWriteableMutable<T>.Create(Default(T));
end;
class function TMutable<T>.CreateWriteable: TMutable<T>;
begin
Result := TMycWriteableMutable<T>.Create(Default(T));
@@ -129,7 +126,7 @@ end;
function TMutable<T>.GetIsWriteable: Boolean;
begin
Result := Assigned( FMutable.Writer );
Result := Assigned(FMutable.Writer);
end;
function TMutable<T>.GetValue: T;
@@ -137,10 +134,18 @@ begin
Result := FMutable.Value;
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);
begin
Assert( IsWriteable );
FMutable.Writer.SetValue( Value );
Assert(IsWriteable);
FMutable.Writer.SetValue(Value);
end;
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);
begin
Assert( IsWriteable );
FDataSeries.Writer.Add( Data, NumToAdd );
Assert(IsWriteable);
FDataSeries.Writer.Add(Data, NumToAdd);
end;
procedure TDataSeries<T>.Clear;
begin
Assert( IsWriteable );
Assert(IsWriteable);
FDataSeries.Writer.Clear;
end;
@@ -173,7 +173,7 @@ end;
function TDataSeries<T>.GetIsWriteable: Boolean;
begin
Result := Assigned( FDataSeries.Writer );
Result := Assigned(FDataSeries.Writer);
end;
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.
function DoLoad(const FileName: string): TFuture<TArray<TDataPoint<T>>>;
function ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture<TArray<TDataPoint<T>>>; Terminated: TState; Proc: TDataProc<T>):
TState;
function ProcessFile(
FileInfo: TAuraDataFile;
const DataFile: TFuture<TArray<TDataPoint<T>>>;
Terminated: TState;
Proc: TDataProc<T>
): TState;
strict private
class var
@@ -394,10 +398,10 @@ begin
Result :=
FindFirstFile(Symbol)
.Chain(
function(const FirstFileInfo: TAuraDataFile): TState
begin
Result := ProcessFile(FirstFileInfo, LoadDataFile(FirstFileInfo), terminated, capProc);
end);
function(const FirstFileInfo: TAuraDataFile): TState
begin
Result := ProcessFile(FirstFileInfo, LoadDataFile(FirstFileInfo), terminated, capProc);
end);
end;
function TAuraDataServer<T>.LoadDataFile(const DataFile: TAuraDataFile): TFuture<TArray<TDataPoint<T>>>;
@@ -406,15 +410,19 @@ begin
Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName);
end;
function TAuraDataServer<T>.ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture<TArray<TDataPoint<T>>>; Terminated: TState; Proc:
TDataProc<T>): TState;
function TAuraDataServer<T>.ProcessFile(
FileInfo: TAuraDataFile;
const DataFile: TFuture<TArray<TDataPoint<T>>>;
Terminated: TState;
Proc: TDataProc<T>
): TState;
begin
if not FileInfo.IsValid or Terminated.IsSet then
exit(TState.Null);
// Read ahead the next file, while processing the current one
var nextFileInfo := FileInfo.GetNextFile;
var nextFile := LoadDataFile( nextFileInfo );
var nextFile := LoadDataFile(nextFileInfo);
Result :=
DataFile.Chain(