Refactoring

This commit is contained in:
Michael Schimmel
2025-06-03 18:20:02 +02:00
parent 561a3c6bb5
commit 556690fa5e
12 changed files with 152 additions and 155 deletions
+9 -9
View File
@@ -10,23 +10,23 @@ type
TMycFuture<T> = class abstract( TInterfacedObject, IMycFuture<T> )
protected
function GetResult: T; virtual; abstract;
function GetDone: IMycState; virtual; abstract;
function GetDone: TState; virtual; abstract;
end;
TMycNullFuture<T> = class( TMycFuture<T> )
protected
function GetResult: T; override;
function GetDone: IMycState; override;
function GetDone: TState; override;
end;
TMycGateFuncFuture<T> = class(TMycFuture<T>)
TMycGateFuncFuture<T> = class( TMycFuture<T> )
private
FInit: TMycSubscription;
FInit: TState.TSubscription;
FDone: IMycLatch;
FResult: T;
protected
function GetResult: T; override;
function GetDone: IMycState; override;
function GetDone: TState; override;
public
constructor Create( const ATaskManager: IMycTaskManager; const AGate: IMycState; AProc: TFunc<T> );
destructor Destroy; override;
@@ -36,19 +36,19 @@ implementation
{ TMycNullFuture<T> }
function TMycNullFuture<T>.GetDone: IMycState;
function TMycNullFuture<T>.GetDone: TState;
begin
Result := TState.Null;
end;
function TMycNullFuture<T>.GetResult: T;
begin
Result := Default(T);
Result := Default ( T );
end;
{ TMycGateFuncFuture<T> }
constructor TMycGateFuncFuture<T>.Create(const ATaskManager: IMycTaskManager; const AGate: IMycState; AProc: TFunc<T>);
constructor TMycGateFuncFuture<T>.Create( const ATaskManager: IMycTaskManager; const AGate: IMycState; AProc: TFunc<T> );
begin
inherited Create;
@@ -81,7 +81,7 @@ begin
inherited Destroy;
end;
function TMycGateFuncFuture<T>.GetDone: IMycState;
function TMycGateFuncFuture<T>.GetDone: TState;
begin
Result := FDone.State;
end;
+3 -3
View File
@@ -25,12 +25,12 @@ type
TMycFuncLazy<T> = class( TMycLazy<T> )
private
FChanged: IMycDirty;
FChangeState: TMycSubscription;
FChangeState: TState.TSubscription;
FProc: TFunc<T>;
protected
function GetChanged: IMycState; override;
public
constructor Create( const AChanged: IMycState; const AProc: TFunc<T> );
constructor Create(const AChanged: TState; const AProc: TFunc<T>);
destructor Destroy; override;
function Pop( out Res: T ): Boolean; override;
end;
@@ -52,7 +52,7 @@ end;
{ TMycFuncLazy<T> }
constructor TMycFuncLazy<T>.Create( const AChanged: IMycState; const AProc: TFunc<T> );
constructor TMycFuncLazy<T>.Create(const AChanged: TState; const AProc: TFunc<T>);
begin
inherited Create;
FChanged := TDirty.Construct;
+20 -20
View File
@@ -12,7 +12,7 @@ type
protected
function GetIsSet: Boolean; virtual; abstract;
public
function Subscribe(Subscriber: IMycSubscriber): TMycSubscription; virtual; abstract;
function Subscribe(Subscriber: IMycSubscriber): Pointer; virtual; abstract;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag); virtual; abstract;
property IsSet: Boolean read GetIsSet;
end;
@@ -23,7 +23,7 @@ type
protected
// IMycState
function GetIsSet: Boolean;
function Subscribe(Subscriber: IMycSubscriber): TMycSubscription;
function Subscribe(Subscriber: IMycSubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
public
constructor Create;
@@ -38,7 +38,7 @@ type
FSubscribers: TMycNotifyList<IMycSubscriber>; // List of subscribers waiting for this latch to be set.
private
[volatile] FCount: Integer; // The internal countdown value for the latch.
function GetState: IMycState; // Implementation for IMycLatch.GetState and IMycFlag.GetState.
function GetState: TState; // Implementation for IMycLatch.GetState and IMycFlag.GetState.
protected
function GetIsSet: Boolean; override; final; // Implementation for IMycState.GetIsSet.
public
@@ -48,7 +48,7 @@ type
destructor Destroy; override;
// IMycSignal implementation
function Subscribe(Subscriber: IMycSubscriber): TMycSubscription; override;
function Subscribe(Subscriber: IMycSubscriber): Pointer; override;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag); override;
// IMycSubscriber implementation for TMycLatch itself.
@@ -59,7 +59,7 @@ type
TMycNullLatch = class( TInterfacedObject, IMycLatch )
private
function GetState: IMycState;
function GetState: TState;
function Notify: Boolean;
end;
@@ -71,7 +71,7 @@ type
FSubscribers: TMycNotifyList<IMycSubscriber>; // List of subscribers interested in state changes of this dirty flag.
private
[volatile] FFlag: Boolean; // Internal state: true if dirty/set, false if clean/reset.
function GetState: IMycState; // Implementation for IMycFlag.GetState.
function GetState: TState;
protected
function GetIsSet: Boolean; override; final; // Implementation for IMycState.GetIsSet (true if dirty).
public
@@ -82,7 +82,7 @@ type
// Factory method to create a new TMycDirty instance.
class function CreateDirty: IMycDirty; static;
function Subscribe(Subscriber: IMycSubscriber): TMycSubscription; override;
function Subscribe(Subscriber: IMycSubscriber): Pointer; override;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag); override;
// IMycSubscriber implementation for TMycDirty.
@@ -95,7 +95,7 @@ type
TMycNullDirty = class( TInterfacedObject, IMycDirty )
private
function GetState: IMycState;
function GetState: TState;
function Notify: Boolean;
function Reset: Boolean;
end;
@@ -117,7 +117,7 @@ begin
Result := true; // Null state is always set.
end;
function TMycNullState.Subscribe(Subscriber: IMycSubscriber): TMycSubscription;
function TMycNullState.Subscribe(Subscriber: IMycSubscriber): Pointer;
begin
// Since the state is always set, notify the subscriber immediately.
if Assigned(Subscriber) then
@@ -125,7 +125,7 @@ begin
Subscriber.Notify;
end;
// No ongoing subscription is necessary or meaningful for a null state.
Result.Create(Self, nil); // Return an empty subscription.
Result := nil;
end;
procedure TMycNullState.Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
@@ -135,7 +135,7 @@ end;
{ TMycNullLatch }
function TMycNullLatch.GetState: IMycState;
function TMycNullLatch.GetState: TState;
begin
Result := TState.Null;
end;
@@ -202,13 +202,13 @@ begin
Result := FCount <= 0;
end;
function TMycLatch.GetState: IMycState;
function TMycLatch.GetState: TState;
begin
// TMycLatch itself implements IMycState.
exit(Self);
Result := Self;
end;
function TMycLatch.Subscribe(Subscriber: IMycSubscriber): TMycSubscription;
function TMycLatch.Subscribe(Subscriber: IMycSubscriber): Pointer;
var
alreadySet: Boolean;
begin
@@ -227,7 +227,7 @@ begin
else
begin
// If not yet set, advise the subscriber.
Result.Create(Self, FSubscribers.Advise(Subscriber));
Result := FSubscribers.Advise(Subscriber);
end;
finally
FSubscribers.Release;
@@ -249,7 +249,7 @@ end;
{ TMycNullDirty }
function TMycNullDirty.GetState: IMycState;
function TMycNullDirty.GetState: TState;
begin
Result := TState.Null;
end;
@@ -297,10 +297,10 @@ begin
Result := FFlag;
end;
function TMycDirty.GetState: IMycState;
function TMycDirty.GetState: TState;
begin
// TMycDirty itself implements IMycState.
exit(Self);
Result := Self;
end;
function TMycDirty.Notify: Boolean;
@@ -329,7 +329,7 @@ begin
end;
end;
function TMycDirty.Subscribe(Subscriber: IMycSubscriber): TMycSubscription;
function TMycDirty.Subscribe(Subscriber: IMycSubscriber): Pointer;
begin
if not Assigned(Subscriber) then
exit;
@@ -341,7 +341,7 @@ begin
FSubscribers.Lock;
try
// Add subscriber regardless of current state.
Result.Create(Self, FSubscribers.Advise(Subscriber));
Result := FSubscribers.Advise(Subscriber);
if FFlag then // If currently dirty, notify the new subscriber immediately.
begin
Subscriber.Notify;
+3 -4
View File
@@ -76,7 +76,7 @@ type
procedure HandleException;
procedure EnqueueJob(const Job: TProc);
function Run(Job: TProc): IMycSubscriber;
function CreateTask(const Gate: IMycState; const Proc: TProc): TMycSubscription;
function CreateTask(const Gate: TState; const Proc: TProc): TState.TSubscription;
procedure WaitFor(State: IMycState);
procedure Teardown;
function InMainThread: Boolean;
@@ -183,10 +183,9 @@ begin
Result.NameThreadForDebugging(DbgName); // Set thread name for debugging
end;
function TMycTaskFactory.CreateTask(const Gate: IMycState; const Proc: TProc):
TMycSubscription;
function TMycTaskFactory.CreateTask(const Gate: TState; const Proc: TProc): TState.TSubscription;
begin
if not Assigned(Gate) or Gate.IsSet then
if Gate.IsSet then
begin
EnqueueJob( Proc );
end
+19 -18
View File
@@ -11,12 +11,12 @@ type
IMycFuture<T> = interface
{$REGION 'property access'}
function GetResult: T;
function GetDone: IMycState;
function GetDone: TState;
{$ENDREGION}
// Provides access to the computed result.
property Result: T read GetResult;
// Provides access to the completion state.
property Done: IMycState read GetDone;
property Done: TState read GetDone;
end;
TFuture<T> = record
@@ -25,22 +25,22 @@ type
function GetDone: IMycState; inline;
function GetResult: T; inline;
class var
FNull: IMycFuture<T>;
class var
FNull: IMycFuture<T>;
class constructor CreateClass;
class destructor DestroyClass;
public
constructor Create(const AFuture: IMycFuture<T>);
constructor Create( const AFuture: IMycFuture<T> );
class operator Implicit(const A: IMycFuture<T>): TFuture<T>; overload;
class operator Implicit(const A: TFuture<T>): IMycFuture<T>; overload;
class operator Implicit( const A: IMycFuture<T> ): TFuture<T>; overload;
class operator Implicit( const A: TFuture<T> ): IMycFuture<T>; overload;
class function Construct(const Proc: TFunc<T>): IMycFuture<T>; overload; static;
class function Construct(const Gate: IMycState; const Proc: TFunc<T>): IMycFuture<T>; overload; static;
class function Construct( const Proc: TFunc<T> ): TFuture<T>; overload; static;
class function Construct( const Gate: IMycState; const Proc: TFunc<T> ): TFuture<T>; overload; static;
function Chain<S>(const Proc: TFunc<T, S>): IMycFuture<S>;
function Chain<S>( const Proc: TFunc<T, S> ): TFuture<S>;
function WaitFor: T;
@@ -53,10 +53,10 @@ implementation
uses
Myc.Core.Futures, Myc.Core.Tasks;
constructor TFuture<T>.Create(const AFuture: IMycFuture<T>);
constructor TFuture<T>.Create( const AFuture: IMycFuture<T> );
begin
FFuture := AFuture;
if not Assigned(FFuture) then
if not Assigned( FFuture ) then
FFuture := FNull;
end;
@@ -71,9 +71,10 @@ begin
TMycTaskFactory.ReleaseTaskManager;
end;
function TFuture<T>.Chain<S>(const Proc: TFunc<T, S>): IMycFuture<S>;
function TFuture<T>.Chain<S>( const Proc: TFunc<T, S> ): TFuture<S>;
begin
var Cap := FFuture;
var
Cap := FFuture;
Result := TFuture<S>.Construct( FFuture.Done,
function: S
@@ -82,12 +83,12 @@ begin
end );
end;
class function TFuture<T>.Construct(const Proc: TFunc<T>): IMycFuture<T>;
class function TFuture<T>.Construct( const Proc: TFunc<T> ): TFuture<T>;
begin
Result := TMycGateFuncFuture<T>.Create( TaskManager, nil, Proc );
end;
class function TFuture<T>.Construct(const Gate: IMycState; const Proc: TFunc<T>): IMycFuture<T>;
class function TFuture<T>.Construct( const Gate: IMycState; const Proc: TFunc<T> ): TFuture<T>;
begin
Result := TMycGateFuncFuture<T>.Create( TaskManager, Gate, Proc );
end;
@@ -108,12 +109,12 @@ begin
Result := FFuture.Result;
end;
class operator TFuture<T>.Implicit(const A: IMycFuture<T>): TFuture<T>;
class operator TFuture<T>.Implicit( const A: IMycFuture<T> ): TFuture<T>;
begin
Result.Create( A );
end;
class operator TFuture<T>.Implicit(const A: TFuture<T>): IMycFuture<T>;
class operator TFuture<T>.Implicit( const A: TFuture<T> ): IMycFuture<T>;
begin
Result := A.FFuture;
end;
+12 -12
View File
@@ -19,19 +19,19 @@ type
private
FLazy: IMycLazy<T>;
function GetChanged: IMycState; inline;
class var
FNull: IMycLazy<T>;
class var
FNull: IMycLazy<T>;
class constructor CreateClass;
public
constructor Create(const ALazy: IMycLazy<T>);
constructor Create( const ALazy: IMycLazy<T> );
class function Construct( const Changing: IMycState; const Proc: TFunc<T> ): IMycLazy<T>; static;
class operator Implicit(const A: IMycLazy<T>): TLazy<T>; overload;
class operator Implicit(const A: TLazy<T>): IMycLazy<T>; overload;
class operator Implicit( const A: IMycLazy<T> ): TLazy<T>; overload;
class operator Implicit( const A: TLazy<T> ): IMycLazy<T>; overload;
function Pop(out Res: T): Boolean; inline;
function Pop( out Res: T ): Boolean; inline;
property Changed: IMycState read GetChanged;
end;
@@ -41,14 +41,14 @@ implementation
uses
Myc.Core.Lazy;
constructor TLazy<T>.Create(const ALazy: IMycLazy<T>);
constructor TLazy<T>.Create( const ALazy: IMycLazy<T> );
begin
FLazy := ALazy;
if not Assigned(FLazy) then
if not Assigned( FLazy ) then
FLazy := FNull;
end;
class function TLazy<T>.Construct(const Changing: IMycState; const Proc: TFunc<T>): IMycLazy<T>;
class function TLazy<T>.Construct( const Changing: IMycState; const Proc: TFunc<T> ): IMycLazy<T>;
begin
Result := TMycFuncLazy<T>.Create( Changing, Proc );
end;
@@ -63,17 +63,17 @@ begin
Result := FLazy.Changed;
end;
function TLazy<T>.Pop(out Res: T): Boolean;
function TLazy<T>.Pop( out Res: T ): Boolean;
begin
Result := FLazy.Pop( Res );
end;
class operator TLazy<T>.Implicit(const A: IMycLazy<T>): TLazy<T>;
class operator TLazy<T>.Implicit( const A: IMycLazy<T> ): TLazy<T>;
begin
Result.Create( A );
end;
class operator TLazy<T>.Implicit(const A: TLazy<T>): IMycLazy<T>;
class operator TLazy<T>.Implicit( const A: TLazy<T> ): IMycLazy<T>;
begin
Result := A.FLazy;
end;
+50 -52
View File
@@ -12,53 +12,52 @@ type
function Notify: Boolean;
end;
IMycState = interface;
TMycSubscription = record
private
FState: IMycState;
FTag: Pointer; // Tag identifying this subscription within the notifier list.
function GetState: IMycState;
public
constructor Create( const AState: IMycState; ATag: Pointer );
// Unsubscribes from the associated TState.
procedure Unsubscribe;
class operator Initialize( out Dest: TMycSubscription );
property State: IMycState read GetState;
end;
IMycState = interface
// Represents a subscribable TState that can be queried.
{$REGION 'property access'}
function GetIsSet: Boolean;
{$ENDREGION}
// Subscribes a given subscriber to this TState.
function Subscribe( Subscriber: IMycSubscriber ): TMycSubscription;
function Subscribe( Subscriber: IMycSubscriber ): Pointer;
procedure Unsubscribe( Tag: Pointer );
// IsSet is true if the TState has been reached or the condition is met.
property IsSet: Boolean read GetIsSet;
end;
TState = record // helper for IMycState
type
TSubscription = record
private
FState: IMycState;
FTag: Pointer; // Tag identifying this subscription within the notifier list.
function GetState: IMycState;
constructor Create( const AState: IMycState; ATag: Pointer );
public
class operator Initialize( out Dest: TSubscription );
// Unsubscribes from the associated TState.
procedure Unsubscribe;
end;
strict private
class var
FNull: IMycState;
class var
FNull: IMycState;
class constructor ClassCreate;
private
FState: IMycState;
function GetIsSet: Boolean; inline;
public
constructor Create(const AState: IMycState);
class operator Implicit(const A: IMycState): TState; overload;
class operator Implicit(const A: TState): IMycState; overload;
constructor Create( const AState: IMycState );
class function All( const States: TArray<IMycState> ): IMycState; static;
class function Any( const States: TArray<IMycState> ): IMycState; static;
class operator Implicit( const A: IMycState ): TState; overload;
class operator Implicit( const A: TState ): IMycState; overload;
class function All( const States: TArray<TState> ): TState; static;
class function Any( const States: TArray<TState> ): TState; static;
class property Null: IMycState read FNull;
function Subscribe(Subscriber: IMycSubscriber): TMycSubscription; inline;
procedure Unsubscribe(Tag: Pointer); inline;
function Subscribe( Subscriber: IMycSubscriber ): TSubscription; inline;
procedure Unsubscribe( Tag: Pointer ); inline;
property IsSet: Boolean read GetIsSet;
end;
@@ -67,18 +66,17 @@ type
// It typically becomes set when an internal countdown reaches zero.
IMycLatch = interface( IMycSubscriber )
// Provides access to the IMycState interface of the flag.
function GetState: IMycState;
property State: IMycState read GetState;
// Inherits IMycSubscriber and State property from IMycFlag. No new members.
function GetState: TState;
property State: TState read GetState;
end;
TLatch = record
strict private
class var
FNull: IMycLatch;
class var
FNull: IMycLatch;
class constructor ClassCreate;
public
class function Construct(Count: Integer): IMycLatch; static;
class function Construct( Count: Integer ): IMycLatch; static;
class property Null: IMycLatch read FNull;
end;
@@ -86,17 +84,17 @@ type
// It inherits from IMycFlag, meaning it has a State, can be notified, and subscribed to.
IMycDirty = interface( IMycSubscriber )
// Provides access to the IMycState interface of the flag.
function GetState: IMycState;
function GetState: TState;
// Resets the flag to its "clean" (not set / not dirty) State.
// Returns true if the flag was actually dirty before this reset, false otherwise.
function Reset: Boolean;
property State: IMycState read GetState;
property State: TState read GetState;
end;
TDirty = record
strict private
class var
FNull: IMycDirty;
class var
FNull: IMycDirty;
class constructor ClassCreate;
public
class function Construct: IMycDirty; static;
@@ -108,9 +106,9 @@ implementation
uses
Myc.Core.Notifier, Myc.Core.Signals;
{ TMycSubscription }
{ TState.TSubscription }
constructor TMycSubscription.Create( const AState: IMycState; ATag:
constructor TState.TSubscription.Create( const AState: IMycState; ATag:
TMycNotifyList<IMycSubscriber>.TTag );
begin
Assert( Assigned( AState ) );
@@ -118,19 +116,19 @@ begin
FTag := ATag;
end;
procedure TMycSubscription.Unsubscribe;
procedure TState.TSubscription.Unsubscribe;
begin
FState.Unsubscribe( FTag );
FState := TState.Null;
FTag := nil;
end;
function TMycSubscription.GetState: IMycState;
function TState.TSubscription.GetState: IMycState;
begin
Result := FState
end;
class operator TMycSubscription.Initialize( out Dest: TMycSubscription );
class operator TState.TSubscription.Initialize( out Dest: TSubscription );
begin
Dest.FState := TState.Null;
Dest.FTag := nil;
@@ -138,20 +136,20 @@ end;
{ TState }
constructor TState.Create(const AState: IMycState);
constructor TState.Create( const AState: IMycState );
begin
FState := AState;
if not Assigned(FState) then
if not Assigned( FState ) then
FState := FNull;
end;
class constructor TState.ClassCreate;
begin
// Create a singleton null latch instance that is initially (and always) set.
FNull := TMycNullState.Create(); // Calls the instance constructor
FNull := TMycNullState.Create( ); // Calls the instance constructor
end;
class function TState.All( const States: TArray<IMycState> ): IMycState;
class function TState.All( const States: TArray<TState> ): TState;
var
Latch: IMycLatch;
begin
@@ -161,7 +159,7 @@ begin
Result := Latch.State;
end;
class function TState.Any( const States: TArray<IMycState> ): IMycState;
class function TState.Any( const States: TArray<TState> ): TState;
var
Latch: IMycLatch;
begin
@@ -183,22 +181,22 @@ begin
Result := FState.IsSet;
end;
function TState.Subscribe(Subscriber: IMycSubscriber): TMycSubscription;
function TState.Subscribe( Subscriber: IMycSubscriber ): TSubscription;
begin
Result := FState.Subscribe(Subscriber);
Result := TSubscription.Create( FState, FState.Subscribe( Subscriber ) );
end;
procedure TState.Unsubscribe(Tag: Pointer);
procedure TState.Unsubscribe( Tag: Pointer );
begin
FState.Unsubscribe(Tag);
FState.Unsubscribe( Tag );
end;
class operator TState.Implicit(const A: TState): IMycState;
class operator TState.Implicit( const A: TState ): IMycState;
begin
Result := A.FState;
end;
class operator TState.Implicit(const A: IMycState): TState;
class operator TState.Implicit( const A: IMycState ): TState;
begin
Result.Create( A );
end;
@@ -211,7 +209,7 @@ begin
FNull := TMycNullLatch.Create; // Calls the instance constructor
end;
class function TLatch.Construct(Count: Integer): IMycLatch;
class function TLatch.Construct( Count: Integer ): IMycLatch;
begin
if Count > 0 then
Result := TMycLatch.Create( Count )
+4 -5
View File
@@ -9,7 +9,7 @@ uses
type
IMycTaskManager = interface
// TOD Dokumentation
function CreateTask( const Gate: IMycState; const Proc: TProc ): TMycSubscription;
function CreateTask( const Gate: TState; const Proc: TProc ): TState.TSubscription;
// Waits for the operation associated with State to complete.
// Must not be called from a worker thread of this factory.
@@ -41,7 +41,7 @@ type
TMycTaskManagerMock = class(TInterfacedObject, IMycTaskManager)
public
// IMycTaskManager
function CreateTask(const Gate: IMycState; const Proc: TProc): TMycSubscription;
function CreateTask(const Gate: TState; const Proc: TProc): TState.TSubscription;
procedure WaitFor(State: IMycState);
constructor Create;
@@ -71,10 +71,9 @@ begin
inherited Create;
end;
function TMycTaskManagerMock.CreateTask(const Gate: IMycState; const Proc: TProc): TMycSubscription;
function TMycTaskManagerMock.CreateTask(const Gate: TState; const Proc: TProc): TState.TSubscription;
begin
var s: IMycState := TState(Gate);
Result := s.Subscribe( TMycExecMock.Create( Proc ) );
Result := Gate.Subscribe( TMycExecMock.Create( Proc ) );
end;
procedure TMycTaskManagerMock.WaitFor(State: IMycState);