fgl.pp 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 by Micha Nelissen
  4. member of the Free Pascal development team
  5. It contains the Free Pascal generics library
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. { be aware, this unit is a prototype and subject to be changed heavily }
  14. unit fgl;
  15. interface
  16. uses
  17. types, sysutils;
  18. const
  19. MaxListSize = Maxint div 16;
  20. type
  21. EListError = class(Exception);
  22. TFPSList = class;
  23. TFPSListCompareFunc = function(Key1, Key2: Pointer): Integer of object;
  24. TFPSList = class(TObject)
  25. protected
  26. FList: PByte;
  27. FCount: Integer;
  28. FCapacity: Integer; { list is one longer than capacity, for temp }
  29. FItemSize: Integer;
  30. procedure CopyItem(Src, Dest: Pointer); virtual;
  31. procedure Deref(Item: Pointer); virtual; overload;
  32. procedure Deref(FromIndex, ToIndex: Integer); overload;
  33. function Get(Index: Integer): Pointer;
  34. procedure InternalExchange(Index1, Index2: Integer);
  35. function InternalGet(Index: Integer): Pointer; {$ifdef CLASSESINLINE} inline; {$endif}
  36. procedure InternalPut(Index: Integer; NewItem: Pointer);
  37. procedure Put(Index: Integer; Item: Pointer);
  38. procedure QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  39. procedure SetCapacity(NewCapacity: Integer);
  40. procedure SetCount(NewCount: Integer);
  41. procedure RaiseIndexError(Index : Integer);
  42. property InternalItems[Index: Integer]: Pointer read InternalGet write InternalPut;
  43. public
  44. constructor Create(AItemSize: Integer = sizeof(Pointer));
  45. destructor Destroy; override;
  46. function Add(Item: Pointer): Integer;
  47. procedure Clear;
  48. procedure Delete(Index: Integer);
  49. class procedure Error(const Msg: string; Data: PtrInt);
  50. procedure Exchange(Index1, Index2: Integer);
  51. function Expand: TFPSList;
  52. function Extract(Item: Pointer): Pointer;
  53. function First: Pointer;
  54. function IndexOf(Item: Pointer): Integer;
  55. procedure Insert(Index: Integer; Item: Pointer);
  56. function Insert(Index: Integer): Pointer;
  57. function Last: Pointer;
  58. procedure Move(CurIndex, NewIndex: Integer);
  59. procedure Assign(Obj: TFPSList);
  60. function Remove(Item: Pointer): Integer;
  61. procedure Pack;
  62. procedure Sort(Compare: TFPSListCompareFunc);
  63. property Capacity: Integer read FCapacity write SetCapacity;
  64. property Count: Integer read FCount write SetCount;
  65. property Items[Index: Integer]: Pointer read Get write Put; default;
  66. property ItemSize: Integer read FItemSize;
  67. property List: PByte read FList;
  68. end;
  69. {$ifndef VER2_0}
  70. const
  71. MaxGListSize = MaxInt div 1024;
  72. type
  73. generic TFPGList<T> = class(TFPSList)
  74. type public
  75. TCompareFunc = function(const Item1, Item2: T): Integer;
  76. TTypeList = array[0..MaxGListSize] of T;
  77. PTypeList = ^TTypeList;
  78. PT = ^T;
  79. var protected
  80. FOnCompare: TCompareFunc;
  81. procedure CopyItem(Src, Dest: Pointer); override;
  82. procedure Deref(Item: Pointer); override;
  83. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  84. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  85. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  86. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  87. public
  88. constructor Create;
  89. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  90. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  91. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  92. function IndexOf(const Item: T): Integer;
  93. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  94. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  95. {$info FIXME: bug #10479: implement TFPGList<T>.Assign(TFPGList) to work somehow}
  96. {procedure Assign(Source: TFPGList);}
  97. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  98. procedure Sort(Compare: TCompareFunc);
  99. property Items[Index: Integer]: T read Get write Put; default;
  100. property List: PTypeList read GetList;
  101. end;
  102. generic TFPGObjectList<T> = class(TFPSList)
  103. type public
  104. TCompareFunc = function(const Item1, Item2: T): Integer;
  105. TTypeList = array[0..MaxGListSize] of T;
  106. PTypeList = ^TTypeList;
  107. PT = ^T;
  108. var protected
  109. FOnCompare: TCompareFunc;
  110. procedure CopyItem(Src, Dest: Pointer); override;
  111. procedure Deref(Item: Pointer); override;
  112. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  113. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  114. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  115. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  116. public
  117. constructor Create;
  118. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  119. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  120. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  121. function IndexOf(const Item: T): Integer;
  122. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  123. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  124. {$info FIXME: bug #10479: implement TFPGList<T>.Assign(TFPGList) to work somehow}
  125. {procedure Assign(Source: TFPGList);}
  126. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  127. procedure Sort(Compare: TCompareFunc);
  128. property Items[Index: Integer]: T read Get write Put; default;
  129. property List: PTypeList read GetList;
  130. end;
  131. {$endif}
  132. TFPSMap = class(TFPSList)
  133. private
  134. FKeySize: Integer;
  135. FDataSize: Integer;
  136. FDuplicates: TDuplicates;
  137. FSorted: Boolean;
  138. FOnPtrCompare: TFPSListCompareFunc;
  139. procedure SetSorted(Value: Boolean);
  140. protected
  141. function BinaryCompare(Key1, Key2: Pointer): Integer;
  142. procedure CopyKey(Src, Dest: Pointer); virtual;
  143. procedure CopyData(Src, Dest: Pointer); virtual;
  144. function GetKey(Index: Integer): Pointer;
  145. function GetKeyData(AKey: Pointer): Pointer;
  146. function GetData(Index: Integer): Pointer;
  147. procedure InitOnPtrCompare; virtual;
  148. function LinearIndexOf(AKey: Pointer): Integer;
  149. procedure PutKey(Index: Integer; AKey: Pointer);
  150. procedure PutKeyData(AKey: Pointer; NewData: Pointer);
  151. procedure PutData(Index: Integer; AData: Pointer);
  152. public
  153. constructor Create(AKeySize: Integer = sizeof(Pointer);
  154. ADataSize: integer = sizeof(Pointer));
  155. function Add(AKey, AData: Pointer): Integer;
  156. function Add(AKey: Pointer): Integer;
  157. function Find(AKey: Pointer; var Index: Integer): Boolean;
  158. function IndexOf(AKey: Pointer): Integer;
  159. function IndexOfData(AData: Pointer): Integer;
  160. function Insert(Index: Integer): Pointer;
  161. procedure Insert(Index: Integer; var AKey, AData: Pointer);
  162. procedure InsertKey(Index: Integer; AKey: Pointer);
  163. procedure InsertKeyData(Index: Integer; AKey, AData: Pointer);
  164. function Remove(AKey: Pointer): Integer;
  165. procedure Sort;
  166. property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  167. property KeySize: Integer read FKeySize;
  168. property DataSize: Integer read FDataSize;
  169. property Keys[Index: Integer]: Pointer read GetKey write PutKey;
  170. property Data[Index: Integer]: Pointer read GetData write PutData;
  171. property KeyData[Key: Pointer]: Pointer read GetKeyData write PutKeyData; default;
  172. property Sorted: Boolean read FSorted write SetSorted;
  173. property OnPtrCompare: TFPSListCompareFunc read FOnPtrCompare write FOnPtrCompare;
  174. end;
  175. {$ifndef VER2_0}
  176. generic TFPGMap<TKey, TData> = class(TFPSMap)
  177. type public
  178. TCompareFunc = function(const Key1, Key2: TKey): Integer;
  179. PKey = ^TKey;
  180. PData = ^TData;
  181. var protected
  182. FOnCompare: TCompareFunc;
  183. procedure CopyItem(Src, Dest: Pointer); override;
  184. procedure CopyKey(Src, Dest: Pointer); override;
  185. procedure CopyData(Src, Dest: Pointer); override;
  186. procedure Deref(Item: Pointer); override;
  187. procedure InitOnPtrCompare; override;
  188. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  189. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  190. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  191. function KeyCompare(Key1, Key2: Pointer): Integer;
  192. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  193. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  194. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  195. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  196. procedure SetOnCompare(NewCompare: TCompareFunc);
  197. public
  198. constructor Create;
  199. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  200. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  201. function Find(const AKey: TKey; var Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  202. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  203. function IndexOfData(const AData: TData): Integer;
  204. procedure InsertKey(Index: Integer; const AKey: TKey);
  205. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  206. function Remove(const AKey: TKey): Integer;
  207. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  208. property Data[Index: Integer]: TData read GetData write PutData;
  209. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  210. property OnCompare: TCompareFunc read FOnCompare write SetOnCompare;
  211. end;
  212. {$endif}
  213. implementation
  214. uses
  215. rtlconsts;
  216. {****************************************************************************
  217. TFPSList
  218. ****************************************************************************}
  219. constructor TFPSList.Create(AItemSize: integer);
  220. begin
  221. inherited Create;
  222. FItemSize := AItemSize;
  223. end;
  224. destructor TFPSList.Destroy;
  225. begin
  226. Clear;
  227. // Clear() does not clear the whole list; there is always a single temp entry
  228. // at the end which is never freed. Take care of that one here.
  229. FreeMem(FList);
  230. inherited Destroy;
  231. end;
  232. procedure TFPSList.CopyItem(Src, Dest: Pointer);
  233. begin
  234. System.Move(Src^, Dest^, FItemSize);
  235. end;
  236. procedure TFPSList.RaiseIndexError(Index : Integer);
  237. begin
  238. Error(SListIndexError, Index);
  239. end;
  240. function TFPSList.InternalGet(Index: Integer): Pointer;
  241. begin
  242. Result:=FList+Index*ItemSize;
  243. end;
  244. procedure TFPSList.InternalPut(Index: Integer; NewItem: Pointer);
  245. var
  246. ListItem: Pointer;
  247. begin
  248. ListItem := InternalItems[Index];
  249. CopyItem(NewItem, ListItem);
  250. end;
  251. function TFPSList.Get(Index: Integer): Pointer;
  252. begin
  253. if (Index < 0) or (Index >= FCount) then
  254. RaiseIndexError(Index);
  255. Result := InternalItems[Index];
  256. end;
  257. procedure TFPSList.Put(Index: Integer; Item: Pointer);
  258. begin
  259. if (Index < 0) or (Index >= FCount) then
  260. RaiseIndexError(Index);
  261. InternalItems[Index] := Item;
  262. end;
  263. procedure TFPSList.SetCapacity(NewCapacity: Integer);
  264. begin
  265. if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  266. Error(SListCapacityError, NewCapacity);
  267. if NewCapacity = FCapacity then
  268. exit;
  269. ReallocMem(FList, (NewCapacity+1) * FItemSize);
  270. FillChar(InternalItems[FCapacity]^, (NewCapacity+1-FCapacity) * FItemSize, #0);
  271. FCapacity := NewCapacity;
  272. end;
  273. procedure TFPSList.Deref(Item: Pointer);
  274. begin
  275. end;
  276. procedure TFPSList.Deref(FromIndex, ToIndex: Integer);
  277. var
  278. ListItem, ListItemLast: Pointer;
  279. begin
  280. ListItem := InternalItems[FromIndex];
  281. ListItemLast := InternalItems[ToIndex];
  282. repeat
  283. Deref(ListItem);
  284. if ListItem = ListItemLast then
  285. break;
  286. ListItem := PByte(ListItem) + ItemSize;
  287. until false;
  288. end;
  289. procedure TFPSList.SetCount(NewCount: Integer);
  290. begin
  291. if (NewCount < 0) or (NewCount > MaxListSize) then
  292. Error(SListCountError, NewCount);
  293. if NewCount > FCount then
  294. begin
  295. if NewCount > FCapacity then
  296. SetCapacity(NewCount);
  297. if NewCount > FCount then
  298. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  299. else if NewCount < FCount then
  300. Deref(NewCount, FCount-1);
  301. end;
  302. FCount := NewCount;
  303. end;
  304. function TFPSList.Add(Item: Pointer): Integer;
  305. begin
  306. if FCount = FCapacity then
  307. Self.Expand;
  308. CopyItem(Item, InternalItems[FCount]);
  309. Result := FCount;
  310. Inc(FCount);
  311. end;
  312. procedure TFPSList.Clear;
  313. begin
  314. if Assigned(FList) then
  315. begin
  316. SetCount(0);
  317. SetCapacity(0);
  318. end;
  319. end;
  320. procedure TFPSList.Delete(Index: Integer);
  321. var
  322. ListItem: Pointer;
  323. begin
  324. if (Index < 0) or (Index >= FCount) then
  325. Error(SListIndexError, Index);
  326. Dec(FCount);
  327. ListItem := InternalItems[Index];
  328. Deref(ListItem);
  329. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  330. // Shrink the list if appropriate
  331. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  332. begin
  333. FCapacity := FCapacity shr 1;
  334. ReallocMem(FList, (FCapacity+1) * FItemSize);
  335. end;
  336. end;
  337. function TFPSList.Extract(Item: Pointer): Pointer;
  338. var
  339. i : Integer;
  340. begin
  341. Result := nil;
  342. i := IndexOf(Item);
  343. if i >= 0 then
  344. begin
  345. Result := InternalItems[i];
  346. System.Move(Result^, InternalItems[FCapacity]^, FItemSize);
  347. Delete(i);
  348. end;
  349. end;
  350. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  351. begin
  352. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  353. end;
  354. procedure TFPSList.Exchange(Index1, Index2: Integer);
  355. begin
  356. if ((Index1 >= FCount) or (Index1 < 0)) then
  357. Error(SListIndexError, Index1);
  358. if ((Index2 >= FCount) or (Index2 < 0)) then
  359. Error(SListIndexError, Index2);
  360. InternalExchange(Index1, Index2);
  361. end;
  362. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  363. begin
  364. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  365. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  366. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  367. end;
  368. function TFPSList.Expand: TFPSList;
  369. var
  370. IncSize : Longint;
  371. begin
  372. if FCount < FCapacity then exit;
  373. IncSize := 4;
  374. if FCapacity > 3 then IncSize := IncSize + 4;
  375. if FCapacity > 8 then IncSize := IncSize + 8;
  376. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  377. SetCapacity(FCapacity + IncSize);
  378. Result := Self;
  379. end;
  380. function TFPSList.First: Pointer;
  381. begin
  382. If FCount = 0 then
  383. Result := Nil
  384. else
  385. Result := InternalItems[0];
  386. end;
  387. function TFPSList.IndexOf(Item: Pointer): Integer;
  388. var
  389. ListItem: Pointer;
  390. begin
  391. Result := 0;
  392. ListItem := First;
  393. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  394. begin
  395. Inc(Result);
  396. ListItem := PByte(ListItem)+FItemSize;
  397. end;
  398. if Result = FCount then Result := -1;
  399. end;
  400. function TFPSList.Insert(Index: Integer): Pointer;
  401. begin
  402. if (Index < 0) or (Index > FCount) then
  403. Error(SListIndexError, Index);
  404. if FCount = FCapacity then Self.Expand;
  405. if Index<FCount then
  406. System.Move(InternalItems[Index]^, InternalItems[Index+1]^, (FCount - Index) * FItemSize);
  407. Result := InternalItems[Index];
  408. Inc(FCount);
  409. end;
  410. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  411. begin
  412. CopyItem(Item, Insert(Index));
  413. end;
  414. function TFPSList.Last: Pointer;
  415. begin
  416. if FCount = 0 then
  417. Result := nil
  418. else
  419. Result := InternalItems[FCount - 1];
  420. end;
  421. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  422. var
  423. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  424. MoveCount: Integer;
  425. begin
  426. if (CurIndex < 0) or (CurIndex >= Count) then
  427. Error(SListIndexError, CurIndex);
  428. if (NewIndex < 0) or (NewIndex >= Count) then
  429. Error(SListIndexError, NewIndex);
  430. if CurIndex = NewIndex then
  431. exit;
  432. CurItem := InternalItems[CurIndex];
  433. NewItem := InternalItems[NewIndex];
  434. TmpItem := InternalItems[FCapacity];
  435. System.Move(CurItem^, TmpItem^, FItemSize);
  436. if NewIndex > CurIndex then
  437. begin
  438. Src := InternalItems[CurIndex+1];
  439. Dest := CurItem;
  440. MoveCount := NewIndex - CurIndex;
  441. end else begin
  442. Src := NewItem;
  443. Dest := InternalItems[NewIndex+1];
  444. MoveCount := CurIndex - NewIndex;
  445. end;
  446. System.Move(Src^, Dest^, MoveCount * FItemSize);
  447. System.Move(TmpItem^, NewItem^, FItemSize);
  448. end;
  449. function TFPSList.Remove(Item: Pointer): Integer;
  450. begin
  451. Result := IndexOf(Item);
  452. if Result <> -1 then
  453. Delete(Result);
  454. end;
  455. procedure TFPSList.Pack;
  456. var
  457. NewCount,
  458. i : integer;
  459. pdest,
  460. psrc : Pointer;
  461. begin
  462. NewCount:=0;
  463. psrc:=First;
  464. pdest:=psrc;
  465. For I:=0 To FCount-1 Do
  466. begin
  467. if assigned(pointer(psrc^)) then
  468. begin
  469. System.Move(psrc^, pdest^, FItemSize);
  470. inc(pdest);
  471. inc(NewCount);
  472. end;
  473. inc(psrc);
  474. end;
  475. FCount:=NewCount;
  476. end;
  477. // Needed by Sort method.
  478. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  479. var
  480. I, J, P: Integer;
  481. PivotItem: Pointer;
  482. begin
  483. repeat
  484. I := L;
  485. J := R;
  486. P := (L + R) div 2;
  487. repeat
  488. PivotItem := InternalItems[P];
  489. while Compare(PivotItem, InternalItems[I]) > 0 do
  490. Inc(I);
  491. while Compare(PivotItem, InternalItems[J]) < 0 do
  492. Dec(J);
  493. if I <= J then
  494. begin
  495. InternalExchange(I, J);
  496. if P = I then
  497. P := J
  498. else if P = J then
  499. P := I;
  500. Inc(I);
  501. Dec(J);
  502. end;
  503. until I > J;
  504. if L < J then
  505. QuickSort(L, J, Compare);
  506. L := I;
  507. until I >= R;
  508. end;
  509. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  510. begin
  511. if not Assigned(FList) or (FCount < 2) then exit;
  512. QuickSort(0, FCount-1, Compare);
  513. end;
  514. procedure TFPSList.Assign(Obj: TFPSList);
  515. var
  516. i: Integer;
  517. begin
  518. if Obj.ItemSize <> FItemSize then
  519. Error(SListItemSizeError, 0);
  520. Clear;
  521. for I := 0 to Obj.Count - 1 do
  522. Add(Obj[i]);
  523. end;
  524. {$ifndef VER2_0}
  525. {****************************************************************************}
  526. {* TFPGList *}
  527. {****************************************************************************}
  528. constructor TFPGList.Create;
  529. begin
  530. inherited Create(sizeof(T));
  531. end;
  532. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  533. begin
  534. T(Dest^) := T(Src^);
  535. end;
  536. procedure TFPGList.Deref(Item: Pointer);
  537. begin
  538. Finalize(T(Item^));
  539. end;
  540. function TFPGList.Get(Index: Integer): T;
  541. begin
  542. Result := T(inherited Get(Index)^);
  543. end;
  544. function TFPGList.GetList: PTypeList;
  545. begin
  546. Result := PTypeList(FList);
  547. end;
  548. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  549. begin
  550. Result := FOnCompare(T(Item1^), T(Item2^));
  551. end;
  552. procedure TFPGList.Put(Index: Integer; const Item: T);
  553. begin
  554. inherited Put(Index, @Item);
  555. end;
  556. function TFPGList.Add(const Item: T): Integer;
  557. begin
  558. Result := inherited Add(@Item);
  559. end;
  560. function TFPGList.Extract(const Item: T): T;
  561. var
  562. ResPtr: Pointer;
  563. begin
  564. ResPtr := inherited Extract(@Item);
  565. if ResPtr <> nil then
  566. Result := T(ResPtr^)
  567. else
  568. FillByte(Result, 0, sizeof(T));
  569. end;
  570. function TFPGList.First: T;
  571. begin
  572. Result := T(inherited First^);
  573. end;
  574. function TFPGList.IndexOf(const Item: T): Integer;
  575. begin
  576. Result := 0;
  577. {$info TODO: fix inlining to work! InternalItems[Result]^}
  578. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  579. Inc(Result);
  580. if Result = FCount then
  581. Result := -1;
  582. end;
  583. procedure TFPGList.Insert(Index: Integer; const Item: T);
  584. begin
  585. T(inherited Insert(Index)^) := Item;
  586. end;
  587. function TFPGList.Last: T;
  588. begin
  589. Result := T(inherited Last^);
  590. end;
  591. function TFPGList.Remove(const Item: T): Integer;
  592. begin
  593. Result := IndexOf(Item);
  594. if Result >= 0 then
  595. Delete(Result);
  596. end;
  597. procedure TFPGList.Sort(Compare: TCompareFunc);
  598. begin
  599. FOnCompare := Compare;
  600. inherited Sort(@ItemPtrCompare);
  601. end;
  602. {****************************************************************************}
  603. {* TFPGObjectList *}
  604. {****************************************************************************}
  605. constructor TFPGObjectList.Create;
  606. begin
  607. inherited Create;
  608. end;
  609. procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
  610. begin
  611. T(Dest^) := T(Src^);
  612. end;
  613. procedure TFPGObjectList.Deref(Item: Pointer);
  614. begin
  615. T(Item^).Free;
  616. end;
  617. function TFPGObjectList.Get(Index: Integer): T;
  618. begin
  619. Result := T(inherited Get(Index)^);
  620. end;
  621. function TFPGObjectList.GetList: PTypeList;
  622. begin
  623. Result := PTypeList(FList);
  624. end;
  625. function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  626. begin
  627. Result := FOnCompare(T(Item1^), T(Item2^));
  628. end;
  629. procedure TFPGObjectList.Put(Index: Integer; const Item: T);
  630. begin
  631. inherited Put(Index, @Item);
  632. end;
  633. function TFPGObjectList.Add(const Item: T): Integer;
  634. begin
  635. Result := inherited Add(@Item);
  636. end;
  637. function TFPGObjectList.Extract(const Item: T): T;
  638. var
  639. ResPtr: Pointer;
  640. begin
  641. ResPtr := inherited Extract(@Item);
  642. if ResPtr <> nil then
  643. Result := T(ResPtr^)
  644. else
  645. FillByte(Result, 0, sizeof(T));
  646. end;
  647. function TFPGObjectList.First: T;
  648. begin
  649. Result := T(inherited First^);
  650. end;
  651. function TFPGObjectList.IndexOf(const Item: T): Integer;
  652. begin
  653. Result := 0;
  654. {$info TODO: fix inlining to work! InternalItems[Result]^}
  655. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  656. Inc(Result);
  657. if Result = FCount then
  658. Result := -1;
  659. end;
  660. procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
  661. begin
  662. T(inherited Insert(Index)^) := Item;
  663. end;
  664. function TFPGObjectList.Last: T;
  665. begin
  666. Result := T(inherited Last^);
  667. end;
  668. function TFPGObjectList.Remove(const Item: T): Integer;
  669. begin
  670. Result := IndexOf(Item);
  671. if Result >= 0 then
  672. Delete(Result);
  673. end;
  674. procedure TFPGObjectList.Sort(Compare: TCompareFunc);
  675. begin
  676. FOnCompare := Compare;
  677. inherited Sort(@ItemPtrCompare);
  678. end;
  679. {$endif}
  680. {****************************************************************************
  681. TFPSMap
  682. ****************************************************************************}
  683. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  684. begin
  685. inherited Create(AKeySize+ADataSize);
  686. FKeySize := AKeySize;
  687. FDataSize := ADataSize;
  688. InitOnPtrCompare;
  689. end;
  690. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  691. begin
  692. System.Move(Src^, Dest^, FKeySize);
  693. end;
  694. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  695. begin
  696. System.Move(Src^, Dest^, FDataSize);
  697. end;
  698. function TFPSMap.BinaryCompare(Key1, Key2: Pointer): Integer;
  699. begin
  700. Result := CompareByte(Key1^, Key2^, FKeySize);
  701. end;
  702. function TFPSMap.GetKey(Index: Integer): Pointer;
  703. begin
  704. Result := Items[Index];
  705. end;
  706. function TFPSMap.GetData(Index: Integer): Pointer;
  707. begin
  708. Result := PByte(Items[Index])+FKeySize;
  709. end;
  710. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  711. var
  712. I: Integer;
  713. begin
  714. I := IndexOf(AKey);
  715. if I >= 0 then
  716. Result := InternalItems[I]+FKeySize
  717. else
  718. Error(SMapKeyError, PtrUInt(AKey));
  719. end;
  720. procedure TFPSMap.InitOnPtrCompare;
  721. begin
  722. FOnPtrCompare := @BinaryCompare;
  723. end;
  724. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  725. begin
  726. if FSorted then
  727. Error(SSortedListError, 0);
  728. CopyKey(AKey, Items[Index]);
  729. end;
  730. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  731. begin
  732. CopyData(AData, PByte(Items[Index])+FKeySize);
  733. end;
  734. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  735. var
  736. I: Integer;
  737. begin
  738. I := IndexOf(AKey);
  739. if I >= 0 then
  740. Data[I] := NewData
  741. else
  742. Add(AKey, NewData);
  743. end;
  744. procedure TFPSMap.SetSorted(Value: Boolean);
  745. begin
  746. if Value = FSorted then exit;
  747. FSorted := Value;
  748. if Value then Sort;
  749. end;
  750. function TFPSMap.Add(AKey: Pointer): Integer;
  751. begin
  752. if Sorted then
  753. begin
  754. if Find(AKey, Result) then
  755. case Duplicates of
  756. dupIgnore: exit;
  757. dupError: Error(SDuplicateItem, 0)
  758. end;
  759. end else
  760. Result := Count;
  761. CopyKey(AKey, inherited Insert(Result));
  762. end;
  763. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  764. begin
  765. Result := Add(AKey);
  766. Data[Result] := AData;
  767. end;
  768. function TFPSMap.Find(AKey: Pointer; var Index: Integer): Boolean;
  769. { Searches for the first item <= Key, returns True if exact match,
  770. sets index to the index f the found string. }
  771. var
  772. I,L,R,Dir: Integer;
  773. begin
  774. Result := false;
  775. // Use binary search.
  776. L := 0;
  777. R := FCount-1;
  778. while L<=R do
  779. begin
  780. I := (L+R) div 2;
  781. Dir := FOnPtrCompare(Items[I], AKey);
  782. if Dir < 0 then
  783. L := I+1
  784. else begin
  785. R := I-1;
  786. if Dir = 0 then
  787. begin
  788. Result := true;
  789. if Duplicates <> dupAccept then
  790. L := I;
  791. end;
  792. end;
  793. end;
  794. Index := L;
  795. end;
  796. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  797. var
  798. ListItem: Pointer;
  799. begin
  800. Result := 0;
  801. ListItem := First;
  802. while (Result < FCount) and (FOnPtrCompare(ListItem, AKey) <> 0) do
  803. begin
  804. Inc(Result);
  805. ListItem := PByte(ListItem)+FItemSize;
  806. end;
  807. if Result = FCount then Result := -1;
  808. end;
  809. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  810. begin
  811. if Sorted then
  812. begin
  813. if not Find(AKey, Result) then
  814. Result := -1;
  815. end else
  816. Result := LinearIndexOf(AKey);
  817. end;
  818. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  819. var
  820. ListItem: Pointer;
  821. begin
  822. Result := 0;
  823. ListItem := First+FKeySize;
  824. while (Result < FCount) and (CompareByte(ListItem^, AData^, FDataSize) <> 0) do
  825. begin
  826. Inc(Result);
  827. ListItem := PByte(ListItem)+FItemSize;
  828. end;
  829. if Result = FCount then Result := -1;
  830. end;
  831. function TFPSMap.Insert(Index: Integer): Pointer;
  832. begin
  833. if FSorted then
  834. Error(SSortedListError, 0);
  835. Result := inherited Insert(Index);
  836. end;
  837. procedure TFPSMap.Insert(Index: Integer; var AKey, AData: Pointer);
  838. begin
  839. AKey := Insert(Index);
  840. AData := PByte(AKey) + FKeySize;
  841. end;
  842. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  843. begin
  844. CopyKey(AKey, Insert(Index));
  845. end;
  846. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  847. var
  848. ListItem: Pointer;
  849. begin
  850. ListItem := Insert(Index);
  851. CopyKey(AKey, ListItem);
  852. CopyData(AData, PByte(ListItem)+FKeySize);
  853. end;
  854. function TFPSMap.Remove(AKey: Pointer): Integer;
  855. begin
  856. Result := IndexOf(AKey);
  857. if Result >= 0 then
  858. Delete(Result);
  859. end;
  860. procedure TFPSMap.Sort;
  861. begin
  862. inherited Sort(FOnPtrCompare);
  863. end;
  864. {****************************************************************************
  865. TFPGMap
  866. ****************************************************************************}
  867. {$ifndef VER2_0}
  868. constructor TFPGMap.Create;
  869. begin
  870. inherited Create(SizeOf(TKey), SizeOf(TData));
  871. end;
  872. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  873. begin
  874. CopyKey(Src, Dest);
  875. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  876. end;
  877. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  878. begin
  879. TKey(Dest^) := TKey(Src^);
  880. end;
  881. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  882. begin
  883. TData(Dest^) := TData(Src^);
  884. end;
  885. procedure TFPGMap.Deref(Item: Pointer);
  886. begin
  887. Finalize(TKey(Item^));
  888. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  889. end;
  890. function TFPGMap.GetKey(Index: Integer): TKey;
  891. begin
  892. Result := TKey(inherited GetKey(Index)^);
  893. end;
  894. function TFPGMap.GetData(Index: Integer): TData;
  895. begin
  896. Result := TData(inherited GetData(Index)^);
  897. end;
  898. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  899. begin
  900. Result := TData(inherited GetKeyData(@AKey)^);
  901. end;
  902. procedure TFPGMap.InitOnPtrCompare;
  903. begin
  904. OnPtrCompare := @KeyCompare;
  905. end;
  906. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  907. begin
  908. if PKey(Key1)^ < PKey(Key2)^ then
  909. Result := -1
  910. else if PKey(Key1)^ > PKey(Key2)^ then
  911. Result := 1
  912. else
  913. Result := 0;
  914. end;
  915. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  916. begin
  917. Result := FOnCompare(TKey(Key1^), TKey(Key2^));
  918. end;
  919. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  920. begin
  921. inherited PutKey(Index, @NewKey);
  922. end;
  923. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  924. begin
  925. inherited PutData(Index, @NewData);
  926. end;
  927. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  928. begin
  929. inherited PutKeyData(@AKey, @NewData);
  930. end;
  931. procedure TFPGMap.SetOnCompare(NewCompare: TCompareFunc);
  932. begin
  933. FOnCompare := NewCompare;
  934. if NewCompare <> nil then
  935. OnPtrCompare := @KeyCustomCompare
  936. else
  937. InitOnPtrCompare;
  938. end;
  939. function TFPGMap.Add(const AKey: TKey): Integer;
  940. begin
  941. Result := inherited Add(@AKey);
  942. end;
  943. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  944. begin
  945. Result := inherited Add(@AKey, @AData);
  946. end;
  947. function TFPGMap.Find(const AKey: TKey; var Index: Integer): Boolean;
  948. begin
  949. Result := inherited Find(@AKey, Index);
  950. end;
  951. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  952. begin
  953. Result := inherited IndexOf(@AKey);
  954. end;
  955. function TFPGMap.IndexOfData(const AData: TData): Integer;
  956. begin
  957. { TODO: loop ? }
  958. Result := inherited IndexOfData(@AData);
  959. end;
  960. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  961. begin
  962. inherited InsertKey(Index, @AKey);
  963. end;
  964. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  965. begin
  966. inherited InsertKeyData(Index, @AKey, @AData);
  967. end;
  968. function TFPGMap.Remove(const AKey: TKey): Integer;
  969. begin
  970. Result := inherited Remove(@AKey);
  971. end;
  972. {$endif}
  973. end.