diff --git a/AuraTrader/MainForm.pas b/AuraTrader/MainForm.pas index dd6fd7b..7c3d693 100644 --- a/AuraTrader/MainForm.pas +++ b/AuraTrader/MainForm.pas @@ -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>.CreateProtected; - var currLog := TMutable.CreateProtected; + var currPathData := TMutable>.CreateWriteable.Protect; + var currLog := TMutable.CreateWriteable.Protect; const width = 1000; const incsize = 100; - begin - var arr := TDataSeries.CreateWriteable(width); - var done := - FServer.ProcessData( - Symbol, - FTerminate.Signal, - procedure(const Values: TArray>; 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.CreateWriteable(width); + var done := + FServer.ProcessData( + Symbol, + FTerminate.Signal, + procedure(const Values: TArray>; 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.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.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. diff --git a/Src/Myc.Core.Lazy.pas b/Src/Myc.Core.Lazy.pas index 8706a5e..d0ca058 100644 --- a/Src/Myc.Core.Lazy.pas +++ b/Src/Myc.Core.Lazy.pas @@ -46,6 +46,7 @@ type function GetChanged: TSignal; function GetValue: T; function GetWriter: TMutable.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); end; - TMycProtectedWriteableMutable = class(TInterfacedObject, TMutable.IMutable, TMutable.IWriter) + TMycProtectedMutable = class(TInterfacedObject, TMutable.IMutable, TMutable.IWriter) private - FValue: T; - FChanged: TEvent; + FMutable: TMutable.IMutable; FLock: Integer; protected + function Exchange(const Value: T): T; function GetChanged: TSignal; function GetValue: T; function GetWriter: TMutable.IWriter; procedure Lock; inline; procedure Release; inline; public - constructor Create(const AValue: T); + constructor Create(const AMutable: TMutable.IMutable); procedure SetValue(const Value: T); end; @@ -149,6 +150,12 @@ begin FChanged := TEvent.CreateEvent; end; +function TMycWriteableMutable.Exchange(const Value: T): T; +begin + Result := FValue; + FValue := Value; +end; + function TMycWriteableMutable.GetChanged: TSignal; begin Result := FChanged.Signal; @@ -239,52 +246,64 @@ begin Result := FProc(); end; -{ TMycProtectedWriteableMutable } +{ TMycProtectedMutable } -constructor TMycProtectedWriteableMutable.Create(const AValue: T); +constructor TMycProtectedMutable.Create(const AMutable: TMutable.IMutable); begin inherited Create; - FValue := AValue; - FChanged := TEvent.CreateEvent; + FMutable := AMutable; end; -function TMycProtectedWriteableMutable.GetChanged: TSignal; -begin - Result := FChanged.Signal; -end; - -function TMycProtectedWriteableMutable.GetValue: T; +function TMycProtectedMutable.Exchange(const Value: T): T; begin Lock; try - Result := FValue; + Assert(FMutable.Writer <> nil); + FMutable.Writer.Exchange(Value); finally Release; end; end; -function TMycProtectedWriteableMutable.GetWriter: TMutable.IWriter; +function TMycProtectedMutable.GetChanged: TSignal; begin - Result := Self; + Result := FMutable.Changed; end; -procedure TMycProtectedWriteableMutable.Lock; +function TMycProtectedMutable.GetValue: T; +begin + Lock; + try + Result := FMutable.Value; + finally + Release; + end; +end; + +function TMycProtectedMutable.GetWriter: TMutable.IWriter; +begin + Result := nil; + if FMutable.Writer <> nil then + Result := Self; +end; + +procedure TMycProtectedMutable.Lock; begin while AtomicExchange(FLock, 1) = 1 do YieldProcessor; end; -procedure TMycProtectedWriteableMutable.Release; +procedure TMycProtectedMutable.Release; begin AtomicExchange(FLock, 0); end; -procedure TMycProtectedWriteableMutable.SetValue(const Value: T); +procedure TMycProtectedMutable.SetValue(const Value: T); begin Lock; try - FValue := Value; - FChanged.Notify; + Assert(FMutable.Writer <> nil); + FMutable.Writer.SetValue(Value); finally Release; end; diff --git a/Src/Myc.Futures.pas b/Src/Myc.Futures.pas index 6a97f71..d52d4e4 100644 --- a/Src/Myc.Futures.pas +++ b/Src/Myc.Futures.pas @@ -180,7 +180,7 @@ end; function TObjectRef.Pop: T; begin Result := FObj; - FreeAndNil( FObj ); + FreeAndNil(FObj); end; end. diff --git a/Src/Myc.Lazy.pas b/Src/Myc.Lazy.pas index 862c954..65e0290 100644 --- a/Src/Myc.Lazy.pas +++ b/Src/Myc.Lazy.pas @@ -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): TMutable; overload; static; - class function CreateProtected: TMutable; overload; static; class function CreateWriteable: TMutable; overload; static; + function Protect: TMutable; + property Value: T read GetValue write SetValue; property Changed: TSignal read GetChanged; property IsWriteable: Boolean read GetIsWriteable; @@ -112,11 +114,6 @@ begin Result := TMycFuncMutable.Create(Changing, Proc); end; -class function TMutable.CreateProtected: TMutable; -begin - Result := TMycProtectedWriteableMutable.Create(Default(T)); -end; - class function TMutable.CreateWriteable: TMutable; begin Result := TMycWriteableMutable.Create(Default(T)); @@ -129,7 +126,7 @@ end; function TMutable.GetIsWriteable: Boolean; begin - Result := Assigned( FMutable.Writer ); + Result := Assigned(FMutable.Writer); end; function TMutable.GetValue: T; @@ -137,10 +134,18 @@ begin Result := FMutable.Value; end; +function TMutable.Protect: TMutable; +begin + if not (FMutable is TMycProtectedMutable) then + Result := TMycProtectedMutable.Create(FMutable) + else + Result := FMutable; +end; + procedure TMutable.SetValue(const Value: T); begin - Assert( IsWriteable ); - FMutable.Writer.SetValue( Value ); + Assert(IsWriteable); + FMutable.Writer.SetValue(Value); end; class operator TMutable.Implicit(const A: TMutable): IMutable; diff --git a/Src/Myc.Trade.DataPoint.pas b/Src/Myc.Trade.DataPoint.pas index 48ddc62..3dd755c 100644 --- a/Src/Myc.Trade.DataPoint.pas +++ b/Src/Myc.Trade.DataPoint.pas @@ -116,13 +116,13 @@ end; procedure TDataSeries.Add(const Data: array of TDataPoint; NumToAdd: Integer = -1); begin - Assert( IsWriteable ); - FDataSeries.Writer.Add( Data, NumToAdd ); + Assert(IsWriteable); + FDataSeries.Writer.Add(Data, NumToAdd); end; procedure TDataSeries.Clear; begin - Assert( IsWriteable ); + Assert(IsWriteable); FDataSeries.Writer.Clear; end; @@ -173,7 +173,7 @@ end; function TDataSeries.GetIsWriteable: Boolean; begin - Result := Assigned( FDataSeries.Writer ); + Result := Assigned(FDataSeries.Writer); end; function TDataSeries.GetTime(Idx: Int64): TDateTime; diff --git a/Src/Myc.Trade.DataStream.pas b/Src/Myc.Trade.DataStream.pas index 049219a..7747db1 100644 --- a/Src/Myc.Trade.DataStream.pas +++ b/Src/Myc.Trade.DataStream.pas @@ -101,8 +101,12 @@ type // Used by cache to actually load an uncached file. function DoLoad(const FileName: string): TFuture>>; - function ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture>>; Terminated: TState; Proc: TDataProc): - TState; + function ProcessFile( + FileInfo: TAuraDataFile; + const DataFile: TFuture>>; + Terminated: TState; + Proc: TDataProc + ): 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.LoadDataFile(const DataFile: TAuraDataFile): TFuture>>; @@ -406,15 +410,19 @@ begin Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName); end; -function TAuraDataServer.ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture>>; Terminated: TState; Proc: - TDataProc): TState; +function TAuraDataServer.ProcessFile( + FileInfo: TAuraDataFile; + const DataFile: TFuture>>; + Terminated: TState; + Proc: TDataProc +): 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(