TWriteable<T>

This commit is contained in:
Michael Schimmel
2025-06-24 19:11:29 +02:00
parent 3797507d95
commit a65a5f2b0a
4 changed files with 140 additions and 48 deletions
+3 -4
View File
@@ -89,15 +89,14 @@ begin
exit;
var arr := TDataSeries<TAskBidItem>.CreateArray(3000);
var curr := TMutable<TDataSeries<TAskBidItem>>.CreateProtected;
var curr := TWriteable<TDataSeries<TAskBidItem>>.CreateProtected;
var Symbol := FSymbols.WaitFor[SymbolsComboBox.ItemIndex];
var done :=
TAuraFileLoader<TAskBidItem>.LoadData(
FServer as TAuraTABFileServer,
FServer.ProcessData(
Symbol,
FTerminate.Signal,
procedure(const Values: TArray<TDataPoint<TAskBidItem>>)
procedure(const Values: TArray<TDataPoint<TAskBidItem>>; const Terminated: TState)
begin
arr.Add(Values);
curr.Value := arr.Copy;
+19 -8
View File
@@ -36,7 +36,7 @@ type
constructor Create(const AChanged: TSignal; const AProc: TFunc<T>);
end;
TMycWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriteable)
TMycWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TWriteable<T>.IWriteable)
private
FValue: T;
FChanged: TEvent;
@@ -77,7 +77,7 @@ type
constructor Create(const AChanged: TSignal.ISignal; const AProc: TFunc<T>);
end;
TMycProtectedWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriteable)
TMycProtectedWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TWriteable<T>.IWriteable)
private
FValue: T;
FChanged: TEvent;
@@ -85,6 +85,8 @@ type
protected
function GetChanged: TSignal;
function GetValue: T;
procedure Lock; inline;
procedure Release; inline;
public
constructor Create(const AValue: T);
procedure SetValue(const Value: T);
@@ -234,24 +236,33 @@ end;
function TMycProtectedWriteableMutable<T>.GetValue: T;
begin
while AtomicExchange(FLock, 1) = 1 do
YieldProcessor;
Lock;
try
Result := FValue;
finally
AtomicExchange(FLock, 0);
Release;
end;
end;
procedure TMycProtectedWriteableMutable<T>.Lock;
begin
while AtomicExchange(FLock, 1) = 1 do
YieldProcessor;
end;
procedure TMycProtectedWriteableMutable<T>.Release;
begin
AtomicExchange(FLock, 0);
end;
procedure TMycProtectedWriteableMutable<T>.SetValue(const Value: T);
begin
while AtomicExchange(FLock, 1) = 1 do
YieldProcessor;
Lock;
try
FValue := Value;
FChanged.Notify;
finally
AtomicExchange(FLock, 0);
Release;
end;
end;
+68 -18
View File
@@ -18,11 +18,6 @@ type
property Value: T read GetValue;
end;
IWriteable = interface(IMutable)
procedure SetValue(const Value: T);
property Value: T read GetValue write SetValue;
end;
{$REGION 'private'}
strict private
class var
@@ -44,13 +39,36 @@ type
class function Construct(const Changing: TSignal; const Proc: TFunc<T>): TMutable<T>; overload; static;
class function CreateWriteable(const Init: T): IWriteable; overload; static;
class function CreateProtected: IWriteable; 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);
property Value: T read GetValue write SetValue;
end;
private
FWriteable: IWriteable;
function GetChanged: TSignal; inline;
function GetValue: T; inline;
procedure SetValue(const Value: T); inline;
public
constructor Create(const AWriteable: IWriteable);
class function CreateProtected: TWriteable<T>; overload; static;
class function CreateWriteable: TWriteable<T>; overload; static;
class operator Implicit(const A: IWriteable): TWriteable<T>; overload;
class operator Implicit(const A: TWriteable<T>): IWriteable; overload;
property Value: T read GetValue write SetValue;
property Changed: TSignal read GetChanged;
end;
TLazy<T> = record
type
ILazy = interface
@@ -109,16 +127,6 @@ begin
Result := TMycFuncMutable<T>.Create(Changing, Proc);
end;
class function TMutable<T>.CreateProtected: IWriteable;
begin
Result := TMycProtectedWriteableMutable<T>.Create(Default(T));
end;
class function TMutable<T>.CreateWriteable(const Init: T): IWriteable;
begin
Result := TMycWriteableMutable<T>.Create(Init);
end;
function TMutable<T>.GetChanged: TSignal;
begin
Result := FMutable.Changed;
@@ -193,4 +201,46 @@ begin
Dest.FLazy := FNull;
end;
{ TWriteable<T> }
constructor TWriteable<T>.Create(const AWriteable: IWriteable);
begin
FWriteable := AWriteable;
end;
class function TWriteable<T>.CreateProtected: TWriteable<T>;
begin
Result := TMycProtectedWriteableMutable<T>.Create(Default(T));
end;
class function TWriteable<T>.CreateWriteable: TWriteable<T>;
begin
Result := TMycWriteableMutable<T>.Create(Default(T));
end;
function TWriteable<T>.GetChanged: TSignal;
begin
Result := FWriteable.Changed;
end;
function TWriteable<T>.GetValue: T;
begin
Result := FWriteable.Value;
end;
procedure TWriteable<T>.SetValue(const Value: T);
begin
FWriteable.Value := 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;
end.
+50 -18
View File
@@ -54,23 +54,14 @@ type
function IsHistory: Boolean; virtual; abstract;
end;
// Represents a factory for creating IDataStream instances.
IDataStreamNode<T> = interface
['{DA3531F1-158E-4A63-8E5A-34089C537B1B}']
function CreateDataStream: IDataStream<T>;
end;
// Abstract base class for IDataStreamNode implementations.
TDataStreamNode<T> = class(TInterfacedObject, IDataStreamNode<T>)
public
function CreateDataStream: IDataStream<T>; virtual; abstract;
end;
TDataProc<T> = reference to procedure(const Values: TArray<TDataPoint<T>>; const Terminated: TState);
// Interface for an instantiable data server.
IDataServer<T: record> = interface
['{1F8E5A9D-E92A-44C1-9F3F-C4B82A6E94B3}']
function CreateStream(const Symbol: String): IDataStream<T>;
procedure ClearCache;
function ProcessData(const Symbol: String; const Terminate: TSignal; const Proc: TDataProc<T>): TState;
function EnumerateSymbols: TFuture<TArray<String>>;
end;
@@ -110,6 +101,8 @@ type
// Used by cache to actually load an uncached file.
function DoLoad(const FileName: string): TFuture<TArray<TDataPoint<T>>>;
function LoadFile(currFile: TAuraDataFile; Terminated: TState; Proc: TDataProc<T>): TState;
strict private
class var
FLoadGate: TLatch;
@@ -130,6 +123,9 @@ type
function ParseFileName(const FileName: string): TAuraDataFile; virtual; abstract;
function EnumerateSymbols: TFuture<TArray<String>>;
function LoadDataFile(const DataFile: TAuraDataFile): TFuture<TArray<TDataPoint<T>>>;
function ProcessData(const Symbol: String; const Terminate: TSignal; const Proc: TDataProc<T>): TState;
property Path: String read GetPath;
end;
@@ -180,13 +176,8 @@ type
TAuraFileLoader<T: record> = class(TInterfacedObject)
type
TDataProc = reference to procedure(const Values: TArray<TDataPoint<T>>);
public
class function LoadData(
DataServer: TAuraDataServer<T>;
const Symbol: String;
const Terminate: TSignal;
const Proc: TDataProc
): TState;
private
class procedure LoadFile(
DataServer: TAuraDataServer<T>;
currFile: TAuraDataFile;
@@ -194,6 +185,14 @@ type
Done: TLatch;
Proc: TDataProc
);
public
class function LoadData(
DataServer: TAuraDataServer<T>;
const Symbol: String;
const Terminate: TSignal;
const Proc: TDataProc
): TState;
end;
implementation
@@ -409,11 +408,44 @@ begin
Result := FPath;
end;
function TAuraDataServer<T>.ProcessData(const Symbol: String; const Terminate: TSignal; const Proc: TDataProc<T>): TState;
begin
var capProc := Proc;
var terminated := TFlag.CreateObserver(Terminate).State;
var firstFile := FindFirstFile(Symbol);
var done := TLatch.CreateLatch(1);
Result := done.State;
TaskManager.CreateTask(firstFile.Done, procedure begin LoadFile(firstFile.Value, terminated, capProc).Subscribe(done); end);
end;
function TAuraDataServer<T>.LoadDataFile(const DataFile: TAuraDataFile): TFuture<TArray<TDataPoint<T>>>;
begin
Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName);
end;
function TAuraDataServer<T>.LoadFile(currFile: TAuraDataFile; Terminated: TState; Proc: TDataProc<T>): TState;
begin
if not currFile.IsValid or Terminated.IsSet then
exit(TState.Null);
var done := TLatch.CreateLatch(1);
Result := done.State;
var data := FCachedFiles.GetOrAdd(currFile.GetFullFileName);
TaskManager.CreateTask(
data.Done,
procedure
begin
Proc(data.Value, Terminated);
LoadFile(currFile.GetNextFile, Terminated, Proc).Subscribe(done);
end
);
end;
{ TAuraFileStream<T> }
constructor TAuraFileStream<T>.Create(ADataServer: TAuraDataServer<T>; const ASymbol: String);