Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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