MGList.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. //******************************************************************************
  2. //*** COMMON DELPHI FUNCTIONS ***
  3. //*** ***
  4. //*** (c) Beppe Grimaldi, Massimo Magnano 11-11-2004. ***
  5. //*** ***
  6. //*** ***
  7. //******************************************************************************
  8. // File : MGList.pas REV. 1.6 (13-09-2006)
  9. //
  10. // Description : Implementation of an Optimazed and Polimorphic List.
  11. //
  12. //******************************************************************************
  13. unit MGList;
  14. interface
  15. Type
  16. PDataExt = ^TDataExt;
  17. TDataExt = record
  18. Data :Pointer;
  19. Prev :PDataExt;
  20. Next :PDataExt;
  21. end;
  22. //I Tag sono necessari xche' Non posso leggere le variabili che stanno nello Stack
  23. //quindi devo passare le variabile necessarie alle funzioni locali così
  24. TLocalCompareFunction = function (Tag :Integer; ptData1, ptData2 :Pointer) :Boolean;
  25. TLocalWalkFunction = procedure (Tag :Integer; ptData :Pointer);
  26. TObjCompareFunction = function (Tag :Integer; ptData1, ptData2 :Pointer) :Boolean of object;
  27. PObjCompareFunction = ^TObjCompareFunction;
  28. TObjWalkFunction = procedure (Tag :Integer; ptData :Pointer) of object;
  29. TMGList = class
  30. protected
  31. rListInit,
  32. rListEnd,
  33. rCurrent :PDataExt;
  34. rCount :Integer;
  35. function Get(Index: Integer): Pointer;
  36. function InternalDelete(Item :PDataExt) :PDataExt; overload;
  37. function InternalFind(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=nil) :PDataExt; virtual;
  38. function PutInRightPosition(newElem :PDataExt; ATag :Integer; CompareFunction : TLocalCompareFunction=nil) :Integer; overload; virtual;
  39. function PutInRightPosition(newElem :PDataExt; ATag :Integer; CompareFunction : TObjCompareFunction) :Integer; overload; virtual;
  40. function allocData :Pointer; virtual;
  41. procedure deallocData(pData :Pointer); virtual;
  42. function RefreshOK(pData :Pointer) : Boolean; virtual;
  43. public
  44. constructor Create; virtual;
  45. destructor Destroy; override;
  46. function Find(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=nil): Integer; overload;
  47. function Find(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction): Integer; overload;
  48. function Find(const Args: array of Variant): Pointer; overload; virtual;
  49. function ExtFind(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=nil): Pointer; overload;
  50. function ExtFind(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction): Pointer; overload;
  51. procedure Walk(ATag :Integer; WalkFunction : TLocalWalkFunction); overload;
  52. procedure Walk(ATag :Integer; WalkFunction : TObjWalkFunction); overload;
  53. procedure WalkAndRefresh(ATag :Integer; WalkFunction : TLocalWalkFunction); overload;
  54. procedure WalkAndRefresh(ATag :Integer; WalkFunction : TObjWalkFunction); overload;
  55. function Add :Pointer; overload;
  56. function Insert(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=nil) :Integer; overload;
  57. function Insert(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction) :Integer; overload;
  58. function Delete(Index :Integer) :Boolean; overload;
  59. function Delete(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=Nil) :Boolean; overload;
  60. function Delete(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction) :Boolean; overload;
  61. procedure Exchange(pData1, pData2 :Pointer); overload; virtual;
  62. procedure Clear;
  63. procedure Refresh;
  64. function FindFirst: Pointer; virtual;
  65. function FindNext : Pointer; virtual;
  66. function GetCurrent : Pointer; virtual;
  67. function GetData(DataPointer :Pointer; DataName :String) :Variant; virtual;
  68. function DeleteCurrent :Boolean;
  69. procedure FindClose; virtual;
  70. property Count :Integer read rCount;
  71. property Items [Index :Integer] :Pointer read Get;
  72. end;
  73. TMGListClass = class of TMGList;
  74. TMGObjectWithCreate = class(TObject)
  75. public
  76. constructor Create(dummy :Boolean); virtual;
  77. end;
  78. TObjectWCClass = class of TMGObjectWithCreate;
  79. TMGObject_List = class(TMGList)
  80. protected
  81. function allocData :Pointer; override;
  82. procedure deallocData(pData :Pointer); override;
  83. function GetObjectClass :TObjectWCClass; virtual; abstract;
  84. end;
  85. TMGList_List = class(TMGList)
  86. protected
  87. function allocData :Pointer; override;
  88. procedure deallocData(pData :Pointer); override;
  89. function GetObjectClass :TMGListClass; virtual; abstract;
  90. end;
  91. implementation
  92. Type
  93. TLocalToObjData_Compare = record
  94. Tag :Integer;
  95. Func :TObjCompareFunction;
  96. end;
  97. PLocalToObjData_Compare = ^TLocalToObjData_Compare;
  98. TLocalToObjData_Walk = record
  99. Tag :Integer;
  100. Func :TObjWalkFunction;
  101. end;
  102. PLocalToObjData_Walk = ^TLocalToObjData_Walk;
  103. function _localToObj_Compare(xTag :Integer; ptData1, ptData2 :Pointer) :Boolean;
  104. begin
  105. Result := PLocalToObjData_Compare(xTag).Func(
  106. PLocalToObjData_Compare(xTag).Tag,
  107. ptData1, ptData2);
  108. end;
  109. procedure _localToObj_Walk(xTag :Integer; ptData :Pointer);
  110. begin
  111. PLocalToObjData_Walk(xTag).Func(PLocalToObjData_Walk(xTag).Tag, ptData);
  112. end;
  113. function AllocData_Compare(Tag :Integer; Func :TObjCompareFunction) :PLocalToObjData_Compare;
  114. begin
  115. GetMem(Result, sizeOf(TLocalToObjData_Compare));
  116. Result^.Tag :=Tag;
  117. Result^.Func :=Func;
  118. end;
  119. function AllocData_Walk(Tag :Integer; Func :TObjWalkFunction) :PLocalToObjData_Walk;
  120. begin
  121. GetMem(Result, sizeOf(TLocalToObjData_Walk));
  122. Result^.Tag :=Tag;
  123. Result^.Func :=Func;
  124. end;
  125. function CompByData(xTag :Integer; ptData1, ptData2 :Pointer) :Boolean;
  126. begin
  127. Result := (ptData1 = ptData2);
  128. end;
  129. // =============================================================================
  130. constructor TMGList.Create;
  131. begin
  132. rCount := 0;
  133. rListInit := Nil;
  134. rListEnd := Nil;
  135. rCurrent := Nil;
  136. end;
  137. destructor TMGList.Destroy;
  138. begin
  139. Clear;
  140. end;
  141. function TMGList.allocData :Pointer;
  142. begin
  143. Result :=Nil;
  144. end;
  145. procedure TMGList.deallocData(pData :Pointer);
  146. begin
  147. end;
  148. function TMGList.RefreshOK(pData :Pointer) : Boolean;
  149. begin
  150. Result :=True;
  151. end;
  152. procedure TMGList.Clear;
  153. var
  154. pIndex :PDataExt;
  155. begin
  156. while (rListInit <> Nil) do
  157. begin
  158. pIndex := rListInit;
  159. rListInit := rListInit^.Next;
  160. deallocData(pIndex^.Data);
  161. Dispose(pIndex);
  162. end;
  163. rListInit := Nil;
  164. rListEnd := Nil;
  165. rCount := 0;
  166. end;
  167. procedure TMGList.Refresh;
  168. var
  169. pIndex :PDataExt;
  170. begin
  171. pIndex := rListInit;
  172. while (pIndex <> Nil) do
  173. begin
  174. if RefreshOK(pIndex^.Data)
  175. then pIndex := pIndex^.Next
  176. else begin
  177. if (pIndex^.Next = Nil) // se è l'ultimo elemento..
  178. then rListEnd := pIndex^.Prev;
  179. pIndex := InternalDelete(pIndex);
  180. end;
  181. end;
  182. end;
  183. function TMGList.FindFirst: Pointer;
  184. begin
  185. if (rCurrent=Nil)
  186. then begin
  187. rCurrent :=rListInit;
  188. Result :=GetCurrent;
  189. end
  190. else Result :=Nil;
  191. end;
  192. function TMGList.FindNext : Pointer;
  193. begin
  194. if (rCurrent<>Nil)
  195. then begin
  196. rCurrent :=rCurrent^.Next;
  197. Result :=GetCurrent;
  198. end
  199. else Result :=Nil;
  200. end;
  201. function TMGList.GetCurrent : Pointer;
  202. begin
  203. if (rCurrent=Nil)
  204. then Result :=Nil
  205. else Result :=rCurrent^.Data;
  206. end;
  207. function TMGList.GetData(DataPointer :Pointer; DataName :String) :Variant;
  208. begin
  209. Result :=Variant(Integer(DataPointer));
  210. end;
  211. function TMGList.DeleteCurrent :Boolean;
  212. begin
  213. Result := False;
  214. if (rCurrent <> Nil) then
  215. begin
  216. rCurrent := InternalDelete(rCurrent);
  217. Result := True;
  218. end;
  219. end;
  220. procedure TMGList.FindClose;
  221. begin
  222. rCurrent :=Nil;
  223. end;
  224. function TMGList.Get(Index: Integer): Pointer;
  225. var
  226. I :Integer;
  227. pIndex :PDataExt;
  228. begin
  229. Result := Nil;
  230. if ((Index >= 0) and (Index < rCount)) then
  231. begin
  232. pIndex := rListInit;
  233. for i:=0 to Index-1 do
  234. pIndex := pIndex^.Next;
  235. Result := pIndex^.Data;
  236. end;
  237. end;
  238. function TMGList.Find(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=nil): Integer;
  239. var
  240. i :Integer;
  241. Found :Boolean;
  242. pIndex :PDataExt;
  243. begin
  244. if not(Assigned(CompareFunction))
  245. then CompareFunction :=CompByData;
  246. Result := -1;
  247. i := 0;
  248. Found := False;
  249. pIndex := rListInit;
  250. while ((i < rCount) and not Found) do
  251. if CompareFunction(ATag, pData, pIndex^.Data)
  252. then begin
  253. Result := i;
  254. Found := True;
  255. end
  256. else begin
  257. Inc(i);
  258. pIndex := pIndex^.Next;
  259. end;
  260. end;
  261. function TMGList.Find(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction): Integer;
  262. Var
  263. auxPointer :PLocalToObjData_Compare;
  264. begin
  265. auxPointer :=AllocData_Compare(ATag, CompareFunction);
  266. Result := Find(pData, Integer(auxPointer), _LocalToObj_Compare);
  267. FreeMem(auxPointer);
  268. end;
  269. function TMGList.Find(const Args: array of Variant): Pointer;
  270. begin
  271. Result :=Nil;
  272. end;
  273. function TMGList.ExtFind(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=nil): Pointer;
  274. var
  275. Found :Boolean;
  276. pIndex :PDataExt;
  277. begin
  278. if not(Assigned(CompareFunction))
  279. then CompareFunction :=CompByData;
  280. Result := Nil;
  281. Found := False;
  282. pIndex := rListInit;
  283. while ((pIndex <> Nil) and not Found) do
  284. if CompareFunction(ATag, pData, pIndex^.Data)
  285. then begin
  286. Result := pIndex^.Data;
  287. Found := True;
  288. end
  289. else pIndex := pIndex^.Next;
  290. end;
  291. function TMGList.ExtFind(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction): Pointer;
  292. Var
  293. auxPointer :PLocalToObjData_Compare;
  294. begin
  295. auxPointer :=AllocData_Compare(ATag, CompareFunction);
  296. Result := ExtFind(pData, Integer(auxPointer), _LocalToObj_Compare);
  297. FreeMem(auxPointer);
  298. end;
  299. procedure TMGList.Walk(ATag :Integer; WalkFunction : TLocalWalkFunction);
  300. var
  301. pIndex :PDataExt;
  302. begin
  303. pIndex := rListInit;
  304. while (pIndex <> Nil) do
  305. begin
  306. WalkFunction(ATag, pIndex^.Data);
  307. pIndex := pIndex^.Next;
  308. end;
  309. end;
  310. procedure TMGList.Walk(ATag :Integer; WalkFunction : TObjWalkFunction);
  311. Var
  312. auxPointer :PLocalToObjData_Walk;
  313. begin
  314. auxPointer :=AllocData_Walk(ATag, WalkFunction);
  315. Walk(Integer(auxPointer), _LocalToObj_Walk);
  316. FreeMem(auxPointer);
  317. end;
  318. procedure TMGList.WalkAndRefresh(ATag :Integer; WalkFunction : TLocalWalkFunction);
  319. var
  320. pIndex :PDataExt;
  321. begin
  322. pIndex := rListInit;
  323. while (pIndex <> Nil) do
  324. begin
  325. if RefreshOk(pIndex^.Data)
  326. then begin
  327. WalkFunction(ATag, pIndex^.Data);
  328. pIndex := pIndex^.Next;
  329. end
  330. else begin
  331. if (pIndex^.Next = Nil) // se è l'ultimo elemento..
  332. then rListEnd := pIndex^.Prev;
  333. pIndex := InternalDelete(pIndex);
  334. end;
  335. end;
  336. end;
  337. procedure TMGList.WalkAndRefresh(ATag :Integer; WalkFunction : TObjWalkFunction);
  338. Var
  339. auxPointer :PLocalToObjData_Walk;
  340. begin
  341. auxPointer :=AllocData_Walk(ATag, WalkFunction);
  342. WalkAndRefresh(Integer(auxPointer), _LocalToObj_Walk);
  343. FreeMem(auxPointer);
  344. end;
  345. function TMGList.Add :Pointer;
  346. var
  347. newElem :PDataExt;
  348. begin
  349. new(newElem);
  350. fillchar(newElem^, sizeof(TDataExt), 0);
  351. newElem^.Data := allocData;
  352. if (rListEnd = Nil)
  353. then begin
  354. rListInit := newElem;
  355. rListEnd := newElem;
  356. end
  357. else begin
  358. rListEnd^.Next := newElem;
  359. newElem^.Prev := rListEnd;
  360. rListEnd := newElem;
  361. end;
  362. Inc(rCount);
  363. Result := newElem^.Data;
  364. end;
  365. function TMGList.PutInRightPosition(newElem :PDataExt; ATag :Integer; CompareFunction : TLocalCompareFunction) :Integer;
  366. var
  367. Found :Boolean;
  368. pIndex :PDataExt;
  369. begin
  370. if not(Assigned(CompareFunction))
  371. then CompareFunction :=CompByData;
  372. Result := 0;
  373. if (rListInit = Nil)
  374. then begin
  375. rListInit := newElem;
  376. rListEnd := newElem;
  377. end
  378. else begin
  379. Found := False;
  380. pIndex := rListInit;
  381. repeat
  382. if CompareFunction(ATag, newElem^.Data, pIndex^.Data)
  383. then begin
  384. // uso 'newElem^.Prev' per conservare il puntatore al record precedente..
  385. newElem^.Prev := pIndex;
  386. pIndex := pIndex^.Next;
  387. end
  388. else Found := True;
  389. Inc(Result);
  390. until ((pIndex = Nil) or Found);
  391. if (newElem^.Prev = Nil) // inserisco in prima posizione..
  392. then rListInit := newElem
  393. else newElem^.Prev^.Next := newElem;
  394. newElem^.Next := pIndex;
  395. if (pIndex <> Nil)
  396. then pIndex^.Prev := newElem
  397. else rListEnd := newElem; // inserisco in ultima posizione..
  398. end;
  399. end;
  400. function TMGList.PutInRightPosition(newElem :PDataExt; ATag :Integer; CompareFunction : TObjCompareFunction) :Integer;
  401. Var
  402. auxPointer :PLocalToObjData_Compare;
  403. begin
  404. auxPointer :=AllocData_Compare(ATag, CompareFunction);
  405. Result := PutInRightPosition(newElem, Integer(auxPointer), _LocalToObj_Compare);
  406. FreeMem(auxPointer);
  407. end;
  408. function TMGList.Insert(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=Nil) :Integer;
  409. var
  410. newElem :PDataExt;
  411. begin
  412. if not(Assigned(CompareFunction))
  413. then CompareFunction :=CompByData;
  414. new(newElem);
  415. fillchar(newElem^, sizeof(TDataExt), 0);
  416. newElem^.Data :=pData;
  417. Result := PutInRightPosition(pData, ATag, CompareFunction);
  418. Inc(rCount);
  419. end;
  420. function TMGList.Insert(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction) :Integer;
  421. Var
  422. auxPointer :PLocalToObjData_Compare;
  423. begin
  424. auxPointer :=AllocData_Compare(ATag, CompareFunction);
  425. Result := Insert(pData, Integer(auxPointer), _LocalToObj_Compare);
  426. FreeMem(auxPointer);
  427. end;
  428. function TMGList.Delete(Index :Integer) :Boolean;
  429. var
  430. i :Integer;
  431. pIndex :PDataExt;
  432. begin
  433. Result := False;
  434. if ((Index >= 0) and (Index < rCount)) then
  435. begin
  436. pIndex := rListInit;
  437. for i:=0 to Index-1 do
  438. pIndex := pIndex^.Next;
  439. if (pIndex = Nil)
  440. then InternalDelete(rListEnd)
  441. else InternalDelete(pIndex);
  442. Result := True;
  443. end;
  444. end;
  445. function TMGList.Delete(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=Nil) :Boolean;
  446. Var
  447. toDel :PDataExt;
  448. begin
  449. if not(Assigned(CompareFunction))
  450. then CompareFunction :=CompByData;
  451. toDel := InternalFind(pData, ATag, CompareFunction);
  452. Result := (toDel<>Nil);
  453. if Result
  454. then InternalDelete(toDel);
  455. end;
  456. function TMGList.Delete(pData :Pointer; ATag :Integer; CompareFunction : TObjCompareFunction) :Boolean;
  457. Var
  458. auxPointer :PLocalToObjData_Compare;
  459. begin
  460. auxPointer :=AllocData_Compare(ATag, CompareFunction);
  461. Result := Delete(pData, Integer(auxPointer), _LocalToObj_Compare);
  462. FreeMem(auxPointer);
  463. end;
  464. procedure TMGList.Exchange(pData1, pData2 :Pointer);
  465. var
  466. pIndex,
  467. pIndexData1,
  468. pIndexData2 :PDataExt;
  469. xData :Pointer;
  470. begin
  471. pIndex := rListInit;
  472. pIndexData1 :=Nil;
  473. pIndexData2 :=Nil;
  474. while ((pIndex <> Nil) and ((pIndexData1=Nil) or (pIndexData2=Nil))) do
  475. begin
  476. if (pIndex^.Data=pData1)
  477. then pIndexData1 :=pIndex
  478. else if (pIndex^.Data=pData2)
  479. then pIndexData2 :=pIndex;
  480. pIndex := pIndex^.Next;
  481. end;
  482. if ((pIndexData1<>Nil) and (pIndexData2<>Nil)) then
  483. begin
  484. xData := pIndexData1^.Data;
  485. pIndexData1^.Data := pIndexData2^.Data;
  486. pIndexData2^.Data := xData;
  487. end;
  488. end;
  489. function TMGList.InternalDelete(Item :PDataExt) :PDataExt;
  490. var
  491. P :PDataExt;
  492. begin
  493. Result := Nil;
  494. P := PDataExt(Item);
  495. if (P <> Nil) then
  496. begin
  497. if (P^.Prev <> Nil)
  498. then P^.Prev^.Next := P^.Next
  499. else rListInit := P^.Next;
  500. if (P^.Next <> Nil)
  501. then P^.Next^.Prev := P^.Prev
  502. else rListEnd := P^.Prev; // sto cancellando l'ultimo elemento..
  503. Result := P^.Prev;
  504. deallocData(P^.Data);
  505. Dispose(P);
  506. Dec(rCount);
  507. end;
  508. end;
  509. function TMGList.InternalFind(pData :Pointer; ATag :Integer; CompareFunction : TLocalCompareFunction=nil) :PDataExt;
  510. var
  511. Found :Boolean;
  512. pIndex :PDataExt;
  513. begin
  514. if not(Assigned(CompareFunction))
  515. then CompareFunction :=CompByData;
  516. Result := Nil;
  517. Found := False;
  518. pIndex := rListInit;
  519. while ((pIndex <> Nil) and not Found) do
  520. if CompareFunction(ATag, pData, pIndex^.Data)
  521. then begin
  522. Result := pIndex;
  523. Found := True;
  524. end
  525. else pIndex := pIndex^.Next;
  526. end;
  527. //==============================================================================
  528. // TMGObject_List = class(TMGList)
  529. constructor TMGObjectWithCreate.Create(dummy :Boolean);
  530. begin
  531. inherited Create;
  532. end;
  533. function TMGObject_List.allocData :Pointer;
  534. begin
  535. Result :=GetObjectClass.Create(true); //Why Tobject.Create is not virtual???
  536. end;
  537. procedure TMGObject_List.deallocData(pData :Pointer);
  538. begin
  539. TObject(pData).Free;
  540. end;
  541. //==============================================================================
  542. // TMGList_List = class(TMGList)
  543. function TMGList_List.allocData :Pointer;
  544. begin
  545. Result :=GetObjectClass.Create;
  546. end;
  547. procedure TMGList_List.deallocData(pData :Pointer);
  548. begin
  549. TMGList(pData).Free;
  550. end;
  551. end.