BaseQueue.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. unit BaseQueue;
  2. interface
  3. uses
  4. SyncObjs;
  5. {$IFDEF DEBUG}
  6. {$DEFINE DEBUG_ON}
  7. {$ENDIF}
  8. type
  9. PQueueData = ^TQueueData;
  10. TQueueData = record
  11. Data: Pointer;
  12. Next: PQueueData;
  13. end;
  14. TBaseQueue = class(TObject)
  15. private
  16. FName: String;
  17. FLocker: TCriticalSection;
  18. FCount: Integer;
  19. FHead: PQueueData;
  20. FTail: PQueueData;
  21. {$IFDEF DEBUG_ON}
  22. FPopCounter:Integer;
  23. FPushCounter:Integer;
  24. {$ENDIF}
  25. /// <summary>
  26. /// 清空所有数据
  27. /// </summary>
  28. procedure clear;
  29. function innerPop: PQueueData;
  30. procedure innerAddToTail(AData: PQueueData);
  31. procedure innerAddToHead(AData: PQueueData);
  32. public
  33. constructor Create;
  34. destructor Destroy; override;
  35. function IsEmpty: Boolean;
  36. function size:Integer;
  37. function Pop: Pointer;overload;
  38. function Pop(var outPointer:Pointer):Boolean;overload;
  39. /// <summary>
  40. /// add to tail
  41. /// </summary>
  42. procedure Push(AData: Pointer);
  43. /// <summary>
  44. /// add to head
  45. /// </summary>
  46. procedure AddToHead(AData: Pointer);
  47. /// <summary>
  48. /// invoke Only Data Pointer is TObject
  49. /// </summary>
  50. procedure FreeDataObject;
  51. /// <summary>
  52. /// dispose all data
  53. /// </summary>
  54. procedure DisposeAllData;
  55. property Name: String read FName write FName;
  56. end;
  57. type
  58. /// <summary>
  59. /// without lock
  60. /// </summary>
  61. TSimpleQueue = class(TObject)
  62. private
  63. FName: String;
  64. FCount: Integer;
  65. FHead: PQueueData;
  66. FTail: PQueueData;
  67. {$IFDEF DEBUG_ON}
  68. FPopCounter:Integer;
  69. FPushCounter:Integer;
  70. {$ENDIF}
  71. /// <summary>
  72. /// 清空所有数据
  73. /// </summary>
  74. procedure clear;
  75. function innerPop: PQueueData;
  76. procedure innerAddToTail(AData: PQueueData);
  77. procedure innerAddToHead(AData: PQueueData);
  78. public
  79. constructor Create;
  80. destructor Destroy; override;
  81. function IsEmpty: Boolean;
  82. function size:Integer;
  83. function Pop: Pointer;overload;
  84. function Pop(var outPointer:Pointer):Boolean;overload;
  85. /// <summary>
  86. /// add to tail
  87. /// </summary>
  88. procedure Push(AData: Pointer);
  89. /// <summary>
  90. /// add to head
  91. /// </summary>
  92. procedure AddToHead(AData: Pointer);
  93. /// <summary>
  94. /// invoke Only Data Pointer is TObject
  95. /// </summary>
  96. procedure FreeDataObject;
  97. /// <summary>
  98. /// dispose all data
  99. /// </summary>
  100. procedure DisposeAllData;
  101. property Name: String read FName write FName;
  102. end;
  103. implementation
  104. type
  105. /// <summary>
  106. /// reference TJobPool in qdac3
  107. /// </summary>
  108. TQueueDataPool = class
  109. protected
  110. FFirst: PQueueData;
  111. FCount: Integer;
  112. FSize: Integer;
  113. FLocker: TCriticalSection;
  114. {$IFDEF DEBUG_ON}
  115. FPopCounter:Integer;
  116. FPushCounter:Integer;
  117. {$ENDIF}
  118. public
  119. constructor Create(AMaxSize: Integer = 2048); overload;
  120. destructor Destroy; override;
  121. procedure Push(pvQueueData: PQueueData);
  122. function Pop: PQueueData;
  123. property Count: Integer read FCount;
  124. property Size: Integer read FSize write FSize;
  125. end;
  126. var
  127. // data pool of PQueueData
  128. queueDataPool :TQueueDataPool;
  129. function IsDebugMode: Boolean;
  130. begin
  131. {$IFDEF MSWINDOWS}
  132. {$warn symbol_platform off}
  133. Result := Boolean(DebugHook);
  134. {$warn symbol_platform on}
  135. {$ELSE}
  136. Result := false;
  137. {$ENDIF}
  138. end;
  139. constructor TBaseQueue.Create;
  140. begin
  141. inherited Create;
  142. FLocker := TCriticalSection.Create();
  143. FHead := nil;
  144. FTail := nil;
  145. FCount := 0;
  146. FName := 'BaseQueue';
  147. end;
  148. destructor TBaseQueue.Destroy;
  149. begin
  150. {$IFDEF DEBUG_ON}
  151. if IsDebugMode then
  152. Assert(FPopCounter = FPushCounter, ('[' + FName + ']PopCounter <> PushCounter'));
  153. {$ENDIF}
  154. Clear;
  155. FLocker.Free;
  156. inherited Destroy;
  157. end;
  158. procedure TBaseQueue.DisposeAllData;
  159. var
  160. lvData:Pointer;
  161. begin
  162. while True do
  163. begin
  164. lvData := nil;
  165. if Pop(lvData) then
  166. begin
  167. if lvData = nil then
  168. begin
  169. lvData := nil;
  170. end else
  171. begin
  172. Dispose(lvData);
  173. end;
  174. end else
  175. begin
  176. Break;
  177. end;
  178. end;
  179. end;
  180. { TBaseQueue }
  181. procedure TBaseQueue.AddToHead(AData: Pointer);
  182. var
  183. lvTemp:PQueueData;
  184. begin
  185. lvTemp := queueDataPool.Pop;
  186. lvTemp.Data := AData;
  187. innerAddToHead(lvTemp);
  188. end;
  189. procedure TBaseQueue.clear;
  190. var
  191. ANext: PQueueData;
  192. begin
  193. FLocker.Enter;
  194. try
  195. if FHead = nil then Exit;
  196. while FHead.Next <> nil do
  197. begin
  198. ANext := FHead.Next;
  199. queueDataPool.Push(FHead);
  200. FHead := ANext;
  201. end;
  202. FCount := 0;
  203. finally
  204. FLocker.Leave;
  205. end;
  206. end;
  207. procedure TBaseQueue.freeDataObject;
  208. var
  209. lvData:Pointer;
  210. begin
  211. while True do
  212. begin
  213. lvData := nil;
  214. if Pop(lvData) then
  215. begin
  216. if lvData = nil then
  217. begin
  218. lvData := nil;
  219. end else
  220. begin
  221. TObject(lvData).Free;
  222. end;
  223. end else
  224. begin
  225. Break;
  226. end;
  227. end;
  228. end;
  229. function TBaseQueue.IsEmpty: Boolean;
  230. begin
  231. Result := (FHead.next = nil);
  232. end;
  233. function TBaseQueue.Pop: Pointer;
  234. var
  235. lvTemp:PQueueData;
  236. begin
  237. Result := nil;
  238. lvTemp := innerPop;
  239. if lvTemp <> nil then
  240. begin
  241. Result := lvTemp.Data;
  242. queueDataPool.Push(lvTemp);
  243. end;
  244. end;
  245. function TBaseQueue.Pop(var outPointer: Pointer): Boolean;
  246. var
  247. lvTemp:PQueueData;
  248. begin
  249. Result := false;
  250. lvTemp := innerPop;
  251. if lvTemp <> nil then
  252. begin
  253. outPointer := lvTemp.Data;
  254. queueDataPool.Push(lvTemp);
  255. Result := true;
  256. end;
  257. end;
  258. procedure TBaseQueue.Push(AData: Pointer);
  259. var
  260. lvTemp:PQueueData;
  261. begin
  262. lvTemp := queueDataPool.Pop;
  263. lvTemp.Data := AData;
  264. innerAddToTail(lvTemp);
  265. end;
  266. function TBaseQueue.size: Integer;
  267. begin
  268. Result := FCount;
  269. end;
  270. procedure TBaseQueue.innerAddToHead(AData: PQueueData);
  271. begin
  272. FLocker.Enter;
  273. try
  274. AData.Next := FHead;
  275. FHead := AData;
  276. if FTail = nil then FTail := FHead;
  277. Inc(FCount);
  278. {$IFDEF DEBUG_ON}
  279. Inc(FPushCounter);
  280. {$ENDIF}
  281. finally
  282. FLocker.Leave;
  283. end;
  284. end;
  285. function TBaseQueue.innerPop: PQueueData;
  286. begin
  287. FLocker.Enter;
  288. try
  289. Result := FHead;
  290. if Result <> nil then
  291. begin
  292. FHead := Result.Next;
  293. if FHead = nil then FTail := nil;
  294. Dec(FCount);
  295. {$IFDEF DEBUG_ON}
  296. Inc(FPopCounter);
  297. {$ENDIF}
  298. end;
  299. finally
  300. FLocker.Leave;
  301. end;
  302. end;
  303. procedure TBaseQueue.innerAddToTail(AData: PQueueData);
  304. begin
  305. AData.Next := nil;
  306. FLocker.Enter;
  307. try
  308. if FTail = nil then
  309. FHead := AData
  310. else
  311. begin
  312. FTail.Next := AData;
  313. end;
  314. FTail := AData;
  315. Inc(FCount);
  316. {$IFDEF DEBUG_ON}
  317. Inc(FPushCounter);
  318. {$ENDIF}
  319. finally
  320. FLocker.Leave;
  321. end;
  322. end;
  323. { TQueueDataPool }
  324. constructor TQueueDataPool.Create(AMaxSize: Integer = 2048);
  325. begin
  326. inherited Create;
  327. FSize := AMaxSize;
  328. FLocker := TCriticalSection.Create;
  329. end;
  330. destructor TQueueDataPool.Destroy;
  331. var
  332. lvData: PQueueData;
  333. begin
  334. {$IFDEF DEBUG_ON}
  335. if IsDebugMode then
  336. Assert(FPopCounter = FPushCounter, ('PopCounter <> PushCounter'));
  337. {$ENDIF}
  338. FLocker.Enter;
  339. while FFirst <> nil do
  340. begin
  341. lvData := FFirst.Next;
  342. Dispose(FFirst);
  343. FFirst := lvData;
  344. end;
  345. FLocker.Free;
  346. inherited;
  347. end;
  348. function TQueueDataPool.Pop: PQueueData;
  349. begin
  350. FLocker.Enter;
  351. Result := FFirst;
  352. if Result <> nil then
  353. begin
  354. FFirst := Result.Next;
  355. Dec(FCount);
  356. end;
  357. {$IFDEF DEBUG_ON}
  358. Inc(FPopCounter);
  359. {$ENDIF}
  360. FLocker.Leave;
  361. if Result = nil then
  362. GetMem(Result, SizeOf(TQueueData));
  363. Result.Data := nil;
  364. Result.Next := nil;
  365. end;
  366. procedure TQueueDataPool.Push(pvQueueData: PQueueData);
  367. var
  368. ADoFree: Boolean;
  369. begin
  370. Assert(pvQueueData <> nil);
  371. FLocker.Enter;
  372. ADoFree := (FCount = FSize);
  373. if not ADoFree then
  374. begin
  375. pvQueueData.Next := FFirst;
  376. FFirst := pvQueueData;
  377. Inc(FCount);
  378. end;
  379. {$IFDEF DEBUG_ON}
  380. Inc(FPushCounter);
  381. {$ENDIF}
  382. FLocker.Leave;
  383. if ADoFree then
  384. begin
  385. FreeMem(pvQueueData);
  386. end;
  387. end;
  388. constructor TSimpleQueue.Create;
  389. begin
  390. inherited Create;
  391. FHead := nil;
  392. FTail := nil;
  393. FCount := 0;
  394. FName := 'simpleQueue';
  395. end;
  396. destructor TSimpleQueue.Destroy;
  397. begin
  398. {$IFDEF DEBUG_ON}
  399. if IsDebugMode then
  400. Assert(FPopCounter = FPushCounter, ('[' + FName + ']PopCounter <> PushCounter'));
  401. {$ENDIF}
  402. Clear;
  403. inherited Destroy;
  404. end;
  405. procedure TSimpleQueue.DisposeAllData;
  406. var
  407. lvData:Pointer;
  408. begin
  409. while True do
  410. begin
  411. lvData := nil;
  412. if Pop(lvData) then
  413. begin
  414. if lvData = nil then
  415. begin
  416. lvData := nil;
  417. end else
  418. begin
  419. Dispose(lvData);
  420. end;
  421. end else
  422. begin
  423. Break;
  424. end;
  425. end;
  426. end;
  427. { TSimpleQueue }
  428. procedure TSimpleQueue.AddToHead(AData: Pointer);
  429. var
  430. lvTemp:PQueueData;
  431. begin
  432. lvTemp := queueDataPool.Pop;
  433. lvTemp.Data := AData;
  434. innerAddToHead(lvTemp);
  435. end;
  436. procedure TSimpleQueue.clear;
  437. var
  438. ANext: PQueueData;
  439. begin
  440. if FHead = nil then Exit;
  441. while FHead.Next <> nil do
  442. begin
  443. ANext := FHead.Next;
  444. queueDataPool.Push(FHead);
  445. FHead := ANext;
  446. end;
  447. FCount := 0;
  448. end;
  449. procedure TSimpleQueue.freeDataObject;
  450. var
  451. lvData:Pointer;
  452. begin
  453. while True do
  454. begin
  455. lvData := nil;
  456. if Pop(lvData) then
  457. begin
  458. if lvData = nil then
  459. begin
  460. lvData := nil;
  461. end else
  462. begin
  463. TObject(lvData).Free;
  464. end;
  465. end else
  466. begin
  467. Break;
  468. end;
  469. end;
  470. end;
  471. function TSimpleQueue.IsEmpty: Boolean;
  472. begin
  473. Result := (FHead.next = nil);
  474. end;
  475. function TSimpleQueue.Pop: Pointer;
  476. var
  477. lvTemp:PQueueData;
  478. begin
  479. Result := nil;
  480. lvTemp := innerPop;
  481. if lvTemp <> nil then
  482. begin
  483. Result := lvTemp.Data;
  484. queueDataPool.Push(lvTemp);
  485. end;
  486. end;
  487. function TSimpleQueue.Pop(var outPointer: Pointer): Boolean;
  488. var
  489. lvTemp:PQueueData;
  490. begin
  491. Result := false;
  492. lvTemp := innerPop;
  493. if lvTemp <> nil then
  494. begin
  495. outPointer := lvTemp.Data;
  496. queueDataPool.Push(lvTemp);
  497. Result := true;
  498. end;
  499. end;
  500. procedure TSimpleQueue.Push(AData: Pointer);
  501. var
  502. lvTemp:PQueueData;
  503. begin
  504. lvTemp := queueDataPool.Pop;
  505. lvTemp.Data := AData;
  506. innerAddToTail(lvTemp);
  507. end;
  508. function TSimpleQueue.size: Integer;
  509. begin
  510. Result := FCount;
  511. end;
  512. procedure TSimpleQueue.innerAddToHead(AData: PQueueData);
  513. begin
  514. AData.Next := FHead;
  515. FHead := AData;
  516. if FTail = nil then FTail := FHead;
  517. Inc(FCount);
  518. {$IFDEF DEBUG_ON}
  519. Inc(FPushCounter);
  520. {$ENDIF}
  521. end;
  522. function TSimpleQueue.innerPop: PQueueData;
  523. begin
  524. Result := FHead;
  525. if Result <> nil then
  526. begin
  527. FHead := Result.Next;
  528. if FHead = nil then FTail := nil;
  529. Dec(FCount);
  530. {$IFDEF DEBUG_ON}
  531. Inc(FPopCounter);
  532. {$ENDIF}
  533. end;
  534. end;
  535. procedure TSimpleQueue.innerAddToTail(AData: PQueueData);
  536. begin
  537. AData.Next := nil;
  538. if FTail = nil then
  539. FHead := AData
  540. else
  541. begin
  542. FTail.Next := AData;
  543. end;
  544. FTail := AData;
  545. Inc(FCount);
  546. {$IFDEF DEBUG_ON}
  547. Inc(FPushCounter);
  548. {$ENDIF}
  549. end;
  550. initialization
  551. queueDataPool := TQueueDataPool.Create(10240);
  552. finalization
  553. queueDataPool.Free;
  554. end.