diff --git a/Src/Myc.Core.Futures.pas b/Src/Myc.Core.Futures.pas index 024d52a..3782a2a 100644 --- a/Src/Myc.Core.Futures.pas +++ b/Src/Myc.Core.Futures.pas @@ -37,7 +37,7 @@ constructor TMycInitStateFuncFuture.Create( const ATaskManager: IMycTaskManag begin inherited Create; - FDone := TMycLatch.CreateLatch( 1 ); + FDone := State.CreateLatch( 1 ); // Subscribe the job execution to AGate. // The job will run when AGate notifies the subscriber returned by Run. diff --git a/Src/Myc.Core.Tasks.pas b/Src/Myc.Core.Tasks.pas index c272f85..1dbcd69 100644 --- a/Src/Myc.Core.Tasks.pas +++ b/Src/Myc.Core.Tasks.pas @@ -95,6 +95,9 @@ type implementation +uses + Myc.Core.Signals; + type TMycPendingJob = class(TInterfacedObject, IMycSubscriber) private diff --git a/Src/Myc.Signals.pas b/Src/Myc.Signals.pas index b418daa..c678548 100644 --- a/Src/Myc.Signals.pas +++ b/Src/Myc.Signals.pas @@ -3,211 +3,91 @@ unit Myc.Signals; interface uses - System.SysUtils, Myc.Core.Notifier; + System.SysUtils; type - IMycState = interface; - IMycSubscriber = interface - // Interface for an entity that can be notified by a signal or latch. + // Interface for an entity that can be notified by a State or State. // Returns true if this subscriber expects further notifications from the source, false otherwise. function Notify: Boolean; end; - TMycState = class; + IMycState = interface; TMycSubscription = record private FState: IMycState; - FTag: TMycNotifyList.TTag; // Tag identifying this subscription within the notifier list. + FTag: Pointer; // Tag identifying this subscription within the notifier list. function GetState: IMycState; public - constructor Create(const AState: IMycState; ATag: TMycNotifyList.TTag); - // Unsubscribes from the associated signal. + constructor Create( const AState: IMycState; ATag: Pointer ); + // Unsubscribes from the associated State. procedure Unsubscribe; - class operator Initialize(out Dest: TMycSubscription); + class operator Initialize( out Dest: TMycSubscription ); property State: IMycState read GetState; end; IMycState = interface // Represents a subscribable state that can be queried. - {$region 'property access'} + {$REGION 'property access'} function GetIsSet: Boolean; - {$endregion} - // Subscribes a given subscriber to this signal. - function Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; - procedure Unsubscribe(Tag: TMycNotifyList.TTag); + {$ENDREGION} + // Subscribes a given subscriber to this State. + function Subscribe( Subscriber: IMycSubscriber ): TMycSubscription; + procedure Unsubscribe( Tag: Pointer ); // IsSet is true if the state has been reached or the condition is met. property IsSet: Boolean read GetIsSet; end; - TMycState = class abstract( TInterfacedObject, IMycState ) - strict private - class var - FNull: IMycState; - class constructor ClassCreate; - protected - function GetIsSet: Boolean; virtual; abstract; - public - function Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; virtual; abstract; - procedure Unsubscribe(Tag: TMycNotifyList.TTag); virtual; abstract; - property IsSet: Boolean read GetIsSet; - // Provides access to the singleton null latch instance (always set). - class property Null: IMycState read FNull; - end; - - // IMycFlag represents a base for signal-like objects that have a binary state (set/not set), - // can be notified (as an IMycSubscriber) to potentially change state, - // and whose state (IMycState) can be queried and subscribed to. - IMycFlag = interface(IMycSubscriber) - {$region 'property access'} - // Provides access to the IMycState interface of the flag. - function GetState: IMycState; - {$endregion} - property State: IMycState read GetState; - end; - // IMycLatch is a specific type of flag that, once set, remains set (non-resettable). // It typically becomes set when an internal countdown reaches zero. - IMycLatch = interface(IMycFlag) + 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. end; - // TMycLatch implements a countdown latch. - // It is initialized with a count. Calls to its Notify method (as an IMycSubscriber) - // decrement this count. When the count reaches zero, the latch transitions to the "set" - // state (IsSet becomes true), notifies its current subscribers once, and then remains set. - TMycLatch = class(TMycState, IMycLatch, IMycFlag) - strict private - FSubscribers: TMycNotifyList; // List of subscribers waiting for this latch to be set. - class var - FNull: IMycLatch; // Singleton instance of a latch that is always set. - class constructor ClassCreate; // Class constructor to initialize FNull. - private - [volatile] FCount: Integer; // The internal countdown value for the latch. - function GetState: IMycState; // Implementation for IMycLatch.GetState and IMycFlag.GetState. - protected - function GetIsSet: Boolean; override; final; // Implementation for IMycState.GetIsSet. - public - // Creates the latch with an initial count. - // If ACount is 0 or less, the latch is effectively pre-set (delegates to FNull via CreateLatch factory). - constructor Create(ACount: Integer); - destructor Destroy; override; - - // Factory method: creates a new countdown latch or returns the Null latch if Count <= 0. - class function CreateLatch(Count: Integer): IMycLatch; static; - - // IMycSignal implementation - function Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; override; - procedure Unsubscribe(Tag: TMycNotifyList.TTag); override; - - // IMycSubscriber implementation for TMycLatch itself. - // Decrements the internal count. If the count reaches zero, - // registered subscribers are notified, and the latch becomes permanently set. - function Notify: Boolean; - - // Provides access to the singleton null latch instance (always set). - class property Null: IMycLatch read FNull; - end; - // IMycDirty represents a resettable flag, typically indicating if a state is "dirty" (requiring attention) or "clean". // It inherits from IMycFlag, meaning it has a state, can be notified, and subscribed to. - IMycDirty = interface(IMycFlag) + IMycDirty = interface( IMycSubscriber ) + // Provides access to the IMycState interface of the flag. + function GetState: IMycState; // 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; end; - // TMycDirty implements a resettable "dirty flag". - // It can be explicitly set to dirty (via Notify) or reset to clean (via Reset). - // Subscribers are notified of relevant state changes. - TMycDirty = class(TMycState, IMycFlag, IMycDirty) - strict private - FSubscribers: TMycNotifyList; // List of subscribers interested in state changes of this dirty flag. + State = record private - [volatile] FFlag: Boolean; // Internal state: true if dirty/set, false if clean/reset. - function GetState: IMycState; // Implementation for IMycFlag.GetState. - protected - function GetIsSet: Boolean; override; final; // Implementation for IMycState.GetIsSet (true if dirty). + class function GetNull: IMycState; static; public - // Creates a new dirty flag, initially set to dirty (true). - constructor Create; - destructor Destroy; override; - - // Factory method to create a new TMycDirty instance. + class function CreateLatch( Count: Integer ): IMycLatch; static; class function CreateDirty: IMycDirty; static; - - // IMycSignal implementation - function Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; override; - procedure Unsubscribe(Tag: TMycNotifyList.TTag); override; - - // IMycSubscriber implementation for TMycDirty. - // Sets this flag to dirty (true). Notifies subscribers if it transitioned from clean to dirty. - function Notify: Boolean; - - // IMycDirty implementation. Resets the flag to clean (false). - function Reset: Boolean; + class function All( const States: TArray ): IMycState; static; + class function Any( const States: TArray ): IMycState; static; + class property Null: IMycState read GetNull; end; implementation uses - System.SyncObjs; // For TInterlocked - -type - // TMycNullState implements a "null object" pattern for IMycState. - // This state is always considered "set". - TMycNullState = class(TInterfacedObject, IMycState) - protected - // IMycState - function GetIsSet: Boolean; - function Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; - procedure Unsubscribe(Tag: TMycNotifyList.TTag); - public - constructor Create; - end; - -{ TMycNullState } - -constructor TMycNullState.Create; -begin - inherited Create; -end; - -function TMycNullState.GetIsSet: Boolean; -begin - Result := true; // Null state is always set. -end; - -function TMycNullState.Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; -begin - // Since the state is always set, notify the subscriber immediately. - if Assigned(Subscriber) then - begin - Subscriber.Notify; - end; - // No ongoing subscription is necessary or meaningful for a null state. - Result.Create(Self, nil); // Return an empty subscription. -end; - -procedure TMycNullState.Unsubscribe(Tag: TMycNotifyList.TTag); -begin - // Unsubscribing from a null state has no effect. -end; + Myc.Core.Notifier, Myc.Core.Signals; { TMycSubscription } -constructor TMycSubscription.Create(const AState: IMycState; ATag: - TMycNotifyList.TTag); +constructor TMycSubscription.Create( const AState: IMycState; ATag: + TMycNotifyList.TTag ); begin - Assert( Assigned(AState) ); + Assert( Assigned( AState ) ); FState := AState; FTag := ATag; end; procedure TMycSubscription.Unsubscribe; begin - FState.Unsubscribe(FTag); + FState.Unsubscribe( FTag ); FState := TMycState.Null; FTag := nil; end; @@ -217,243 +97,54 @@ begin Result := FState end; -class operator TMycSubscription.Initialize(out Dest: TMycSubscription); +class operator TMycSubscription.Initialize( out Dest: TMycSubscription ); begin Dest.FState := TMycState.Null; Dest.FTag := nil; end; -{ TMycLatch } +{ State } -constructor TMycLatch.Create(ACount: Integer); +class function State.CreateLatch( Count: Integer ): IMycLatch; begin - inherited Create; - Assert( ACount >= 0 ); - FCount := ACount; - FSubscribers.Create; + Result := TMycLatch.CreateLatch( Count ); end; -class constructor TMycLatch.ClassCreate; +class function State.All( const States: TArray ): IMycState; +var + Latch: IMycLatch; begin - // Create a singleton null latch instance that is initially (and always) set. - FNull := TMycLatch.Create(0); // Calls the instance constructor + Latch := CreateLatch( Length( States ) ); + for var i := 0 to High( States ) do + States[i].Subscribe( Latch ); + Result := Latch.State; end; -destructor TMycLatch.Destroy; +class function State.Any( const States: TArray ): IMycState; +var + Latch: IMycLatch; begin - FSubscribers.Destroy; - inherited; -end; - -class function TMycLatch.CreateLatch(Count: Integer): IMycLatch; -begin - // Factory method: returns a new latch or the shared Null latch if Count <= 0. - if Count > 0 then - Result := TMycLatch.Create(Count) // Instance constructor + if Length( States ) = 0 then + begin + Result := State.Null; + end else - Result := FNull; -end; - -function TMycLatch.Notify: Boolean; -var - currentCountAfterDecrement: Integer; - shouldNotifySubscribers: Boolean; -begin - FSubscribers.Lock; - try - currentCountAfterDecrement := TInterlocked.Decrement(FCount); - - if currentCountAfterDecrement < -MaxInt div 2 then - TInterlocked.Increment(FCount); // Defend against extreme underflow. - - shouldNotifySubscribers := (currentCountAfterDecrement = 0); // Notify only on transition to zero. - - if shouldNotifySubscribers then - begin - FSubscribers.Notify( - function(Subscriber: IMycSubscriber): Boolean - begin - Result := Subscriber.Notify; - end); - end; - - // Returns true if the latch has not yet been set by this Notify call (count > 0). - Result := currentCountAfterDecrement > 0; - - // If the latch is now set (or was already set), unadvise all subscribers. - // This ensures one-shot notification for the current set of subscribers. - if currentCountAfterDecrement <= 0 then - FSubscribers.UnadviseAll; - finally - FSubscribers.Release; + begin + Latch := CreateLatch( 1 ); + for var i := 0 to High( States ) do + States[i].Subscribe( Latch ); + Result := Latch.State; end; end; -function TMycLatch.GetIsSet: Boolean; +class function State.CreateDirty: IMycDirty; begin - // The latch is set if its count has reached zero or less. - Result := FCount <= 0; + Result := TMycDirty.CreateDirty; end; -function TMycLatch.GetState: IMycState; +class function State.GetNull: IMycState; begin - // TMycLatch itself implements IMycState. - exit(Self); -end; - -function TMycLatch.Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; -var - alreadySet: Boolean; -begin - if not Assigned(Subscriber) then - exit; - - Subscriber._AddRef; // Manage ref count during this method's logic. - try - FSubscribers.Lock; - try - alreadySet := (FCount <= 0); // Check if latch is already set. - - if alreadySet then - begin - // If already set, notify immediately; no persistent subscription needed. - Subscriber.Notify; - end - else - begin - // If not yet set, advise the subscriber. - Result.Create(Self, FSubscribers.Advise(Subscriber)); - end; - finally - FSubscribers.Release; - end; - finally - Subscriber._Release; - end; -end; - -procedure TMycLatch.Unsubscribe(Tag: TMycNotifyList.TTag); -begin - if Tag = nil then - exit; - - FSubscribers.Lock; - try - FSubscribers.Unadvise(Tag); - finally - FSubscribers.Release; - end; -end; - -{ TMycDirty } - -constructor TMycDirty.Create; -begin - inherited Create; - FFlag := true; // A new dirty flag is initially considered dirty. - FSubscribers.Create; -end; - -class function TMycDirty.CreateDirty: IMycDirty; -begin - // Factory method to create a new TMycDirty instance. - Result := TMycDirty.Create; -end; - -destructor TMycDirty.Destroy; -begin - FSubscribers.Destroy; // Clean up the subscriber list. - inherited; -end; - -function TMycDirty.Reset: Boolean; -begin - // Sets the flag to false (clean) and returns true if it was previously true (dirty). - Result := TInterlocked.Exchange(FFlag, false); -end; - -function TMycDirty.GetIsSet: Boolean; -begin - // IsSet is true if the flag is dirty (FFlag = true). - Result := FFlag; -end; - -function TMycDirty.GetState: IMycState; -begin - // TMycDirty itself implements IMycState. - exit(Self); -end; - -function TMycDirty.Notify: Boolean; -var - wasPreviouslyClean: Boolean; -begin - FSubscribers.Lock; - try - // Set the flag to true (dirty) and check if it was previously false (clean). - wasPreviouslyClean := not TInterlocked.Exchange(FFlag, true); - - if wasPreviouslyClean then // Only notify subscribers if state changed from clean to dirty. - begin - FSubscribers.Notify( - function(Subscriber: IMycSubscriber): Boolean - begin - Result := Subscriber.Notify; - end); - end; - // The return value of this Notify (as an IMycSubscriber) indicates if this - // TMycDirty instance itself would want more notifications if it were subscribed to something. - // Here, it reflects whether a state change to dirty occurred due to this call. - Result := wasPreviouslyClean; - finally - FSubscribers.Release; - end; -end; - -function TMycDirty.Subscribe(const Subscriber: IMycSubscriber): TMycSubscription; -begin - if not Assigned(Subscriber) then - exit; - - // For TMycDirty, we always add the subscriber and then check if we need to notify immediately. - // Ref counting for the subscriber interface is assumed to be handled by TMycNotifyList.Advise/Unadvise. - // Or, if explicit management is needed like in TMycLatch, it should be added. - // For consistency with TMycLatch, let's add AddRef/Release here too. - Subscriber._AddRef; - try - FSubscribers.Lock; - try - // Add subscriber regardless of current state. - Result.Create(Self, FSubscribers.Advise(Subscriber)); - if FFlag then // If currently dirty, notify the new subscriber immediately. - begin - Subscriber.Notify; - end; - finally - FSubscribers.Release; - end; - finally - Subscriber._Release; - end; -end; - -procedure TMycDirty.Unsubscribe(Tag: TMycNotifyList.TTag); -begin - if Tag = nil then - exit; - - FSubscribers.Lock; - try - FSubscribers.Unadvise(Tag); - finally - FSubscribers.Release; - end; -end; - -class constructor TMycState.ClassCreate; -begin - // Create a singleton null latch instance that is initially (and always) set. - FNull := TMycNullState.Create(); // Calls the instance constructor + Result := TMycState.Null; end; end. diff --git a/Test/MycTests.dpr b/Test/MycTests.dpr index e1a53fc..c0102d3 100644 --- a/Test/MycTests.dpr +++ b/Test/MycTests.dpr @@ -26,7 +26,8 @@ uses Myc.Futures in '..\Src\Myc.Futures.pas', TestFutures in 'TestFutures.pas', Myc.TaskManager in '..\Src\Myc.TaskManager.pas', - Myc.Core.Futures in '..\Src\Myc.Core.Futures.pas'; + Myc.Core.Futures in '..\Src\Myc.Core.Futures.pas', + Myc.Core.Signals in '..\Src\Myc.Core.Signals.pas'; { keep comment here to protect the following conditional from being removed by the IDE when adding a unit } {$IFNDEF TESTINSIGHT} diff --git a/Test/MycTests.dproj b/Test/MycTests.dproj index 1b9ad3b..e473c6c 100644 --- a/Test/MycTests.dproj +++ b/Test/MycTests.dproj @@ -126,6 +126,7 @@ $(PostBuildEvent)]]> + Base diff --git a/Test/TestFutures.pas b/Test/TestFutures.pas index dd667a4..642f22b 100644 --- a/Test/TestFutures.pas +++ b/Test/TestFutures.pas @@ -94,7 +94,7 @@ const CExpectedResult = 42; begin // Use TMycLatch.Null for an already set init state [cite: 71, 81, 206, 216, 324, 334] - LInitStateAsState := TMycLatch.Null.State; // Get IMycState from IMycLatch [cite: 61, 196, 314] + LInitStateAsState := State.Null; LFuture := TMycInitStateFuncFuture.Create(FTaskFactory, LInitStateAsState, function: Integer @@ -120,7 +120,7 @@ var const CExpectedResult = 'ChainCompleted'; begin - LInitLatch := TMycLatch.CreateLatch(1); // Create an init state that is not yet set [cite: 77, 212, 330] + LInitLatch := State.CreateLatch(1); // Create an init state that is not yet set [cite: 77, 212, 330] LFuture := TMycInitStateFuncFuture.Create(FTaskFactory, LInitLatch.State, function: string @@ -155,7 +155,7 @@ const begin LExpectedExceptionRaisedByFactory := False; LLocalTaskFactory := TMycTaskFactory.Create; - LInitStateAsState := TMycLatch.Null.State; // Immediate execution + LInitStateAsState := State.Null; // Immediate execution LFuture := TMycInitStateFuncFuture.Create(LLocalTaskFactory, LInitStateAsState, function: Integer @@ -208,7 +208,7 @@ var LFuture: IMycFuture; LInitLatch: IMycLatch; begin - LInitLatch := TMycLatch.CreateLatch(1); + LInitLatch := State.CreateLatch(1); LFuture := TMycInitStateFuncFuture.Create(FTaskFactory, LInitLatch.State, function: Integer @@ -250,7 +250,7 @@ begin FProcExecutionCount := 0; // Reset for this test // Gate Latch: MainFuture waits for this latch, which needs 2 notifications. - LGateLatch := TMycLatch.CreateLatch(2); // [cite: 77, 212, 330] + LGateLatch := State.CreateLatch(2); // [cite: 77, 212, 330] // Create MainFuture, AInitState is the GateLatch's state. LMainFuture := TMycInitStateFuncFuture.Create(FTaskFactory, LGateLatch.State, @@ -262,7 +262,7 @@ begin // Setup Prerequisite Futures // PrerequisiteFuture1 - LInitStateP1 := TMycLatch.CreateLatch(1); // Controllable init state for PF1 + LInitStateP1 := State.CreateLatch(1); // Controllable init state for PF1 LPrerequisiteFuture1 := TMycInitStateFuncFuture.Create(FTaskFactory, LInitStateP1.State, function: Integer begin @@ -273,7 +273,7 @@ begin Subscriptions[1] := LPrerequisiteFuture1.Done.Subscribe(LSub1); // Subscribe to PF1's completion [cite: 56, 188, 306] // PrerequisiteFuture2 - LInitStateP2 := TMycLatch.CreateLatch(1); // Controllable init state for PF2 + LInitStateP2 := State.CreateLatch(1); // Controllable init state for PF2 LPrerequisiteFuture2 := TMycInitStateFuncFuture.Create(FTaskFactory, LInitStateP2.State, function: Integer begin @@ -322,7 +322,7 @@ begin LFlagFutureBRan := False; Self.FSharedCounter := 0; // Reset shared counter for this test - LTriggerLatch := TMycLatch.CreateLatch(1); // Single trigger [cite: 77, 212, 330] + LTriggerLatch := State.CreateLatch(1); // Single trigger [cite: 77, 212, 330] // Future A LFutureA := TMycInitStateFuncFuture.Create(FTaskFactory, LTriggerLatch.State, diff --git a/Test/TestSignals_Dirty.pas b/Test/TestSignals_Dirty.pas index 2424acb..ed62c00 100644 --- a/Test/TestSignals_Dirty.pas +++ b/Test/TestSignals_Dirty.pas @@ -105,7 +105,7 @@ end; function TTestMycDirtyFlag.CreateAndPrepareDirtyFlag(StartDirty: Boolean = True): IMycDirty; begin - Result := TMycDirty.CreateDirty; // Initially dirty + Result := State.CreateDirty; // Initially dirty if not StartDirty then Result.Reset; // Reset to make it clean Assert.AreEqual(StartDirty, Result.State.IsSet, 'CreateAndPrepareDirtyFlag initial state incorrect.'); @@ -127,7 +127,7 @@ procedure TTestMycDirtyFlag.TestCreate_InitialStateIsDirty; var dirtyFlag: IMycDirty; begin - dirtyFlag := TMycDirty.CreateDirty; + dirtyFlag := State.CreateDirty; Assert.IsTrue(dirtyFlag.State.IsSet, 'Newly created dirty flag should be IsSet (dirty).'); end; diff --git a/Test/TestSignals_Latch.pas b/Test/TestSignals_Latch.pas index 123f60d..1ab42a1 100644 --- a/Test/TestSignals_Latch.pas +++ b/Test/TestSignals_Latch.pas @@ -124,7 +124,7 @@ var latch: IMycLatch; begin // TMycLatch.CreateLatch returns TMycLatch.Null if InitialCount <= 0 - latch := TMycLatch.CreateLatch(InitialCount); + latch := State.CreateLatch(InitialCount); Assert.AreEqual(ExpectedIsSet, latch.State.IsSet, 'Latch initial IsSet state mismatch for count ' + IntToStr(InitialCount) + '.'); end; @@ -133,7 +133,7 @@ var latch: IMycLatch; returnedValueFromNotify: Boolean; begin - latch := TMycLatch.CreateLatch(InitialCount); + latch := State.CreateLatch(InitialCount); returnedValueFromNotify := latch.Notify; // This is IMycLatch (as IMycSubscriber).Notify Assert.AreEqual(ExpectedReturn, returnedValueFromNotify, 'Unexpected return value from Latch.Notify call for initial count ' + IntToStr(InitialCount) + '.'); @@ -144,7 +144,7 @@ procedure TTestMycLatch.TestNotify_DecrementsCounter_StateChanges; var latch: IMycLatch; begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); Assert.IsFalse(latch.State.IsSet, 'Latch should initially not be set (Count=1).'); latch.Notify; // Count becomes 0 Assert.IsTrue(latch.State.IsSet, 'Latch should be set after Notify (Count became 0).'); @@ -154,7 +154,7 @@ procedure TTestMycLatch.TestNotify_MultipleNotifies_CounterBecomesNegativeAndSta var latch: IMycLatch; begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); latch.Notify; // Count becomes 0, IsSet = True Assert.IsTrue(latch.State.IsSet, 'Latch should be set after first Notify.'); latch.Notify; // Count becomes -1, IsSet should remain True @@ -169,7 +169,7 @@ var mockSub: TMockSubscriber; subscription: TMycSubscription; begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); mockSub := TMockSubscriber.Create; subscription := latch.State.Subscribe(mockSub); // Subscribing to the Latch's state @@ -188,7 +188,7 @@ var mockSub1, mockSub2, mockSub3: TMockSubscriber; sub1, sub2, sub3: TMycSubscription; // Keep subscriptions in scope begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); mockSub1 := TMockSubscriber.Create; mockSub2 := TMockSubscriber.Create; mockSub3 := TMockSubscriber.Create; @@ -210,7 +210,7 @@ var mockSub: TMockSubscriber; subscription: TMycSubscription; begin - latch := TMycLatch.CreateLatch(2); // Count = 2 + latch := State.CreateLatch(2); // Count = 2 mockSub := TMockSubscriber.Create; subscription := latch.State.Subscribe(mockSub); @@ -225,7 +225,7 @@ var mockSub: TMockSubscriber; subscription: TMycSubscription; begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); mockSub := TMockSubscriber.Create; subscription := latch.State.Subscribe(mockSub); @@ -242,7 +242,7 @@ var mockSub1, mockSub2: TMockSubscriber; subscription1, subscription2: TMycSubscription; begin - latch := TMycLatch.CreateLatch(1); // Create with count 1 + latch := State.CreateLatch(1); // Create with count 1 mockSub1 := TMockSubscriber.Create; subscription1 := latch.State.Subscribe(mockSub1); // Subscribe before set @@ -270,8 +270,8 @@ var mockSubForB: TMockSubscriber; subHandle_B_listens_A, subHandle_Mock_listens_B: TMycSubscription; begin - latchA := TMycLatch.CreateLatch(1); - latchB := TMycLatch.CreateLatch(1); // latchB is an IMycSubscriber + latchA := State.CreateLatch(1); + latchB := State.CreateLatch(1); // latchB is an IMycSubscriber mockSubForB := TMockSubscriber.Create; subHandle_Mock_listens_B := latchB.State.Subscribe(mockSubForB); @@ -295,9 +295,9 @@ var mockSubForC: TMockSubscriber; sub_Mock_C, sub_C_B, sub_B_A: TMycSubscription; begin - latchA := TMycLatch.CreateLatch(1); - latchB := TMycLatch.CreateLatch(1); - latchC := TMycLatch.CreateLatch(1); + latchA := State.CreateLatch(1); + latchB := State.CreateLatch(1); + latchC := State.CreateLatch(1); mockSubForC := TMockSubscriber.Create; sub_Mock_C := latchC.State.Subscribe(mockSubForC); @@ -320,8 +320,8 @@ var 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. - latchA := TMycLatch.CreateLatch(2); - latchB := TMycLatch.CreateLatch(1); + latchA := State.CreateLatch(2); + latchB := State.CreateLatch(1); mockSubForB := TMockSubscriber.Create; sub_Mock_B := latchB.State.Subscribe(mockSubForB); @@ -347,7 +347,7 @@ var mockSub: TMockSubscriber; subscription: TMycSubscription; begin - latch := TMycLatch.CreateLatch(0); // Returns TMycLatch.Null which is set. + latch := State.CreateLatch(0); // Returns TMycLatch.Null which is set. mockSub := TMockSubscriber.Create; subscription := latch.State.Subscribe(mockSub); // TMycLatch.Subscribe notifies immediately if already set. @@ -362,7 +362,7 @@ var mockSub: TMockSubscriber; subscription: TMycSubscription; begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); mockSub := TMockSubscriber.Create; subscription := latch.State.Subscribe(mockSub); @@ -381,7 +381,7 @@ var mockSub: TMockSubscriber; subscription: TMycSubscription; begin - latch := TMycLatch.CreateLatch(3); + latch := State.CreateLatch(3); latch.Notify; // Count -> 2 latch.Notify; // Count -> 1 @@ -404,7 +404,7 @@ var mockSub1, mockSub2: TMockSubscriber; subscription1, subscription2: TMycSubscription; begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); mockSub1 := TMockSubscriber.Create; mockSub2 := TMockSubscriber.Create; @@ -432,7 +432,7 @@ var mockSub: TMockSubscriber; // 'subscription' will be declared in an inner scope to control its finalization begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); mockSub := TMockSubscriber.Create; var noException: Boolean := True; @@ -468,7 +468,7 @@ var mockSubInitial, mockSubNew: TMockSubscriber; subscriptionInitial, subscriptionNew: TMycSubscription; begin - latch := TMycLatch.CreateLatch(1); + latch := State.CreateLatch(1); mockSubInitial := TMockSubscriber.Create; subscriptionInitial := latch.State.Subscribe(mockSubInitial); diff --git a/Test/TestTasks.pas b/Test/TestTasks.pas index 634739d..e9f057d 100644 --- a/Test/TestTasks.pas +++ b/Test/TestTasks.pas @@ -8,7 +8,7 @@ uses System.Classes, System.SyncObjs, Myc.Core.Tasks, - Myc.Signals, // Uses TMycLatch.CreateLatch and TMycLatch.Null + Myc.Signals, Myc.Core.Signals, Myc.Core.Atomic; type