This commit is contained in:
Michael Schimmel
2025-06-06 01:22:25 +02:00
parent 73d656cda5
commit c4d8607d17
13 changed files with 393 additions and 173 deletions
+44 -31
View File
@@ -12,8 +12,8 @@ type
// This state is always considered "set".
TMycNullSignal = class(TInterfacedObject, TSignal.ISignal)
public
function Subscribe(Subscriber: IMycSubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
function Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
end;
// TMycNullState implements a "null object" pattern for IMycState.
@@ -27,29 +27,31 @@ type
// A state that acts as an event. It's state ist always set and it will always Trigger it's subscribers, if it gets notified by itself.
TMycEvent = class(TInterfacedObject, TSignal.ISignal, TEvent.IEvent)
strict private
FSubscribers: TMycNotifyList<IMycSubscriber>;
FSubscribers: TMycNotifyList<TSignal.ISubscriber>;
protected
function GetSignal: TSignal;
function GetIsSet: Boolean;
public
constructor Create;
destructor Destroy; override;
function Subscribe(Subscriber: IMycSubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
procedure Trigger;
function Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
function Notify: Boolean;
end;
TMycNullEvent = class(TMycNullSignal, TEvent.IEvent)
private
procedure Trigger;
function GetSignal: TSignal;
function Notify: Boolean;
end;
// TMycLatch implements a countdown latch.
// It is initialized with a count. Calls to its Notify method (as an IMycSubscriber)
// It is initialized with a count. Calls to its Notify method (as an TSignal.ISubscriber)
// 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(TInterfacedObject, TState.IState, TLatch.ILatch)
strict private
FSubscribers: TMycNotifyList<IMycSubscriber>; // List of subscribers waiting for this latch to be set.
FSubscribers: TMycNotifyList<TSignal.ISubscriber>; // List of subscribers waiting for this latch to be set.
private
[volatile]
FCount: Integer; // The internal countdown value for the latch.
@@ -63,10 +65,10 @@ type
destructor Destroy; override;
// ISignal implementation
function Subscribe(Subscriber: IMycSubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
function Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
// IMycSubscriber implementation for TMycLatch itself.
// TSignal.ISubscriber 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;
@@ -83,7 +85,7 @@ type
// Subscribers are notified of relevant state changes.
TMycFlag = class(TInterfacedObject, TState.IState, TFlag.IFlag)
strict private
FSubscribers: TMycNotifyList<IMycSubscriber>; // List of subscribers interested in state changes of this dirty flag.
FSubscribers: TMycNotifyList<TSignal.ISubscriber>; // 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.
@@ -98,10 +100,10 @@ type
// Factory method to create a new TMycFlag instance.
class function CreateDirty: TFlag.IFlag; static;
function Subscribe(Subscriber: IMycSubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
function Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
procedure Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
// IMycSubscriber implementation for TMycFlag.
// TSignal.ISubscriber implementation for TMycFlag.
// Sets this flag to dirty (true). Notifies subscribers if it transitioned from clean to dirty.
function Notify: Boolean;
@@ -145,17 +147,23 @@ begin
Result := true;
end;
procedure TMycEvent.Trigger;
function TMycEvent.GetSignal: TSignal;
begin
Result := Self;
end;
function TMycEvent.Notify: Boolean;
begin
FSubscribers.Lock;
try
FSubscribers.Notify(function(Subscriber: IMycSubscriber): Boolean begin Result := Subscriber.Notify; end);
FSubscribers.Notify(function(Subscriber: TSignal.ISubscriber): Boolean begin Result := Subscriber.Notify; end);
finally
FSubscribers.Release;
end;
Result := true;
end;
function TMycEvent.Subscribe(Subscriber: IMycSubscriber): Pointer;
function TMycEvent.Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
begin
Result := nil;
if not Assigned(Subscriber) then
@@ -170,7 +178,7 @@ begin
end;
end;
procedure TMycEvent.Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
procedure TMycEvent.Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
begin
if Tag = nil then
exit;
@@ -227,7 +235,7 @@ begin
if shouldNotifySubscribers then
begin
FSubscribers.Notify(function(Subscriber: IMycSubscriber): Boolean begin Result := Subscriber.Notify; end);
FSubscribers.Notify(function(Subscriber: TSignal.ISubscriber): Boolean begin Result := Subscriber.Notify; end);
end;
// Returns true if the latch has not yet been set by this Notify call (count > 0).
@@ -254,7 +262,7 @@ begin
Result := Self;
end;
function TMycLatch.Subscribe(Subscriber: IMycSubscriber): Pointer;
function TMycLatch.Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
var
alreadySet: Boolean;
begin
@@ -281,7 +289,7 @@ begin
end;
end;
procedure TMycLatch.Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
procedure TMycLatch.Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
begin
if Tag = nil then
exit;
@@ -361,9 +369,9 @@ begin
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);
FSubscribers.Notify(function(Subscriber: TSignal.ISubscriber): Boolean begin Result := Subscriber.Notify; end);
end;
// The return value of this Notify (as an IMycSubscriber) indicates if this
// The return value of this Notify (as an TSignal.ISubscriber) indicates if this
// TMycFlag 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;
@@ -372,7 +380,7 @@ begin
end;
end;
function TMycFlag.Subscribe(Subscriber: IMycSubscriber): Pointer;
function TMycFlag.Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
begin
if not Assigned(Subscriber) then
exit(nil);
@@ -394,7 +402,7 @@ begin
end;
end;
procedure TMycFlag.Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
procedure TMycFlag.Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
begin
if Tag = nil then
exit;
@@ -407,12 +415,17 @@ begin
end;
end;
procedure TMycNullEvent.Trigger;
function TMycNullEvent.GetSignal: TSignal;
begin
// nop
Result := TSignal.Null;
end;
function TMycNullSignal.Subscribe(Subscriber: IMycSubscriber): Pointer;
function TMycNullEvent.Notify: Boolean;
begin
Result := false;
end;
function TMycNullSignal.Subscribe(Subscriber: TSignal.ISubscriber): Pointer;
begin
// Since the state is always set, notify the subscriber immediately.
if Assigned(Subscriber) then
@@ -423,7 +436,7 @@ begin
Result := nil;
end;
procedure TMycNullSignal.Unsubscribe(Tag: TMycNotifyList<IMycSubscriber>.TTag);
procedure TMycNullSignal.Unsubscribe(Tag: TMycNotifyList<TSignal.ISubscriber>.TTag);
begin
// Unsubscribing from a null state has no effect.
end;