Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

301 рядки
11 KiB

  1. unit uutlEvent;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, syncobjs,
  6. uutlCommon, uutlGenerics;
  7. type
  8. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. TutlEventType = byte;
  10. TutlEventTypes = set of TutlEventType;
  11. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12. IutlEvent = interface(IUnknown)
  13. ['{FC7AA96D-9C2C-42AD-A680-DE55341F2B35}']
  14. end;
  15. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. TutlEventList = class(specialize TutlSimpleList<IutlEvent>)
  17. public
  18. constructor Create; reintroduce;
  19. end;
  20. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. TutlEvent = class(TInterfacedObject, IutlEvent)
  22. private
  23. fSender: TObject;
  24. fEventType: TutlEventType;
  25. fTimestamp: Single;
  26. public
  27. property Sender: TObject read fSender;
  28. property EventType: TutlEventType read fEventType;
  29. property Timestamp: Single read fTimestamp;
  30. constructor Create(const aSender: TObject; const aEventType: TutlEventType);
  31. end;
  32. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  33. IutlEventListener = interface(IUnknown)
  34. ['{BC45E26B-96F7-4151-87F1-C330C8C668E5}']
  35. procedure DispatchEvent(aEvent: IutlEvent);
  36. end;
  37. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  38. TutlEventListenerSet = class(specialize TutlHashSetBase<IutlEventListener>)
  39. private type
  40. TComparer = class(TInterfacedObject, IComparer)
  41. function Compare(const i1, i2: IutlEventListener): Integer;
  42. end;
  43. function GetEmpty: Boolean;
  44. public
  45. property Empty: Boolean read GetEmpty;
  46. procedure DispatchEvent(aEvent: IutlEvent); virtual;
  47. function RegisterListener(const aListener: IutlEventListener): Boolean;
  48. function UnregisterListener(const aListener: IutlEventListener): Boolean;
  49. constructor Create;
  50. end;
  51. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  52. TutlEventListenerCallback = class(TInterfacedObject, IutlEventListener)
  53. public type
  54. TCallback = procedure(aEvent: IutlEvent) of object;
  55. private
  56. fCallback: TCallback;
  57. private { IEventListener }
  58. procedure DispatchEvent(aEvent: IutlEvent);
  59. public
  60. constructor Create(const aCallback: TCallback);
  61. end;
  62. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. TutlEventListenerAsync = class(TutlInterfaceNoRefCount, IutlEventListener)
  64. private
  65. fEventLock: TCriticalSection;
  66. fListenerLock: TCriticalSection;
  67. fEvents: TutlEventList;
  68. fListener: TutlEventListenerSet;
  69. function PopEvent: IutlEvent;
  70. private { IEventListener }
  71. procedure DispatchEvent(aEvent: IutlEvent);
  72. public
  73. function RegisterListener(const aListener: IutlEventListener): Boolean;
  74. function UnregisterListener(const aListener: IutlEventListener): Boolean;
  75. procedure DispatchEvents;
  76. constructor Create;
  77. destructor Destroy; override;
  78. end;
  79. implementation
  80. uses
  81. {$IFDEF LOG_DEBUG}
  82. uutlLogger,
  83. {$ENDIF}
  84. uutlTiming;
  85. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  86. //TutlEventList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  88. constructor TutlEventList.Create;
  89. begin
  90. inherited Create(true);
  91. end;
  92. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  93. //TutlEvent//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  94. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  95. constructor TutlEvent.Create(const aSender: TObject; const aEventType: TutlEventType);
  96. begin
  97. inherited Create;
  98. fSender := aSender;
  99. fEventType := aEventType;
  100. fTimestamp := GetMicroTime / 1000000;
  101. {$IFDEF LOG_DEBUG}
  102. utlLogger.Debug(self, 'dispatch event (Sender=%s[%p]; EventType=%0.10d; Timestamp=%10.5f)', [ fSender.ClassName, Pointer(fSender), fEventType, fTimestamp ]);
  103. {$ENDIF}
  104. end;
  105. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  106. //TutlEventListenerSet.TComparer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  107. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  108. function TutlEventListenerSet.TComparer.Compare(const i1, i2: IutlEventListener): Integer;
  109. begin
  110. if (Pointer(i1) < Pointer(i2)) then
  111. result := -1
  112. else if (Pointer(i1) > Pointer(i2)) then
  113. result := 1
  114. else
  115. result := 0;
  116. end;
  117. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  118. //TutlEventListenerSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  119. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  120. function TutlEventListenerSet.GetEmpty: Boolean;
  121. begin
  122. result := (GetCount = 0);
  123. end;
  124. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  125. procedure TutlEventListenerSet.DispatchEvent(aEvent: IutlEvent);
  126. var
  127. l: IutlEventListener;
  128. begin
  129. for l in self do
  130. l.DispatchEvent(aEvent);
  131. end;
  132. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133. function TutlEventListenerSet.RegisterListener(const aListener: IutlEventListener): Boolean;
  134. var
  135. i: Integer;
  136. begin
  137. result := (SearchItem(0, List.Count-1, aListener, i) < 0);
  138. if result then
  139. InsertIntern(i, aListener);
  140. end;
  141. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. function TutlEventListenerSet.UnregisterListener(const aListener: IutlEventListener): Boolean;
  143. var
  144. i, tmp: Integer;
  145. begin
  146. i := SearchItem(0, List.Count-1, aListener, tmp);
  147. result := (i >= 0);
  148. if result then
  149. DeleteIntern(i);
  150. end;
  151. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  152. constructor TutlEventListenerSet.Create;
  153. begin
  154. inherited Create(TComparer.Create, true);
  155. end;
  156. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  157. //TutlEventListenerCallback//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  158. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  159. procedure TutlEventListenerCallback.DispatchEvent(aEvent: IutlEvent);
  160. begin
  161. fCallback(aEvent);
  162. end;
  163. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  164. constructor TutlEventListenerCallback.Create(const aCallback: TCallback);
  165. begin
  166. inherited Create;
  167. if not Assigned(aCallback) then
  168. raise EArgumentException.Create('aCallback is not assigned');
  169. fCallback := aCallback;
  170. end;
  171. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  172. //TutlEventListenerAsync/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  173. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. function TutlEventListenerAsync.PopEvent: IutlEvent;
  175. begin
  176. fEventLock.Enter;
  177. try
  178. if (fEvents.Count > 0)
  179. then result := fEvents.PopFirst(false)
  180. else result := nil;
  181. finally
  182. fEventLock.Leave;
  183. end;
  184. end;
  185. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  186. procedure TutlEventListenerAsync.DispatchEvent(aEvent: IutlEvent);
  187. begin
  188. fEventLock.Enter;
  189. try
  190. fEvents.Add(aEvent);
  191. finally
  192. fEventLock.Leave;
  193. end;
  194. end;
  195. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  196. function TutlEventListenerAsync.RegisterListener(const aListener: IutlEventListener): Boolean;
  197. begin
  198. fListenerLock.Enter;
  199. try
  200. result := fListener.RegisterListener(aListener);
  201. finally
  202. fListenerLock.Leave;
  203. end;
  204. end;
  205. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  206. function TutlEventListenerAsync.UnregisterListener(const aListener: IutlEventListener): Boolean;
  207. begin
  208. fListenerLock.Enter;
  209. try
  210. result := fListener.UnregisterListener(aListener);
  211. finally
  212. fListenerLock.Leave;
  213. end;
  214. end;
  215. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  216. procedure TutlEventListenerAsync.DispatchEvents;
  217. var
  218. e: IutlEvent;
  219. begin
  220. repeat
  221. e := PopEvent;
  222. if Assigned(e) then begin
  223. fListenerLock.Enter;
  224. try
  225. fListener.DispatchEvent(e);
  226. finally
  227. fListenerLock.Leave;
  228. end;
  229. end;
  230. until not Assigned(e);
  231. end;
  232. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  233. constructor TutlEventListenerAsync.Create;
  234. begin
  235. inherited Create;
  236. fEventLock := TCriticalSection.Create;
  237. fListenerLock := TCriticalSection.Create;
  238. fEvents := TutlEventList.Create;
  239. fListener := TutlEventListenerSet.Create;
  240. end;
  241. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  242. destructor TutlEventListenerAsync.Destroy;
  243. begin
  244. fEventLock.Enter;
  245. fListenerLock.Enter;
  246. try
  247. FreeAndNil(fEvents);
  248. FreeAndNil(fListener);
  249. finally
  250. fListenerLock.Leave;
  251. fEventLock.Leave;
  252. end;
  253. FreeAndNil(fEventLock);
  254. FreeAndNil(fListenerLock);
  255. inherited Destroy;
  256. end;
  257. end.