unit Myc.Core.Lazy; interface uses System.Classes, System.SysUtils, Myc.Signals, Myc.Lazy; type TMycNullMutable = class(TInterfacedObject, TMutable.IMutable) private function GetChanged: TSignal; function GetValue: T; function GetWriter: TMutable.IWriter; end; TMycMutableBase = class(TInterfacedObject, TMutable.IMutable) strict private FChanged: TEvent; FChangeState: TSignal.TSubscription; function GetChanged: TSignal; function GetWriter: TMutable.IWriter; protected function GetValue: T; virtual; abstract; public constructor Create(const AChanged: TSignal); destructor Destroy; override; end; TMycFuncMutable = class(TMycMutableBase) private FProc: TFunc; protected function GetValue: T; override; public constructor Create(const AChanged: TSignal; const AProc: TFunc); end; TMycWriteableMutable = class(TInterfacedObject, TMutable.IMutable, TMutable.IWriter) private FValue: T; FChanged: TEvent; protected 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); end; TMycNullLazy = class(TInterfacedObject, TLazy.ILazy) protected function GetChanged: TState; public function Pop(out Res: T): Boolean; end; TMycLazyBase = class(TInterfacedObject, TLazy.ILazy) strict private FChanged: TFlag; FChangeState: TSignal.TSubscription; function GetChanged: TState; protected function GetValue: T; virtual; abstract; public constructor Create(const AChanged: TSignal); destructor Destroy; override; function Pop(out Res: T): Boolean; end; TMycFuncLazy = class(TMycLazyBase) private FProc: TFunc; protected function GetValue: T; override; public constructor Create(const AChanged: TSignal.ISignal; const AProc: TFunc); end; TMycProtectedMutable = class(TInterfacedObject, TMutable.IMutable, TMutable.IWriter) private 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 AMutable: TMutable.IMutable); procedure SetValue(const Value: T); end; implementation { TMycNullMutable } function TMycNullMutable.GetChanged: TSignal; begin Result := TSignal.Null; end; function TMycNullMutable.GetValue: T; begin Result := Default(T); end; function TMycNullMutable.GetWriter: TMutable.IWriter; begin Result := nil; end; { TMycMutableBase } constructor TMycMutableBase.Create(const AChanged: TSignal); begin inherited Create; FChanged := TEvent.CreateEvent; FChangeState := AChanged.Subscribe(FChanged); end; destructor TMycMutableBase.Destroy; begin FChangeState.Unsubscribe; inherited; end; function TMycMutableBase.GetChanged: TSignal; begin Result := FChanged.Signal; end; function TMycMutableBase.GetWriter: TMutable.IWriter; begin Result := nil; end; { TMycWriteableMutable } constructor TMycWriteableMutable.Create(const AValue: T); begin inherited Create; FValue := AValue; 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; end; function TMycWriteableMutable.GetValue: T; begin Result := FValue; end; function TMycWriteableMutable.GetWriter: TMutable.IWriter; begin Result := Self; end; procedure TMycWriteableMutable.SetValue(const Value: T); begin FValue := Value; FChanged.Notify; end; { TMycNullLazy } function TMycNullLazy.GetChanged: TState; begin Result := TState.Null; end; function TMycNullLazy.Pop(out Res: T): Boolean; begin Res := Default(T); Result := true; end; { TMycLazyBase } constructor TMycLazyBase.Create(const AChanged: TSignal); begin inherited Create; FChanged := TFlag.CreateFlag; FChanged.Notify; FChangeState := AChanged.Subscribe(FChanged); end; destructor TMycLazyBase.Destroy; begin FChangeState.Unsubscribe; inherited; end; function TMycLazyBase.GetChanged: TState; begin Result := FChanged.State; end; function TMycLazyBase.Pop(out Res: T): Boolean; begin Result := FChanged.State.IsSet; if Result then begin Res := GetValue; FChanged.Reset; end; end; { TMycFuncLazy } constructor TMycFuncLazy.Create(const AChanged: TSignal.ISignal; const AProc: TFunc); begin inherited Create(AChanged); FProc := AProc; Assert(Assigned(FProc)); end; function TMycFuncLazy.GetValue: T; begin Result := FProc(); end; constructor TMycFuncMutable.Create(const AChanged: TSignal; const AProc: TFunc); begin inherited Create(AChanged); FProc := AProc; end; function TMycFuncMutable.GetValue: T; begin Result := FProc(); end; { TMycProtectedMutable } constructor TMycProtectedMutable.Create(const AMutable: TMutable.IMutable); begin inherited Create; FMutable := AMutable; end; function TMycProtectedMutable.Exchange(const Value: T): T; begin Lock; try Assert(FMutable.Writer <> nil); Result := FMutable.Writer.Exchange(Value); finally Release; end; end; function TMycProtectedMutable.GetChanged: TSignal; begin Result := FMutable.Changed; end; 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 TMycProtectedMutable.Release; begin AtomicExchange(FLock, 0); end; procedure TMycProtectedMutable.SetValue(const Value: T); begin Lock; try Assert(FMutable.Writer <> nil); FMutable.Writer.SetValue(Value); finally Release; end; end; end.