Refactoring
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 )
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -243,7 +243,7 @@ var
|
||||
LGateLatch: IMycLatch;
|
||||
LSub1, LSub2: IMycSubscriber; // To hold the TLatchNotifierSubscriber instances
|
||||
LInitStateP1, LInitStateP2: IMycLatch;
|
||||
Subscriptions: array[1..2] of TMycSubscription; // To manage subscriptions
|
||||
Subscriptions: array[1..2] of TState.TSubscription; // To manage subscriptions
|
||||
const
|
||||
CMainFutureResult = 'AllPrerequisitesCompleted';
|
||||
begin
|
||||
|
||||
@@ -333,7 +333,7 @@ const
|
||||
StressTestFutureCount = 100; // Number of futures for the stress test
|
||||
var
|
||||
Futures: TArray<TFuture<Integer>>;
|
||||
doneStates: TArray<IMycState>;
|
||||
doneStates: TArray<TState>;
|
||||
combinedStateAll: IMycState;
|
||||
masterFuture: TFuture<Boolean>;
|
||||
i: Integer;
|
||||
@@ -397,8 +397,8 @@ const
|
||||
QuickFutureIndex = StressTestFutureCount div 3; // Designate one future to be quicker
|
||||
var
|
||||
Futures: TArray<TFuture<Integer>>;
|
||||
doneStates: TArray<IMycState>;
|
||||
combinedStateAny: IMycState;
|
||||
doneStates: TArray<TState>;
|
||||
combinedStateAny: TState;
|
||||
masterFuture: TFuture<Boolean>;
|
||||
i: Integer;
|
||||
isAtLeastOneSet: Boolean;
|
||||
|
||||
+14
-14
@@ -189,7 +189,7 @@ procedure TTestMycDirtyFlag.TestSubscribe_ToAlreadyDirtyFlag_NotifiesSubscriberI
|
||||
var
|
||||
dirtyFlag: IMycDirty;
|
||||
subscriber: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
dirtyFlag := CreateAndPrepareDirtyFlag(True); // Start dirty
|
||||
subscriber := TMockSubscriber.Create;
|
||||
@@ -204,7 +204,7 @@ procedure TTestMycDirtyFlag.TestSubscribe_ToCleanFlag_DoesNotNotifySubscriberImm
|
||||
var
|
||||
dirtyFlag: IMycDirty;
|
||||
subscriber: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
dirtyFlag := CreateAndPrepareDirtyFlag(False); // Start clean
|
||||
subscriber := TMockSubscriber.Create;
|
||||
@@ -219,7 +219,7 @@ procedure TTestMycDirtyFlag.TestSubscriber_Notified_WhenFlagTransitionsToDirty;
|
||||
var
|
||||
dirtyFlag: IMycDirty;
|
||||
subscriber: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
dirtyFlag := CreateAndPrepareDirtyFlag(False); // Start clean
|
||||
subscriber := TMockSubscriber.Create;
|
||||
@@ -236,7 +236,7 @@ procedure TTestMycDirtyFlag.TestSubscriber_NotNotified_WhenSettingAlreadyDirtyFl
|
||||
var
|
||||
dirtyFlag: IMycDirty;
|
||||
subscriber: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
dirtyFlag := CreateAndPrepareDirtyFlag(True); // Start dirty
|
||||
subscriber := TMockSubscriber.Create;
|
||||
@@ -253,7 +253,7 @@ procedure TTestMycDirtyFlag.TestSubscriber_NotNotified_ByResetAction;
|
||||
var
|
||||
dirtyFlag: IMycDirty;
|
||||
subscriber: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
dirtyFlag := CreateAndPrepareDirtyFlag(True); // Start dirty
|
||||
subscriber := TMockSubscriber.Create;
|
||||
@@ -271,7 +271,7 @@ procedure TTestMycDirtyFlag.TestMultipleSubscribers_Notified_WhenFlagTransitions
|
||||
var
|
||||
dirtyFlag: IMycDirty;
|
||||
sub1, sub2: TMockSubscriber;
|
||||
subscription1, subscription2: TMycSubscription;
|
||||
subscription1, subscription2: TState.TSubscription;
|
||||
begin
|
||||
dirtyFlag := CreateAndPrepareDirtyFlag(False); // Start clean
|
||||
sub1 := TMockSubscriber.Create;
|
||||
@@ -289,7 +289,7 @@ procedure TTestMycDirtyFlag.TestUnsubscribe_SubscriberNotNotified;
|
||||
var
|
||||
dirtyFlag: IMycDirty;
|
||||
subscriber: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
dirtyFlag := CreateAndPrepareDirtyFlag(False); // Start clean
|
||||
subscriber := TMockSubscriber.Create;
|
||||
@@ -310,7 +310,7 @@ procedure TTestMycDirtyFlag.TestChain_A_Notifies_B_SimplePropagation;
|
||||
var
|
||||
flagA, flagB: IMycDirty;
|
||||
subToB: TMockSubscriber;
|
||||
subscriptionA_B, subscriptionMock_B: TMycSubscription;
|
||||
subscriptionA_B, subscriptionMock_B: TState.TSubscription;
|
||||
begin
|
||||
flagA := CreateAndPrepareDirtyFlag(False); // A starts clean
|
||||
flagB := CreateAndPrepareDirtyFlag(False); // B starts clean
|
||||
@@ -330,7 +330,7 @@ procedure TTestMycDirtyFlag.TestChain_A_Notifies_B_Notifies_C_SimplePropagation;
|
||||
var
|
||||
flagA, flagB, flagC: IMycDirty;
|
||||
subToC: TMockSubscriber;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TMycSubscription;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TState.TSubscription;
|
||||
begin
|
||||
flagA := CreateAndPrepareDirtyFlag(False);
|
||||
flagB := CreateAndPrepareDirtyFlag(False);
|
||||
@@ -355,7 +355,7 @@ procedure TTestMycDirtyFlag.TestChain_A_B_ResetB_RetriggerA_BStaysCleanIfANotCha
|
||||
var
|
||||
flagA, flagB: IMycDirty;
|
||||
subToB: TMockSubscriber;
|
||||
subscriptionA_B, subscriptionMock_B: TMycSubscription;
|
||||
subscriptionA_B, subscriptionMock_B: TState.TSubscription;
|
||||
begin
|
||||
flagA := CreateAndPrepareDirtyFlag(False);
|
||||
flagB := CreateAndPrepareDirtyFlag(False);
|
||||
@@ -384,7 +384,7 @@ procedure TTestMycDirtyFlag.TestChain_A_B_ResetA_ThenTriggerA_FullPropagationToB
|
||||
var
|
||||
flagA, flagB: IMycDirty;
|
||||
subToB: TMockSubscriber;
|
||||
subscriptionA_B, subscriptionMock_B: TMycSubscription;
|
||||
subscriptionA_B, subscriptionMock_B: TState.TSubscription;
|
||||
begin
|
||||
flagA := CreateAndPrepareDirtyFlag(False);
|
||||
flagB := CreateAndPrepareDirtyFlag(False);
|
||||
@@ -413,7 +413,7 @@ procedure TTestMycDirtyFlag.TestChain_A_B_C_IntermediateBReset_RetriggerA_Propag
|
||||
var
|
||||
flagA, flagB, flagC: IMycDirty;
|
||||
subToC: TMockSubscriber;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TMycSubscription;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TState.TSubscription;
|
||||
begin
|
||||
flagA := CreateAndPrepareDirtyFlag(False);
|
||||
flagB := CreateAndPrepareDirtyFlag(False);
|
||||
@@ -452,7 +452,7 @@ procedure TTestMycDirtyFlag.TestChain_A_B_C_AllReset_RetriggerA_FullPropagation;
|
||||
var
|
||||
flagA, flagB, flagC: IMycDirty;
|
||||
subToC: TMockSubscriber;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TMycSubscription;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TState.TSubscription;
|
||||
begin
|
||||
flagA := CreateAndPrepareDirtyFlag(False);
|
||||
flagB := CreateAndPrepareDirtyFlag(False);
|
||||
@@ -492,7 +492,7 @@ procedure TTestMycDirtyFlag.TestChain_A_B_C_TriggerA_ResetA_TriggerA_EnsureCNoti
|
||||
var
|
||||
flagA, flagB, flagC: IMycDirty;
|
||||
subToC: TMockSubscriber;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TMycSubscription;
|
||||
subscriptionB_A, subscriptionC_B, subscriptionMock_C: TState.TSubscription;
|
||||
begin
|
||||
flagA := CreateAndPrepareDirtyFlag(False);
|
||||
flagB := CreateAndPrepareDirtyFlag(False);
|
||||
|
||||
+14
-14
@@ -167,7 +167,7 @@ procedure TTestMycLatch.TestSubscriber_Single_IsNotifiedWhenLatchSet;
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(1);
|
||||
mockSub := TMockSubscriber.Create;
|
||||
@@ -186,7 +186,7 @@ procedure TTestMycLatch.TestSubscriber_Multiple_AreNotifiedWhenLatchSet;
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub1, mockSub2, mockSub3: TMockSubscriber;
|
||||
sub1, sub2, sub3: TMycSubscription; // Keep subscriptions in scope
|
||||
sub1, sub2, sub3: TState.TSubscription; // Keep subscriptions in scope
|
||||
begin
|
||||
latch := TLatch.Construct(1);
|
||||
mockSub1 := TMockSubscriber.Create;
|
||||
@@ -208,7 +208,7 @@ procedure TTestMycLatch.TestSubscriber_NotNotified_BeforeLatchSet;
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(2); // Count = 2
|
||||
mockSub := TMockSubscriber.Create;
|
||||
@@ -223,7 +223,7 @@ procedure TTestMycLatch.TestSubscriber_NotifiedOnlyOnce_AfterLatchSetAndUnadvise
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(1);
|
||||
mockSub := TMockSubscriber.Create;
|
||||
@@ -240,7 +240,7 @@ procedure TTestMycLatch.TestSubscribe_ToAlreadySetLatch_NotifiesImmediately;
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub1, mockSub2: TMockSubscriber;
|
||||
subscription1, subscription2: TMycSubscription;
|
||||
subscription1, subscription2: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(1); // Create with count 1
|
||||
mockSub1 := TMockSubscriber.Create;
|
||||
@@ -268,7 +268,7 @@ procedure TTestMycLatch.TestChaining_A_Notifies_B;
|
||||
var
|
||||
latchA, latchB: IMycLatch;
|
||||
mockSubForB: TMockSubscriber;
|
||||
subHandle_B_listens_A, subHandle_Mock_listens_B: TMycSubscription;
|
||||
subHandle_B_listens_A, subHandle_Mock_listens_B: TState.TSubscription;
|
||||
begin
|
||||
latchA := TLatch.Construct(1);
|
||||
latchB := TLatch.Construct(1); // latchB is an IMycSubscriber
|
||||
@@ -293,7 +293,7 @@ procedure TTestMycLatch.TestCascade_A_Notifies_B_Notifies_C;
|
||||
var
|
||||
latchA, latchB, latchC: IMycLatch;
|
||||
mockSubForC: TMockSubscriber;
|
||||
sub_Mock_C, sub_C_B, sub_B_A: TMycSubscription;
|
||||
sub_Mock_C, sub_C_B, sub_B_A: TState.TSubscription;
|
||||
begin
|
||||
latchA := TLatch.Construct(1);
|
||||
latchB := TLatch.Construct(1);
|
||||
@@ -316,7 +316,7 @@ procedure TTestMycLatch.TestChaining_B_NeedsMultipleNotifiesFromA_WithSubscriber
|
||||
var
|
||||
latchA, latchB: IMycLatch;
|
||||
mockSubForB: TMockSubscriber;
|
||||
sub_Mock_B, sub_B_A: TMycSubscription;
|
||||
sub_Mock_B, sub_B_A: TState.TSubscription;
|
||||
begin
|
||||
// LatchA needs 2 notifies to become set. LatchB needs 1 notify to become set.
|
||||
// LatchB subscribes to LatchA. So LatchB will be notified once LatchA becomes set.
|
||||
@@ -345,7 +345,7 @@ procedure TTestMycLatch.TestInitiallySetLatch_NotifiesNewSubscriberImmediately;
|
||||
var
|
||||
latch: IMycLatch; // Will be TMycLatch.Null
|
||||
mockSub: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(0); // Returns TMycLatch.Null which is set.
|
||||
mockSub := TMockSubscriber.Create;
|
||||
@@ -360,7 +360,7 @@ procedure TTestMycLatch.TestUnsubscribe_SubscriberNotNotified;
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(1);
|
||||
mockSub := TMockSubscriber.Create;
|
||||
@@ -379,7 +379,7 @@ procedure TTestMycLatch.TestMultipleTriggersNoSubscriber_StateCorrectForLaterSub
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub: TMockSubscriber;
|
||||
subscription: TMycSubscription;
|
||||
subscription: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(3);
|
||||
|
||||
@@ -402,7 +402,7 @@ procedure TTestMycLatch.TestLatchSet_ClearsSubscribers_NoFurtherNotification;
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSub1, mockSub2: TMockSubscriber;
|
||||
subscription1, subscription2: TMycSubscription;
|
||||
subscription1, subscription2: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(1);
|
||||
mockSub1 := TMockSubscriber.Create;
|
||||
@@ -438,7 +438,7 @@ begin
|
||||
var noException: Boolean := True;
|
||||
try
|
||||
begin // Inner block to control lifetime of 'subscription'
|
||||
var subscription: TMycSubscription; // Local to this block
|
||||
var subscription: TState.TSubscription; // Local to this block
|
||||
subscription := latch.State.Subscribe(mockSub);
|
||||
|
||||
latch.Notify; // Sets the latch, mockSub is notified, UnadviseAll is called internally.
|
||||
@@ -466,7 +466,7 @@ procedure TTestMycLatch.TestLatchSet_NewSubscriberToSetLatch_NotifiedImmediately
|
||||
var
|
||||
latch: IMycLatch;
|
||||
mockSubInitial, mockSubNew: TMockSubscriber;
|
||||
subscriptionInitial, subscriptionNew: TMycSubscription;
|
||||
subscriptionInitial, subscriptionNew: TState.TSubscription;
|
||||
begin
|
||||
latch := TLatch.Construct(1);
|
||||
mockSubInitial := TMockSubscriber.Create;
|
||||
|
||||
Reference in New Issue
Block a user