contnrs.pp 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2002 by Florian Klaempfl
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$ifdef fpc}
  11. {$mode objfpc}
  12. {$endif}
  13. {$H+}
  14. {$ifdef CLASSESINLINE}{$inline on}{$endif}
  15. unit contnrs;
  16. interface
  17. uses
  18. SysUtils,Classes;
  19. Type
  20. TObjectListCallback = procedure(data:TObject;arg:pointer) of object;
  21. TObjectListStaticCallback = procedure(data:TObject;arg:pointer);
  22. TFPObjectList = class(TObject)
  23. private
  24. FFreeObjects : Boolean;
  25. FList: TFPList;
  26. function GetCount: integer;
  27. procedure SetCount(const AValue: integer);
  28. protected
  29. function GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
  30. procedure SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  31. procedure SetCapacity(NewCapacity: Integer);
  32. function GetCapacity: integer;
  33. public
  34. constructor Create;
  35. constructor Create(FreeObjects : Boolean);
  36. destructor Destroy; override;
  37. procedure Clear;
  38. function Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
  39. procedure Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
  40. procedure Exchange(Index1, Index2: Integer);
  41. function Expand: TFPObjectList;
  42. function Extract(Item: TObject): TObject;
  43. function Remove(AObject: TObject): Integer;
  44. function IndexOf(AObject: TObject): Integer;
  45. function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
  46. procedure Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  47. function First: TObject;
  48. function Last: TObject;
  49. procedure Move(CurIndex, NewIndex: Integer);
  50. procedure Assign(Obj:TFPObjectList);
  51. procedure Pack;
  52. procedure Sort(Compare: TListSortCompare);
  53. procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  54. procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  55. property Capacity: Integer read GetCapacity write SetCapacity;
  56. property Count: Integer read GetCount write SetCount;
  57. property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
  58. property Items[Index: Integer]: TObject read GetItem write SetItem; default;
  59. property List: TFPList read FList;
  60. end;
  61. TObjectList = class(TList)
  62. private
  63. ffreeobjects : boolean;
  64. Protected
  65. Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  66. function GetItem(Index: Integer): TObject;
  67. Procedure SetItem(Index: Integer; AObject: TObject);
  68. public
  69. constructor create;
  70. constructor create(freeobjects : boolean);
  71. function Add(AObject: TObject): Integer;
  72. function Extract(Item: TObject): TObject;
  73. function Remove(AObject: TObject): Integer;
  74. function IndexOf(AObject: TObject): Integer;
  75. function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
  76. Procedure Insert(Index: Integer; AObject: TObject);
  77. function First: TObject;
  78. Function Last: TObject;
  79. property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
  80. property Items[Index: Integer]: TObject read GetItem write SetItem; default;
  81. end;
  82. TComponentList = class(TObjectList)
  83. Private
  84. FNotifier : TComponent;
  85. Protected
  86. Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  87. Function GetItems(Index: Integer): TComponent;
  88. Procedure SetItems(Index: Integer; AComponent: TComponent);
  89. Procedure HandleFreeNotify(Sender: TObject; AComponent: TComponent);
  90. public
  91. destructor Destroy; override;
  92. Function Add(AComponent: TComponent): Integer;
  93. Function Extract(Item: TComponent): TComponent;
  94. Function Remove(AComponent: TComponent): Integer;
  95. Function IndexOf(AComponent: TComponent): Integer;
  96. Function First: TComponent;
  97. Function Last: TComponent;
  98. Procedure Insert(Index: Integer; AComponent: TComponent);
  99. property Items[Index: Integer]: TComponent read GetItems write SetItems; default;
  100. end;
  101. TClassList = class(TList)
  102. protected
  103. Function GetItems(Index: Integer): TClass;
  104. Procedure SetItems(Index: Integer; AClass: TClass);
  105. public
  106. Function Add(AClass: TClass): Integer;
  107. Function Extract(Item: TClass): TClass;
  108. Function Remove(AClass: TClass): Integer;
  109. Function IndexOf(AClass: TClass): Integer;
  110. Function First: TClass;
  111. Function Last: TClass;
  112. Procedure Insert(Index: Integer; AClass: TClass);
  113. property Items[Index: Integer]: TClass read GetItems write SetItems; default;
  114. end;
  115. TOrderedList = class(TObject)
  116. private
  117. FList: TList;
  118. protected
  119. Procedure PushItem(AItem: Pointer); virtual; abstract;
  120. Function PopItem: Pointer; virtual;
  121. Function PeekItem: Pointer; virtual;
  122. property List: TList read FList;
  123. public
  124. constructor Create;
  125. destructor Destroy; override;
  126. Function Count: Integer;
  127. Function AtLeast(ACount: Integer): Boolean;
  128. Function Push(AItem: Pointer): Pointer;
  129. Function Pop: Pointer;
  130. Function Peek: Pointer;
  131. end;
  132. { TStack class }
  133. TStack = class(TOrderedList)
  134. protected
  135. Procedure PushItem(AItem: Pointer); override;
  136. end;
  137. { TObjectStack class }
  138. TObjectStack = class(TStack)
  139. public
  140. Function Push(AObject: TObject): TObject;
  141. Function Pop: TObject;
  142. Function Peek: TObject;
  143. end;
  144. { TQueue class }
  145. TQueue = class(TOrderedList)
  146. protected
  147. Procedure PushItem(AItem: Pointer); override;
  148. end;
  149. { TObjectQueue class }
  150. TObjectQueue = class(TQueue)
  151. public
  152. Function Push(AObject: TObject): TObject;
  153. Function Pop: TObject;
  154. Function Peek: TObject;
  155. end;
  156. { ---------------------------------------------------------------------
  157. TFPList with Hash support
  158. ---------------------------------------------------------------------}
  159. type
  160. THashItem=record
  161. HashValue : LongWord;
  162. StrIndex : Integer;
  163. NextIndex : Integer;
  164. Data : Pointer;
  165. end;
  166. PHashItem=^THashItem;
  167. const
  168. MaxHashListSize = Maxint div 16;
  169. MaxHashStrSize = Maxint;
  170. MaxHashTableSize = Maxint div 4;
  171. MaxItemsPerHash = 3;
  172. type
  173. PHashItemList = ^THashItemList;
  174. THashItemList = array[0..MaxHashListSize - 1] of THashItem;
  175. PHashTable = ^THashTable;
  176. THashTable = array[0..MaxHashTableSize - 1] of Integer;
  177. TFPHashList = class(TObject)
  178. private
  179. { ItemList }
  180. FHashList : PHashItemList;
  181. FCount,
  182. FCapacity : Integer;
  183. { Hash }
  184. FHashTable : PHashTable;
  185. FHashCapacity : Integer;
  186. { Strings }
  187. FStrs : PChar;
  188. FStrCount,
  189. FStrCapacity : Integer;
  190. function InternalFind(AHash:LongWord;const AName:shortstring;out PrevIndex:Integer):Integer;
  191. protected
  192. function Get(Index: Integer): Pointer; {$ifdef CCLASSESINLINE}inline;{$endif}
  193. procedure Put(Index: Integer; Item: Pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
  194. procedure SetCapacity(NewCapacity: Integer);
  195. procedure SetCount(NewCount: Integer);
  196. Procedure RaiseIndexError(Index : Integer);
  197. function AddStr(const s:shortstring): Integer;
  198. procedure AddToHashTable(Index: Integer);
  199. procedure StrExpand(MinIncSize:Integer);
  200. procedure SetStrCapacity(NewCapacity: Integer);
  201. procedure SetHashCapacity(NewCapacity: Integer);
  202. procedure ReHash;
  203. public
  204. constructor Create;
  205. destructor Destroy; override;
  206. function Add(const AName:shortstring;Item: Pointer): Integer;
  207. procedure Clear;
  208. function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
  209. function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
  210. procedure Delete(Index: Integer);
  211. class procedure Error(const Msg: string; Data: PtrInt);
  212. function Expand: TFPHashList;
  213. function Extract(item: Pointer): Pointer;
  214. function IndexOf(Item: Pointer): Integer;
  215. function Find(const AName:shortstring): Pointer;
  216. function FindIndexOf(const AName:shortstring): Integer;
  217. function FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
  218. function Rename(const AOldName,ANewName:shortstring): Integer;
  219. function Remove(Item: Pointer): Integer;
  220. procedure Pack;
  221. procedure ShowStatistics;
  222. procedure ForEachCall(proc2call:TListCallback;arg:pointer);
  223. procedure ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  224. property Capacity: Integer read FCapacity write SetCapacity;
  225. property Count: Integer read FCount write SetCount;
  226. property Items[Index: Integer]: Pointer read Get write Put; default;
  227. property List: PHashItemList read FHashList;
  228. property Strs: PChar read FStrs;
  229. end;
  230. {*******************************************************
  231. TFPHashObjectList (From fcl/inc/contnrs.pp)
  232. ********************************************************}
  233. TFPHashObjectList = class;
  234. { TFPHashObject }
  235. TFPHashObject = class
  236. private
  237. FOwner : TFPHashObjectList;
  238. FCachedStr : pshortstring;
  239. FStrIndex : Integer;
  240. procedure InternalChangeOwner(HashObjectList:TFPHashObjectList;const s:shortstring);
  241. protected
  242. function GetName:shortstring;virtual;
  243. function GetHash:Longword;virtual;
  244. public
  245. constructor CreateNotOwned;
  246. constructor Create(HashObjectList:TFPHashObjectList;const s:shortstring);
  247. procedure ChangeOwner(HashObjectList:TFPHashObjectList); {$ifdef CCLASSESINLINE}inline;{$endif}
  248. procedure ChangeOwnerAndName(HashObjectList:TFPHashObjectList;const s:shortstring); {$ifdef CCLASSESINLINE}inline;{$endif}
  249. procedure Rename(const ANewName:shortstring);
  250. property Name:shortstring read GetName;
  251. property Hash:Longword read GetHash;
  252. end;
  253. TFPHashObjectList = class(TObject)
  254. private
  255. FFreeObjects : Boolean;
  256. FHashList: TFPHashList;
  257. function GetCount: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  258. procedure SetCount(const AValue: integer); {$ifdef CCLASSESINLINE}inline;{$endif}
  259. protected
  260. function GetItem(Index: Integer): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  261. procedure SetItem(Index: Integer; AObject: TObject); {$ifdef CCLASSESINLINE}inline;{$endif}
  262. procedure SetCapacity(NewCapacity: Integer); {$ifdef CCLASSESINLINE}inline;{$endif}
  263. function GetCapacity: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  264. public
  265. constructor Create(FreeObjects : boolean = True);
  266. destructor Destroy; override;
  267. procedure Clear;
  268. function Add(const AName:shortstring;AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  269. function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
  270. function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
  271. procedure Delete(Index: Integer);
  272. function Expand: TFPHashObjectList; {$ifdef CCLASSESINLINE}inline;{$endif}
  273. function Extract(Item: TObject): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  274. function Remove(AObject: TObject): Integer;
  275. function IndexOf(AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  276. function Find(const s:shortstring): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  277. function FindIndexOf(const s:shortstring): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  278. function FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
  279. function Rename(const AOldName,ANewName:shortstring): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  280. function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
  281. procedure Pack; {$ifdef CCLASSESINLINE}inline;{$endif}
  282. procedure ShowStatistics; {$ifdef CCLASSESINLINE}inline;{$endif}
  283. procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
  284. procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
  285. property Capacity: Integer read GetCapacity write SetCapacity;
  286. property Count: Integer read GetCount write SetCount;
  287. property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
  288. property Items[Index: Integer]: TObject read GetItem write SetItem; default;
  289. property List: TFPHashList read FHashList;
  290. end;
  291. { ---------------------------------------------------------------------
  292. Hash support, implemented by Dean Zobec
  293. ---------------------------------------------------------------------}
  294. { Must return a Longword value in the range 0..TableSize,
  295. usually via a mod operator; }
  296. THashFunction = function(const S: string; const TableSize: Longword): Longword;
  297. { THTNode }
  298. THTCustomNode = class(TObject)
  299. private
  300. FKey: string;
  301. public
  302. constructor CreateWith(const AString: String);
  303. function HasKey(const AKey: string): boolean;
  304. property Key: string read FKey;
  305. end;
  306. THTCustomNodeClass = Class of THTCustomNode;
  307. { TFPCustomHashTable }
  308. TFPCustomHashTable = class(TObject)
  309. private
  310. FHashTable: TFPObjectList;
  311. FHashTableSize: Longword;
  312. FHashFunction: THashFunction;
  313. FCount: Longword;
  314. function GetDensity: Longword;
  315. function GetNumberOfCollisions: Longword;
  316. procedure SetHashTableSize(const Value: Longword);
  317. procedure InitializeHashTable;
  318. function GetVoidSlots: Longword;
  319. function GetLoadFactor: double;
  320. function GetAVGChainLen: double;
  321. function GetMaxChainLength: Longword;
  322. function Chain(const index: Longword):TFPObjectList;
  323. protected
  324. Function CreateNewNode(const aKey : string) : THTCustomNode; virtual; abstract;
  325. Procedure AddNode(ANode : THTCustomNode); virtual; abstract;
  326. function ChainLength(const ChainIndex: Longword): Longword; virtual;
  327. function FindOrCreateNew(const aKey: string): THTCustomNode; virtual;
  328. procedure SetHashFunction(AHashFunction: THashFunction); virtual;
  329. Function FindChainForAdd(Const aKey : String) : TFPObjectList;
  330. public
  331. constructor Create;
  332. constructor CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction);
  333. destructor Destroy; override;
  334. procedure ChangeTableSize(const ANewSize: Longword); virtual;
  335. procedure Clear; virtual;
  336. procedure Delete(const aKey: string); virtual;
  337. function Find(const aKey: string): THTCustomNode;
  338. function IsEmpty: boolean;
  339. property HashFunction: THashFunction read FHashFunction write SetHashFunction;
  340. property Count: Longword read FCount;
  341. property HashTableSize: Longword read FHashTableSize write SetHashTableSize;
  342. property HashTable: TFPObjectList read FHashTable;
  343. property VoidSlots: Longword read GetVoidSlots;
  344. property LoadFactor: double read GetLoadFactor;
  345. property AVGChainLen: double read GetAVGChainLen;
  346. property MaxChainLength: Longword read GetMaxChainLength;
  347. property NumberOfCollisions: Longword read GetNumberOfCollisions;
  348. property Density: Longword read GetDensity;
  349. end;
  350. { TFPDataHashTable : Hash table with simple data pointers }
  351. THTDataNode = Class(THTCustomNode)
  352. Private
  353. FData: pointer;
  354. public
  355. property Data: pointer read FData write FData;
  356. end;
  357. // For compatibility
  358. THTNode = THTDataNode;
  359. TDataIteratorMethod = procedure(Item: Pointer; const Key: string; var Continue: Boolean) of object;
  360. // For compatibility
  361. TIteratorMethod = TDataIteratorMethod;
  362. TFPDataHashTable = Class(TFPCustomHashTable)
  363. Protected
  364. Function CreateNewNode(const aKey : String) : THTCustomNode; override;
  365. Procedure AddNode(ANode : THTCustomNode); override;
  366. procedure SetData(const index: string; const AValue: Pointer); virtual;
  367. function GetData(const index: string):Pointer; virtual;
  368. function ForEachCall(aMethod: TDataIteratorMethod): THTDataNode; virtual;
  369. Public
  370. procedure Add(const aKey: string; AItem: pointer); virtual;
  371. property Items[const index: string]: Pointer read GetData write SetData; default;
  372. end;
  373. { TFPStringHashTable : Hash table with simple strings as data }
  374. THTStringNode = Class(THTCustomNode)
  375. Private
  376. FData : String;
  377. public
  378. property Data: String read FData write FData;
  379. end;
  380. TStringIteratorMethod = procedure(Item: String; const Key: string; var Continue: Boolean) of object;
  381. TFPStringHashTable = Class(TFPCustomHashTable)
  382. Protected
  383. Function CreateNewNode(const aKey : String) : THTCustomNode; override;
  384. Procedure AddNode(ANode : THTCustomNode); override;
  385. procedure SetData(const Index, AValue: string); virtual;
  386. function GetData(const index: string): String; virtual;
  387. function ForEachCall(aMethod: TStringIteratorMethod): THTStringNode; virtual;
  388. Public
  389. procedure Add(const aKey,aItem: string); virtual;
  390. property Items[const index: string]: String read GetData write SetData; default;
  391. end;
  392. { TFPStringHashTable : Hash table with simple strings as data }
  393. THTObjectNode = Class(THTCustomNode)
  394. Private
  395. FData : TObject;
  396. public
  397. property Data: TObject read FData write FData;
  398. end;
  399. THTOwnedObjectNode = Class(THTObjectNode)
  400. public
  401. Destructor Destroy; override;
  402. end;
  403. TObjectIteratorMethod = procedure(Item: TObject; const Key: string; var Continue: Boolean) of object;
  404. TFPObjectHashTable = Class(TFPCustomHashTable)
  405. Private
  406. FOwnsObjects : Boolean;
  407. Protected
  408. Function CreateNewNode(const aKey : String) : THTCustomNode; override;
  409. Procedure AddNode(ANode : THTCustomNode); override;
  410. procedure SetData(const Index: string; AObject : TObject); virtual;
  411. function GetData(const index: string): TObject; virtual;
  412. function ForEachCall(aMethod: TObjectIteratorMethod): THTObjectNode; virtual;
  413. Public
  414. constructor Create(AOwnsObjects : Boolean = True);
  415. constructor CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction; AOwnsObjects : Boolean = True);
  416. procedure Add(const aKey: string; AItem : TObject); virtual;
  417. property Items[const index: string]: TObject read GetData write SetData; default;
  418. Property OwnsObjects : Boolean Read FOwnsObjects Write FOwnsObjects;
  419. end;
  420. EDuplicate = class(Exception);
  421. EKeyNotFound = class(Exception);
  422. function RSHash(const S: string; const TableSize: Longword): Longword;
  423. implementation
  424. uses
  425. RtlConsts;
  426. ResourceString
  427. DuplicateMsg = 'An item with key %0:s already exists';
  428. KeyNotFoundMsg = 'Method: %0:s key [''%1:s''] not found in container';
  429. NotEmptyMsg = 'Hash table not empty.';
  430. const
  431. NPRIMES = 28;
  432. PRIMELIST: array[0 .. NPRIMES-1] of Longword =
  433. ( 53, 97, 193, 389, 769,
  434. 1543, 3079, 6151, 12289, 24593,
  435. 49157, 98317, 196613, 393241, 786433,
  436. 1572869, 3145739, 6291469, 12582917, 25165843,
  437. 50331653, 100663319, 201326611, 402653189, 805306457,
  438. 1610612741, 3221225473, 4294967291 );
  439. constructor TFPObjectList.Create(FreeObjects : boolean);
  440. begin
  441. Create;
  442. FFreeObjects := Freeobjects;
  443. end;
  444. destructor TFPObjectList.Destroy;
  445. begin
  446. if (FList <> nil) then
  447. begin
  448. Clear;
  449. FList.Destroy;
  450. end;
  451. inherited Destroy;
  452. end;
  453. procedure TFPObjectList.Clear;
  454. var
  455. i: integer;
  456. begin
  457. if FFreeObjects then
  458. for i := 0 to FList.Count - 1 do
  459. TObject(FList[i]).Free;
  460. FList.Clear;
  461. end;
  462. constructor TFPObjectList.Create;
  463. begin
  464. inherited Create;
  465. FList := TFPList.Create;
  466. FFreeObjects := True;
  467. end;
  468. function TFPObjectList.GetCount: integer;
  469. begin
  470. Result := FList.Count;
  471. end;
  472. procedure TFPObjectList.SetCount(const AValue: integer);
  473. begin
  474. if FList.Count <> AValue then
  475. FList.Count := AValue;
  476. end;
  477. function TFPObjectList.GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
  478. begin
  479. Result := TObject(FList[Index]);
  480. end;
  481. procedure TFPObjectList.SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  482. begin
  483. if OwnsObjects then
  484. TObject(FList[Index]).Free;
  485. FList[index] := AObject;
  486. end;
  487. procedure TFPObjectList.SetCapacity(NewCapacity: Integer);
  488. begin
  489. FList.Capacity := NewCapacity;
  490. end;
  491. function TFPObjectList.GetCapacity: integer;
  492. begin
  493. Result := FList.Capacity;
  494. end;
  495. function TFPObjectList.Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
  496. begin
  497. Result := FList.Add(AObject);
  498. end;
  499. procedure TFPObjectList.Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
  500. begin
  501. if OwnsObjects then
  502. TObject(FList[Index]).Free;
  503. FList.Delete(Index);
  504. end;
  505. procedure TFPObjectList.Exchange(Index1, Index2: Integer);
  506. begin
  507. FList.Exchange(Index1, Index2);
  508. end;
  509. function TFPObjectList.Expand: TFPObjectList;
  510. begin
  511. FList.Expand;
  512. Result := Self;
  513. end;
  514. function TFPObjectList.Extract(Item: TObject): TObject;
  515. begin
  516. Result := TObject(FList.Extract(Item));
  517. end;
  518. function TFPObjectList.Remove(AObject: TObject): Integer;
  519. begin
  520. Result := IndexOf(AObject);
  521. if (Result <> -1) then
  522. begin
  523. if OwnsObjects then
  524. TObject(FList[Result]).Free;
  525. FList.Delete(Result);
  526. end;
  527. end;
  528. function TFPObjectList.IndexOf(AObject: TObject): Integer;
  529. begin
  530. Result := FList.IndexOf(Pointer(AObject));
  531. end;
  532. function TFPObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
  533. var
  534. I : Integer;
  535. begin
  536. I:=AStartAt;
  537. Result:=-1;
  538. If AExact then
  539. while (I<Count) and (Result=-1) do
  540. If Items[i].ClassType=AClass then
  541. Result:=I
  542. else
  543. Inc(I)
  544. else
  545. while (I<Count) and (Result=-1) do
  546. If Items[i].InheritsFrom(AClass) then
  547. Result:=I
  548. else
  549. Inc(I);
  550. end;
  551. procedure TFPObjectList.Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  552. begin
  553. FList.Insert(Index, Pointer(AObject));
  554. end;
  555. procedure TFPObjectList.Move(CurIndex, NewIndex: Integer);
  556. begin
  557. FList.Move(CurIndex, NewIndex);
  558. end;
  559. procedure TFPObjectList.Assign(Obj: TFPObjectList);
  560. var
  561. i: Integer;
  562. begin
  563. Clear;
  564. for I := 0 to Obj.Count - 1 do
  565. Add(Obj[i]);
  566. end;
  567. procedure TFPObjectList.Pack;
  568. begin
  569. FList.Pack;
  570. end;
  571. procedure TFPObjectList.Sort(Compare: TListSortCompare);
  572. begin
  573. FList.Sort(Compare);
  574. end;
  575. function TFPObjectList.First: TObject;
  576. begin
  577. Result := TObject(FList.First);
  578. end;
  579. function TFPObjectList.Last: TObject;
  580. begin
  581. Result := TObject(FList.Last);
  582. end;
  583. procedure TFPObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  584. begin
  585. FList.ForEachCall(TListCallBack(proc2call),arg);
  586. end;
  587. procedure TFPObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  588. begin
  589. FList.ForEachCall(TListStaticCallBack(proc2call),arg);
  590. end;
  591. { TObjectList }
  592. constructor tobjectlist.create(freeobjects : boolean);
  593. begin
  594. inherited create;
  595. ffreeobjects:=freeobjects;
  596. end;
  597. Constructor tobjectlist.create;
  598. begin
  599. inherited create;
  600. ffreeobjects:=True;
  601. end;
  602. Procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
  603. begin
  604. if FFreeObjects then
  605. if (Action=lnDeleted) then
  606. TObject(Ptr).Free;
  607. inherited Notify(Ptr,Action);
  608. end;
  609. Function TObjectList.GetItem(Index: Integer): TObject;
  610. begin
  611. Result:=TObject(Inherited Get(Index));
  612. end;
  613. Procedure TObjectList.SetItem(Index: Integer; AObject: TObject);
  614. Var
  615. O : TObject;
  616. begin
  617. if OwnsObjects then
  618. begin
  619. O:=GetItem(Index);
  620. O.Free;
  621. end;
  622. Put(Index,Pointer(AObject));
  623. end;
  624. Function TObjectList.Add(AObject: TObject): Integer;
  625. begin
  626. Result:=Inherited Add(Pointer(AObject));
  627. end;
  628. Function TObjectList.Extract(Item: TObject): TObject;
  629. begin
  630. Result:=Tobject(Inherited Extract(Pointer(Item)));
  631. end;
  632. Function TObjectList.Remove(AObject: TObject): Integer;
  633. begin
  634. Result:=Inherited Remove(Pointer(AObject));
  635. end;
  636. Function TObjectList.IndexOf(AObject: TObject): Integer;
  637. begin
  638. Result:=Inherited indexOF(Pointer(AObject));
  639. end;
  640. Function TObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
  641. Var
  642. I : Integer;
  643. begin
  644. I:=AStartAt;
  645. Result:=-1;
  646. If AExact then
  647. While (I<Count) and (Result=-1) do
  648. If Items[i].ClassType=AClass then
  649. Result:=I
  650. else
  651. Inc(I)
  652. else
  653. While (I<Count) and (Result=-1) do
  654. If Items[i].InheritsFrom(AClass) then
  655. Result:=I
  656. else
  657. Inc(I);
  658. end;
  659. procedure TObjectList.Insert(Index: Integer; AObject: TObject);
  660. begin
  661. Inherited Insert(Index,Pointer(AObject));
  662. end;
  663. function TObjectList.First: TObject;
  664. begin
  665. Result := TObject(Inherited First);
  666. end;
  667. function TObjectList.Last: TObject;
  668. begin
  669. Result := TObject(Inherited Last);
  670. end;
  671. { TListComponent }
  672. Type
  673. TlistComponent = Class(TComponent)
  674. Private
  675. Flist : TComponentList;
  676. Public
  677. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  678. end;
  679. procedure TlistComponent.Notification(AComponent: TComponent;
  680. Operation: TOperation);
  681. begin
  682. If (Operation=opremove) then
  683. Flist.HandleFreeNotify(Self,AComponent);
  684. inherited;
  685. end;
  686. { TComponentList }
  687. Function TComponentList.Add(AComponent: TComponent): Integer;
  688. begin
  689. Result:=Inherited Add(AComponent);
  690. end;
  691. destructor TComponentList.Destroy;
  692. begin
  693. inherited;
  694. FreeAndNil(FNotifier);
  695. end;
  696. Function TComponentList.Extract(Item: TComponent): TComponent;
  697. begin
  698. Result:=TComponent(Inherited Extract(Item));
  699. end;
  700. Function TComponentList.First: TComponent;
  701. begin
  702. Result:=TComponent(Inherited First);
  703. end;
  704. Function TComponentList.GetItems(Index: Integer): TComponent;
  705. begin
  706. Result:=TComponent(Inherited Items[Index]);
  707. end;
  708. Procedure TComponentList.HandleFreeNotify(Sender: TObject;
  709. AComponent: TComponent);
  710. begin
  711. Extract(Acomponent);
  712. end;
  713. Function TComponentList.IndexOf(AComponent: TComponent): Integer;
  714. begin
  715. Result:=Inherited IndexOf(AComponent);
  716. end;
  717. Procedure TComponentList.Insert(Index: Integer; AComponent: TComponent);
  718. begin
  719. Inherited Insert(Index,Acomponent)
  720. end;
  721. Function TComponentList.Last: TComponent;
  722. begin
  723. Result:=TComponent(Inherited Last);
  724. end;
  725. Procedure TComponentList.Notify(Ptr: Pointer; Action: TListNotification);
  726. begin
  727. If FNotifier=NIl then
  728. begin
  729. FNotifier:=TlistComponent.Create(nil);
  730. TlistComponent(FNotifier).FList:=Self;
  731. end;
  732. If Assigned(Ptr) then
  733. With TComponent(Ptr) do
  734. case Action of
  735. lnAdded : FreeNotification(FNotifier);
  736. lnExtracted, lnDeleted: RemoveFreeNotification(FNotifier);
  737. end;
  738. inherited Notify(Ptr, Action);
  739. end;
  740. Function TComponentList.Remove(AComponent: TComponent): Integer;
  741. begin
  742. Result:=Inherited Remove(AComponent);
  743. end;
  744. Procedure TComponentList.SetItems(Index: Integer; AComponent: TComponent);
  745. begin
  746. Put(Index,AComponent);
  747. end;
  748. { TClassList }
  749. Function TClassList.Add(AClass: TClass): Integer;
  750. begin
  751. Result:=Inherited Add(Pointer(AClass));
  752. end;
  753. Function TClassList.Extract(Item: TClass): TClass;
  754. begin
  755. Result:=TClass(Inherited Extract(Pointer(Item)));
  756. end;
  757. Function TClassList.First: TClass;
  758. begin
  759. Result:=TClass(Inherited First);
  760. end;
  761. Function TClassList.GetItems(Index: Integer): TClass;
  762. begin
  763. Result:=TClass(Inherited Items[Index]);
  764. end;
  765. Function TClassList.IndexOf(AClass: TClass): Integer;
  766. begin
  767. Result:=Inherited IndexOf(Pointer(AClass));
  768. end;
  769. Procedure TClassList.Insert(Index: Integer; AClass: TClass);
  770. begin
  771. Inherited Insert(index,Pointer(AClass));
  772. end;
  773. Function TClassList.Last: TClass;
  774. begin
  775. Result:=TClass(Inherited Last);
  776. end;
  777. Function TClassList.Remove(AClass: TClass): Integer;
  778. begin
  779. Result:=Inherited Remove(Pointer(AClass));
  780. end;
  781. Procedure TClassList.SetItems(Index: Integer; AClass: TClass);
  782. begin
  783. Put(Index,Pointer(Aclass));
  784. end;
  785. { TOrderedList }
  786. Function TOrderedList.AtLeast(ACount: Integer): Boolean;
  787. begin
  788. Result:=(FList.Count>=Acount)
  789. end;
  790. Function TOrderedList.Count: Integer;
  791. begin
  792. Result:=FList.Count;
  793. end;
  794. constructor TOrderedList.Create;
  795. begin
  796. FList:=Tlist.Create;
  797. end;
  798. destructor TOrderedList.Destroy;
  799. begin
  800. FList.Free;
  801. end;
  802. Function TOrderedList.Peek: Pointer;
  803. begin
  804. If AtLeast(1) then
  805. Result:=PeekItem
  806. else
  807. Result:=Nil;
  808. end;
  809. Function TOrderedList.PeekItem: Pointer;
  810. begin
  811. With Flist do
  812. Result:=Items[Count-1]
  813. end;
  814. Function TOrderedList.Pop: Pointer;
  815. begin
  816. If Atleast(1) then
  817. Result:=PopItem
  818. else
  819. Result:=Nil;
  820. end;
  821. Function TOrderedList.PopItem: Pointer;
  822. begin
  823. With FList do
  824. If Count>0 then
  825. begin
  826. Result:=Items[Count-1];
  827. Delete(Count-1);
  828. end
  829. else
  830. Result:=Nil;
  831. end;
  832. Function TOrderedList.Push(AItem: Pointer): Pointer;
  833. begin
  834. PushItem(Aitem);
  835. Result:=AItem;
  836. end;
  837. { TStack }
  838. Procedure TStack.PushItem(AItem: Pointer);
  839. begin
  840. FList.Add(Aitem);
  841. end;
  842. { TObjectStack }
  843. Function TObjectStack.Peek: TObject;
  844. begin
  845. Result:=TObject(Inherited Peek);
  846. end;
  847. Function TObjectStack.Pop: TObject;
  848. begin
  849. Result:=TObject(Inherited Pop);
  850. end;
  851. Function TObjectStack.Push(AObject: TObject): TObject;
  852. begin
  853. Result:=TObject(Inherited Push(Pointer(AObject)));
  854. end;
  855. { TQueue }
  856. Procedure TQueue.PushItem(AItem: Pointer);
  857. begin
  858. With Flist Do
  859. Insert(0,AItem);
  860. end;
  861. { TObjectQueue }
  862. Function TObjectQueue.Peek: TObject;
  863. begin
  864. Result:=TObject(Inherited Peek);
  865. end;
  866. Function TObjectQueue.Pop: TObject;
  867. begin
  868. Result:=TObject(Inherited Pop);
  869. end;
  870. Function TObjectQueue.Push(AObject: TObject): TObject;
  871. begin
  872. Result:=TObject(Inherited Push(Pointer(Aobject)));
  873. end;
  874. {*****************************************************************************
  875. TFPHashList
  876. *****************************************************************************}
  877. function FPHash1(const s:shortstring):LongWord;
  878. Var
  879. g : LongWord;
  880. p,pmax : pchar;
  881. begin
  882. result:=0;
  883. p:=@s[1];
  884. pmax:=@s[length(s)+1];
  885. while (p<pmax) do
  886. begin
  887. result:=result shl 4 + LongWord(p^);
  888. g:=result and LongWord($F0000000);
  889. if g<>0 then
  890. result:=result xor (g shr 24) xor g;
  891. inc(p);
  892. end;
  893. If result=0 then
  894. result:=$ffffffff;
  895. end;
  896. function FPHash(const s:shortstring):LongWord;
  897. Var
  898. p,pmax : pchar;
  899. begin
  900. {$ifopt Q+}
  901. {$define overflowon}
  902. {$Q-}
  903. {$endif}
  904. result:=0;
  905. p:=@s[1];
  906. pmax:=@s[length(s)+1];
  907. while (p<pmax) do
  908. begin
  909. result:=LongWord((result shl 5) - result) xor LongWord(P^);
  910. inc(p);
  911. end;
  912. {$ifdef overflowon}
  913. {$Q+}
  914. {$undef overflowon}
  915. {$endif}
  916. end;
  917. procedure TFPHashList.RaiseIndexError(Index : Integer);
  918. begin
  919. Error(SListIndexError, Index);
  920. end;
  921. function TFPHashList.Get(Index: Integer): Pointer;
  922. begin
  923. If (Index < 0) or (Index >= FCount) then
  924. RaiseIndexError(Index);
  925. Result:=FHashList^[Index].Data;
  926. end;
  927. procedure TFPHashList.Put(Index: Integer; Item: Pointer);
  928. begin
  929. if (Index < 0) or (Index >= FCount) then
  930. RaiseIndexError(Index);
  931. FHashList^[Index].Data:=Item;;
  932. end;
  933. function TFPHashList.NameOfIndex(Index: Integer): shortstring;
  934. begin
  935. If (Index < 0) or (Index >= FCount) then
  936. RaiseIndexError(Index);
  937. with FHashList^[Index] do
  938. begin
  939. if StrIndex>=0 then
  940. Result:=PShortString(@FStrs[StrIndex])^
  941. else
  942. Result:='';
  943. end;
  944. end;
  945. function TFPHashList.HashOfIndex(Index: Integer): LongWord;
  946. begin
  947. If (Index < 0) or (Index >= FCount) then
  948. RaiseIndexError(Index);
  949. Result:=FHashList^[Index].HashValue;
  950. end;
  951. function TFPHashList.Extract(item: Pointer): Pointer;
  952. var
  953. i : Integer;
  954. begin
  955. result := nil;
  956. i := IndexOf(item);
  957. if i >= 0 then
  958. begin
  959. Result := item;
  960. Delete(i);
  961. end;
  962. end;
  963. procedure TFPHashList.SetCapacity(NewCapacity: Integer);
  964. begin
  965. If (NewCapacity < FCount) or (NewCapacity > MaxHashListSize) then
  966. Error (SListCapacityError, NewCapacity);
  967. if NewCapacity = FCapacity then
  968. exit;
  969. ReallocMem(FHashList, NewCapacity*SizeOf(THashItem));
  970. FCapacity := NewCapacity;
  971. end;
  972. procedure TFPHashList.SetCount(NewCount: Integer);
  973. begin
  974. if (NewCount < 0) or (NewCount > MaxHashListSize)then
  975. Error(SListCountError, NewCount);
  976. If NewCount > FCount then
  977. begin
  978. If NewCount > FCapacity then
  979. SetCapacity(NewCount);
  980. If FCount < NewCount then
  981. FillChar(FHashList^[FCount], (NewCount-FCount) div Sizeof(THashItem), 0);
  982. end;
  983. FCount := Newcount;
  984. end;
  985. procedure TFPHashList.SetStrCapacity(NewCapacity: Integer);
  986. begin
  987. If (NewCapacity < FStrCount) or (NewCapacity > MaxHashStrSize) then
  988. Error (SListCapacityError, NewCapacity);
  989. if NewCapacity = FStrCapacity then
  990. exit;
  991. ReallocMem(FStrs, NewCapacity);
  992. FStrCapacity := NewCapacity;
  993. end;
  994. procedure TFPHashList.SetHashCapacity(NewCapacity: Integer);
  995. begin
  996. If (NewCapacity < 1) then
  997. Error (SListCapacityError, NewCapacity);
  998. if FHashCapacity=NewCapacity then
  999. exit;
  1000. FHashCapacity:=NewCapacity;
  1001. ReallocMem(FHashTable, FHashCapacity*sizeof(Integer));
  1002. ReHash;
  1003. end;
  1004. procedure TFPHashList.ReHash;
  1005. var
  1006. i : Integer;
  1007. begin
  1008. FillDword(FHashTable^,FHashCapacity,LongWord(-1));
  1009. For i:=0 To FCount-1 Do
  1010. AddToHashTable(i);
  1011. end;
  1012. constructor TFPHashList.Create;
  1013. begin
  1014. SetHashCapacity(1);
  1015. end;
  1016. destructor TFPHashList.Destroy;
  1017. begin
  1018. Clear;
  1019. if assigned(FHashTable) then
  1020. FreeMem(FHashTable);
  1021. inherited Destroy;
  1022. end;
  1023. function TFPHashList.AddStr(const s:shortstring): Integer;
  1024. var
  1025. Len : Integer;
  1026. begin
  1027. len:=length(s)+1;
  1028. if FStrCount+Len >= FStrCapacity then
  1029. StrExpand(Len);
  1030. System.Move(s[0],FStrs[FStrCount],Len);
  1031. result:=FStrCount;
  1032. inc(FStrCount,Len);
  1033. end;
  1034. procedure TFPHashList.AddToHashTable(Index: Integer);
  1035. var
  1036. HashIndex : Integer;
  1037. begin
  1038. with FHashList^[Index] do
  1039. begin
  1040. if not assigned(Data) then
  1041. exit;
  1042. HashIndex:=HashValue mod LongWord(FHashCapacity);
  1043. NextIndex:=FHashTable^[HashIndex];
  1044. FHashTable^[HashIndex]:=Index;
  1045. end;
  1046. end;
  1047. function TFPHashList.Add(const AName:shortstring;Item: Pointer): Integer;
  1048. begin
  1049. if FCount = FCapacity then
  1050. Expand;
  1051. with FHashList^[FCount] do
  1052. begin
  1053. HashValue:=FPHash(AName);
  1054. Data:=Item;
  1055. StrIndex:=AddStr(AName);
  1056. end;
  1057. AddToHashTable(FCount);
  1058. Result := FCount;
  1059. inc(FCount);
  1060. end;
  1061. procedure TFPHashList.Clear;
  1062. begin
  1063. if Assigned(FHashList) then
  1064. begin
  1065. FCount:=0;
  1066. SetCapacity(0);
  1067. FHashList := nil;
  1068. end;
  1069. SetHashCapacity(1);
  1070. if Assigned(FStrs) then
  1071. begin
  1072. FStrCount:=0;
  1073. SetStrCapacity(0);
  1074. FStrs := nil;
  1075. end;
  1076. end;
  1077. procedure TFPHashList.Delete(Index: Integer);
  1078. begin
  1079. If (Index<0) or (Index>=FCount) then
  1080. Error (SListIndexError, Index);
  1081. { Remove from HashList }
  1082. dec(FCount);
  1083. System.Move (FHashList^[Index+1], FHashList^[Index], (FCount - Index) * Sizeof(THashItem));
  1084. { All indexes are updated, we need to build the hashtable again }
  1085. Rehash;
  1086. { Shrink the list if appropriate }
  1087. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  1088. begin
  1089. FCapacity := FCapacity shr 1;
  1090. ReallocMem(FHashList, Sizeof(THashItem) * FCapacity);
  1091. end;
  1092. end;
  1093. function TFPHashList.Remove(Item: Pointer): Integer;
  1094. begin
  1095. Result := IndexOf(Item);
  1096. If Result <> -1 then
  1097. Self.Delete(Result);
  1098. end;
  1099. class procedure TFPHashList.Error(const Msg: string; Data: PtrInt);
  1100. begin
  1101. Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  1102. end;
  1103. function TFPHashList.Expand: TFPHashList;
  1104. var
  1105. IncSize : Longint;
  1106. begin
  1107. Result := Self;
  1108. if FCount < FCapacity then
  1109. exit;
  1110. IncSize := sizeof(ptrint)*2;
  1111. if FCapacity > 127 then
  1112. Inc(IncSize, FCapacity shr 2)
  1113. else if FCapacity > sizeof(ptrint)*3 then
  1114. Inc(IncSize, FCapacity shr 1)
  1115. else if FCapacity >= sizeof(ptrint) then
  1116. inc(IncSize,sizeof(ptrint));
  1117. SetCapacity(FCapacity + IncSize);
  1118. { Maybe expand hash also }
  1119. if FCount>FHashCapacity*MaxItemsPerHash then
  1120. SetHashCapacity(FCount div MaxItemsPerHash);
  1121. end;
  1122. procedure TFPHashList.StrExpand(MinIncSize:Integer);
  1123. var
  1124. IncSize : Longint;
  1125. begin
  1126. if FStrCount+MinIncSize < FStrCapacity then
  1127. exit;
  1128. IncSize := 64;
  1129. if FStrCapacity > 255 then
  1130. Inc(IncSize, FStrCapacity shr 2);
  1131. SetStrCapacity(FStrCapacity + IncSize + MinIncSize);
  1132. end;
  1133. function TFPHashList.IndexOf(Item: Pointer): Integer;
  1134. var
  1135. psrc : PHashItem;
  1136. Index : integer;
  1137. begin
  1138. Result:=-1;
  1139. psrc:=@FHashList^[0];
  1140. For Index:=0 To FCount-1 Do
  1141. begin
  1142. if psrc^.Data=Item then
  1143. begin
  1144. Result:=Index;
  1145. exit;
  1146. end;
  1147. inc(psrc);
  1148. end;
  1149. end;
  1150. function TFPHashList.InternalFind(AHash:LongWord;const AName:shortstring;out PrevIndex:Integer):Integer;
  1151. var
  1152. HashIndex : Integer;
  1153. Len,
  1154. LastChar : Char;
  1155. begin
  1156. HashIndex:=AHash mod LongWord(FHashCapacity);
  1157. Result:=FHashTable^[HashIndex];
  1158. Len:=Char(Length(AName));
  1159. LastChar:=AName[Byte(Len)];
  1160. PrevIndex:=-1;
  1161. while Result<>-1 do
  1162. begin
  1163. with FHashList^[Result] do
  1164. begin
  1165. if assigned(Data) and
  1166. (HashValue=AHash) and
  1167. (Len=FStrs[StrIndex]) and
  1168. (LastChar=FStrs[StrIndex+Byte(Len)]) and
  1169. (AName=PShortString(@FStrs[StrIndex])^) then
  1170. exit;
  1171. PrevIndex:=Result;
  1172. Result:=NextIndex;
  1173. end;
  1174. end;
  1175. end;
  1176. function TFPHashList.Find(const AName:shortstring): Pointer;
  1177. var
  1178. Index,
  1179. PrevIndex : Integer;
  1180. begin
  1181. Result:=nil;
  1182. Index:=InternalFind(FPHash(AName),AName,PrevIndex);
  1183. if Index=-1 then
  1184. exit;
  1185. Result:=FHashList^[Index].Data;
  1186. end;
  1187. function TFPHashList.FindIndexOf(const AName:shortstring): Integer;
  1188. var
  1189. PrevIndex : Integer;
  1190. begin
  1191. Result:=InternalFind(FPHash(AName),AName,PrevIndex);
  1192. end;
  1193. function TFPHashList.FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
  1194. var
  1195. Index,
  1196. PrevIndex : Integer;
  1197. begin
  1198. Result:=nil;
  1199. Index:=InternalFind(AHash,AName,PrevIndex);
  1200. if Index=-1 then
  1201. exit;
  1202. Result:=FHashList^[Index].Data;
  1203. end;
  1204. function TFPHashList.Rename(const AOldName,ANewName:shortstring): Integer;
  1205. var
  1206. PrevIndex,
  1207. Index : Integer;
  1208. OldHash : LongWord;
  1209. begin
  1210. Result:=-1;
  1211. OldHash:=FPHash(AOldName);
  1212. Index:=InternalFind(OldHash,AOldName,PrevIndex);
  1213. if Index=-1 then
  1214. exit;
  1215. { Remove from current Hash }
  1216. if PrevIndex<>-1 then
  1217. FHashList^[PrevIndex].NextIndex:=FHashList^[Index].NextIndex
  1218. else
  1219. FHashTable^[OldHash mod LongWord(FHashCapacity)]:=FHashList^[Index].NextIndex;
  1220. { Set new name and hash }
  1221. with FHashList^[Index] do
  1222. begin
  1223. HashValue:=FPHash(ANewName);
  1224. StrIndex:=AddStr(ANewName);
  1225. end;
  1226. { Insert back in Hash }
  1227. AddToHashTable(Index);
  1228. { Return Index }
  1229. Result:=Index;
  1230. end;
  1231. procedure TFPHashList.Pack;
  1232. var
  1233. NewCount,
  1234. i : integer;
  1235. pdest,
  1236. psrc : PHashItem;
  1237. begin
  1238. NewCount:=0;
  1239. psrc:=@FHashList^[0];
  1240. pdest:=psrc;
  1241. For I:=0 To FCount-1 Do
  1242. begin
  1243. if assigned(psrc^.Data) then
  1244. begin
  1245. pdest^:=psrc^;
  1246. inc(pdest);
  1247. inc(NewCount);
  1248. end;
  1249. inc(psrc);
  1250. end;
  1251. FCount:=NewCount;
  1252. { We need to ReHash to update the IndexNext }
  1253. ReHash;
  1254. { Release over-capacity }
  1255. SetCapacity(FCount);
  1256. SetStrCapacity(FStrCount);
  1257. end;
  1258. procedure TFPHashList.ShowStatistics;
  1259. var
  1260. HashMean,
  1261. HashStdDev : Double;
  1262. Index,
  1263. i,j : Integer;
  1264. begin
  1265. { Calculate Mean and StdDev }
  1266. HashMean:=0;
  1267. HashStdDev:=0;
  1268. for i:=0 to FHashCapacity-1 do
  1269. begin
  1270. j:=0;
  1271. Index:=FHashTable^[i];
  1272. while (Index<>-1) do
  1273. begin
  1274. inc(j);
  1275. Index:=FHashList^[Index].NextIndex;
  1276. end;
  1277. HashMean:=HashMean+j;
  1278. HashStdDev:=HashStdDev+Sqr(j);
  1279. end;
  1280. HashMean:=HashMean/FHashCapacity;
  1281. HashStdDev:=(HashStdDev-FHashCapacity*Sqr(HashMean));
  1282. If FHashCapacity>1 then
  1283. HashStdDev:=Sqrt(HashStdDev/(FHashCapacity-1))
  1284. else
  1285. HashStdDev:=0;
  1286. { Print info to stdout }
  1287. Writeln('HashSize : ',FHashCapacity);
  1288. Writeln('HashMean : ',HashMean:1:4);
  1289. Writeln('HashStdDev : ',HashStdDev:1:4);
  1290. Writeln('ListSize : ',FCount,'/',FCapacity);
  1291. Writeln('StringSize : ',FStrCount,'/',FStrCapacity);
  1292. end;
  1293. procedure TFPHashList.ForEachCall(proc2call:TListCallback;arg:pointer);
  1294. var
  1295. i : integer;
  1296. p : pointer;
  1297. begin
  1298. For I:=0 To Count-1 Do
  1299. begin
  1300. p:=FHashList^[i].Data;
  1301. if assigned(p) then
  1302. proc2call(p,arg);
  1303. end;
  1304. end;
  1305. procedure TFPHashList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  1306. var
  1307. i : integer;
  1308. p : pointer;
  1309. begin
  1310. For I:=0 To Count-1 Do
  1311. begin
  1312. p:=FHashList^[i].Data;
  1313. if assigned(p) then
  1314. proc2call(p,arg);
  1315. end;
  1316. end;
  1317. {*****************************************************************************
  1318. TFPHashObject
  1319. *****************************************************************************}
  1320. procedure TFPHashObject.InternalChangeOwner(HashObjectList:TFPHashObjectList;const s:shortstring);
  1321. var
  1322. Index : integer;
  1323. begin
  1324. FOwner:=HashObjectList;
  1325. Index:=HashObjectList.Add(s,Self);
  1326. FStrIndex:=HashObjectList.List.List^[Index].StrIndex;
  1327. FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
  1328. end;
  1329. constructor TFPHashObject.CreateNotOwned;
  1330. begin
  1331. FStrIndex:=-1;
  1332. end;
  1333. constructor TFPHashObject.Create(HashObjectList:TFPHashObjectList;const s:shortstring);
  1334. begin
  1335. InternalChangeOwner(HashObjectList,s);
  1336. end;
  1337. procedure TFPHashObject.ChangeOwner(HashObjectList:TFPHashObjectList);
  1338. begin
  1339. InternalChangeOwner(HashObjectList,PShortString(@FOwner.List.Strs[FStrIndex])^);
  1340. end;
  1341. procedure TFPHashObject.ChangeOwnerAndName(HashObjectList:TFPHashObjectList;const s:shortstring);
  1342. begin
  1343. InternalChangeOwner(HashObjectList,s);
  1344. end;
  1345. procedure TFPHashObject.Rename(const ANewName:shortstring);
  1346. var
  1347. Index : integer;
  1348. begin
  1349. Index:=FOwner.Rename(PShortString(@FOwner.List.Strs[FStrIndex])^,ANewName);
  1350. if Index<>-1 then
  1351. begin
  1352. FStrIndex:=FOwner.List.List^[Index].StrIndex;
  1353. FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
  1354. end;
  1355. end;
  1356. function TFPHashObject.GetName:shortstring;
  1357. begin
  1358. if FOwner<>nil then
  1359. begin
  1360. FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
  1361. Result:=FCachedStr^;
  1362. end
  1363. else
  1364. Result:='';
  1365. end;
  1366. function TFPHashObject.GetHash:Longword;
  1367. begin
  1368. if FOwner<>nil then
  1369. Result:=FPHash(PShortString(@FOwner.List.Strs[FStrIndex])^)
  1370. else
  1371. Result:=$ffffffff;
  1372. end;
  1373. {*****************************************************************************
  1374. TFPHashObjectList (Copied from rtl/objpas/classes/lists.inc)
  1375. *****************************************************************************}
  1376. constructor TFPHashObjectList.Create(FreeObjects : boolean = True);
  1377. begin
  1378. inherited Create;
  1379. FHashList := TFPHashList.Create;
  1380. FFreeObjects := Freeobjects;
  1381. end;
  1382. destructor TFPHashObjectList.Destroy;
  1383. begin
  1384. if (FHashList <> nil) then
  1385. begin
  1386. Clear;
  1387. FHashList.Destroy;
  1388. end;
  1389. inherited Destroy;
  1390. end;
  1391. procedure TFPHashObjectList.Clear;
  1392. var
  1393. i: integer;
  1394. begin
  1395. if FFreeObjects then
  1396. for i := 0 to FHashList.Count - 1 do
  1397. TObject(FHashList[i]).Free;
  1398. FHashList.Clear;
  1399. end;
  1400. function TFPHashObjectList.GetCount: integer;
  1401. begin
  1402. Result := FHashList.Count;
  1403. end;
  1404. procedure TFPHashObjectList.SetCount(const AValue: integer);
  1405. begin
  1406. if FHashList.Count <> AValue then
  1407. FHashList.Count := AValue;
  1408. end;
  1409. function TFPHashObjectList.GetItem(Index: Integer): TObject;
  1410. begin
  1411. Result := TObject(FHashList[Index]);
  1412. end;
  1413. procedure TFPHashObjectList.SetItem(Index: Integer; AObject: TObject);
  1414. begin
  1415. if OwnsObjects then
  1416. TObject(FHashList[Index]).Free;
  1417. FHashList[index] := AObject;
  1418. end;
  1419. procedure TFPHashObjectList.SetCapacity(NewCapacity: Integer);
  1420. begin
  1421. FHashList.Capacity := NewCapacity;
  1422. end;
  1423. function TFPHashObjectList.GetCapacity: integer;
  1424. begin
  1425. Result := FHashList.Capacity;
  1426. end;
  1427. function TFPHashObjectList.Add(const AName:shortstring;AObject: TObject): Integer;
  1428. begin
  1429. Result := FHashList.Add(AName,AObject);
  1430. end;
  1431. function TFPHashObjectList.NameOfIndex(Index: Integer): shortstring;
  1432. begin
  1433. Result := FHashList.NameOfIndex(Index);
  1434. end;
  1435. function TFPHashObjectList.HashOfIndex(Index: Integer): LongWord;
  1436. begin
  1437. Result := FHashList.HashOfIndex(Index);
  1438. end;
  1439. procedure TFPHashObjectList.Delete(Index: Integer);
  1440. begin
  1441. if OwnsObjects then
  1442. TObject(FHashList[Index]).Free;
  1443. FHashList.Delete(Index);
  1444. end;
  1445. function TFPHashObjectList.Expand: TFPHashObjectList;
  1446. begin
  1447. FHashList.Expand;
  1448. Result := Self;
  1449. end;
  1450. function TFPHashObjectList.Extract(Item: TObject): TObject;
  1451. begin
  1452. Result := TObject(FHashList.Extract(Item));
  1453. end;
  1454. function TFPHashObjectList.Remove(AObject: TObject): Integer;
  1455. begin
  1456. Result := IndexOf(AObject);
  1457. if (Result <> -1) then
  1458. begin
  1459. if OwnsObjects then
  1460. TObject(FHashList[Result]).Free;
  1461. FHashList.Delete(Result);
  1462. end;
  1463. end;
  1464. function TFPHashObjectList.IndexOf(AObject: TObject): Integer;
  1465. begin
  1466. Result := FHashList.IndexOf(Pointer(AObject));
  1467. end;
  1468. function TFPHashObjectList.Find(const s:shortstring): TObject;
  1469. begin
  1470. result:=TObject(FHashList.Find(s));
  1471. end;
  1472. function TFPHashObjectList.FindIndexOf(const s:shortstring): Integer;
  1473. begin
  1474. result:=FHashList.FindIndexOf(s);
  1475. end;
  1476. function TFPHashObjectList.FindWithHash(const AName:shortstring;AHash:LongWord): Pointer;
  1477. begin
  1478. Result:=TObject(FHashList.FindWithHash(AName,AHash));
  1479. end;
  1480. function TFPHashObjectList.Rename(const AOldName,ANewName:shortstring): Integer;
  1481. begin
  1482. Result:=FHashList.Rename(AOldName,ANewName);
  1483. end;
  1484. function TFPHashObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
  1485. var
  1486. I : Integer;
  1487. begin
  1488. I:=AStartAt;
  1489. Result:=-1;
  1490. If AExact then
  1491. while (I<Count) and (Result=-1) do
  1492. If Items[i].ClassType=AClass then
  1493. Result:=I
  1494. else
  1495. Inc(I)
  1496. else
  1497. while (I<Count) and (Result=-1) do
  1498. If Items[i].InheritsFrom(AClass) then
  1499. Result:=I
  1500. else
  1501. Inc(I);
  1502. end;
  1503. procedure TFPHashObjectList.Pack;
  1504. begin
  1505. FHashList.Pack;
  1506. end;
  1507. procedure TFPHashObjectList.ShowStatistics;
  1508. begin
  1509. FHashList.ShowStatistics;
  1510. end;
  1511. procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  1512. begin
  1513. FHashList.ForEachCall(TListCallBack(proc2call),arg);
  1514. end;
  1515. procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  1516. begin
  1517. FHashList.ForEachCall(TListStaticCallBack(proc2call),arg);
  1518. end;
  1519. { ---------------------------------------------------------------------
  1520. Hash support, by Dean Zobec
  1521. ---------------------------------------------------------------------}
  1522. { Default hash function }
  1523. function RSHash(const S: string; const TableSize: Longword): Longword;
  1524. const
  1525. b = 378551;
  1526. var
  1527. a: Longword;
  1528. i: Longword;
  1529. begin
  1530. a := 63689;
  1531. Result := 0;
  1532. if length(s)>0 then
  1533. for i := 1 to Length(S) do
  1534. begin
  1535. Result := Result * a + Ord(S[i]);
  1536. a := a * b;
  1537. end;
  1538. Result := (Result and $7FFFFFFF) mod TableSize;
  1539. end;
  1540. { THTNode }
  1541. constructor THTCustomNode.CreateWith(const AString: string);
  1542. begin
  1543. inherited Create;
  1544. FKey := AString;
  1545. end;
  1546. function THTCustomNode.HasKey(const AKey: string): boolean;
  1547. begin
  1548. if Length(AKey) <> Length(FKey) then
  1549. begin
  1550. Result := false;
  1551. exit;
  1552. end
  1553. else
  1554. Result := CompareMem(PChar(FKey), PChar(AKey), length(AKey));
  1555. end;
  1556. { TFPCustomHashTable }
  1557. constructor TFPCustomHashTable.Create;
  1558. begin
  1559. CreateWith(196613,@RSHash);
  1560. end;
  1561. constructor TFPCustomHashTable.CreateWith(AHashTableSize: Longword;
  1562. aHashFunc: THashFunction);
  1563. begin
  1564. Inherited Create;
  1565. FHashTable := TFPObjectList.Create(True);
  1566. HashTableSize := AHashTableSize;
  1567. FHashFunction := aHashFunc;
  1568. end;
  1569. destructor TFPCustomHashTable.Destroy;
  1570. begin
  1571. FHashTable.Free;
  1572. inherited Destroy;
  1573. end;
  1574. function TFPCustomHashTable.GetDensity: Longword;
  1575. begin
  1576. Result := FHashTableSize - VoidSlots
  1577. end;
  1578. function TFPCustomHashTable.GetNumberOfCollisions: Longword;
  1579. begin
  1580. Result := FCount -(FHashTableSize - VoidSlots)
  1581. end;
  1582. procedure TFPCustomHashTable.SetHashTableSize(const Value: Longword);
  1583. var
  1584. i: Longword;
  1585. newSize: Longword;
  1586. begin
  1587. if Value <> FHashTableSize then
  1588. begin
  1589. i := 0;
  1590. while (PRIMELIST[i] < Value) and (i < 27) do
  1591. inc(i);
  1592. newSize := PRIMELIST[i];
  1593. if Count = 0 then
  1594. begin
  1595. FHashTableSize := newSize;
  1596. InitializeHashTable;
  1597. end
  1598. else
  1599. ChangeTableSize(newSize);
  1600. end;
  1601. end;
  1602. procedure TFPCustomHashTable.InitializeHashTable;
  1603. var
  1604. i: LongWord;
  1605. begin
  1606. if FHashTableSize>0 Then
  1607. for i := 0 to FHashTableSize-1 do
  1608. FHashTable.Add(nil);
  1609. FCount := 0;
  1610. end;
  1611. procedure TFPCustomHashTable.ChangeTableSize(const ANewSize: Longword);
  1612. var
  1613. SavedTable: TFPObjectList;
  1614. SavedTableSize: Longword;
  1615. i, j: Longword;
  1616. temp: THTCustomNode;
  1617. begin
  1618. SavedTable := FHashTable;
  1619. SavedTableSize := FHashTableSize;
  1620. FHashTableSize := ANewSize;
  1621. FHashTable := TFPObjectList.Create(True);
  1622. InitializeHashTable;
  1623. If SavedTableSize>0 Then
  1624. for i := 0 to SavedTableSize-1 do
  1625. begin
  1626. if Assigned(SavedTable[i]) then
  1627. for j := 0 to TFPObjectList(SavedTable[i]).Count -1 do
  1628. begin
  1629. temp := THTCustomNode(TFPObjectList(SavedTable[i])[j]);
  1630. AddNode(temp);
  1631. end;
  1632. end;
  1633. SavedTable.Free;
  1634. end;
  1635. procedure TFPCustomHashTable.SetHashFunction(AHashFunction: THashFunction);
  1636. begin
  1637. if IsEmpty then
  1638. FHashFunction := AHashFunction
  1639. else
  1640. raise Exception.Create(NotEmptyMsg);
  1641. end;
  1642. function TFPCustomHashTable.Find(const aKey: string): THTCustomNode;
  1643. var
  1644. hashCode: Longword;
  1645. chn: TFPObjectList;
  1646. i: Longword;
  1647. begin
  1648. hashCode := FHashFunction(aKey, FHashTableSize);
  1649. chn := Chain(hashCode);
  1650. if Assigned(chn) then
  1651. begin
  1652. if chn.count>0 then
  1653. for i := 0 to chn.Count - 1 do
  1654. if THTCustomNode(chn[i]).HasKey(aKey) then
  1655. begin
  1656. result := THTCustomNode(chn[i]);
  1657. exit;
  1658. end;
  1659. end;
  1660. Result := nil;
  1661. end;
  1662. Function TFPCustomHashTable.FindChainForAdd(Const aKey : String) : TFPObjectList;
  1663. var
  1664. hashCode: Longword;
  1665. i: Longword;
  1666. begin
  1667. hashCode := FHashFunction(aKey, FHashTableSize);
  1668. Result := Chain(hashCode);
  1669. if Assigned(Result) then
  1670. begin
  1671. if Result.count>0 then
  1672. for i := 0 to Result.Count - 1 do
  1673. if THTCustomNode(Result[i]).HasKey(aKey) then
  1674. Raise EDuplicate.CreateFmt(DuplicateMsg, [aKey]);
  1675. end
  1676. else
  1677. begin
  1678. FHashTable[hashcode] := TFPObjectList.Create(true);
  1679. Result := Chain(hashcode);
  1680. end;
  1681. inc(FCount);
  1682. end;
  1683. procedure TFPCustomHashTable.Delete(const aKey: string);
  1684. var
  1685. hashCode: Longword;
  1686. chn: TFPObjectList;
  1687. i: Longword;
  1688. begin
  1689. hashCode := FHashFunction(aKey, FHashTableSize);
  1690. chn := Chain(hashCode);
  1691. if Assigned(chn) then
  1692. begin
  1693. if chn.count>0 then
  1694. for i := 0 to chn.Count - 1 do
  1695. if THTCustomNode(chn[i]).HasKey(aKey) then
  1696. begin
  1697. chn.Delete(i);
  1698. dec(FCount);
  1699. exit;
  1700. end;
  1701. end;
  1702. raise EKeyNotFound.CreateFmt(KeyNotFoundMsg, ['Delete', aKey]);
  1703. end;
  1704. function TFPCustomHashTable.IsEmpty: boolean;
  1705. begin
  1706. Result := (FCount = 0);
  1707. end;
  1708. function TFPCustomHashTable.Chain(const index: Longword): TFPObjectList;
  1709. begin
  1710. Result := TFPObjectList(FHashTable[index]);
  1711. end;
  1712. function TFPCustomHashTable.GetVoidSlots: Longword;
  1713. var
  1714. i: Longword;
  1715. num: Longword;
  1716. begin
  1717. num := 0;
  1718. if FHashTableSize>0 Then
  1719. for i:= 0 to FHashTableSize-1 do
  1720. if Not Assigned(Chain(i)) then
  1721. inc(num);
  1722. result := num;
  1723. end;
  1724. function TFPCustomHashTable.GetLoadFactor: double;
  1725. begin
  1726. Result := Count / FHashTableSize;
  1727. end;
  1728. function TFPCustomHashTable.GetAVGChainLen: double;
  1729. begin
  1730. result := Count / (FHashTableSize - VoidSlots);
  1731. end;
  1732. function TFPCustomHashTable.GetMaxChainLength: Longword;
  1733. var
  1734. i: Longword;
  1735. begin
  1736. Result := 0;
  1737. if FHashTableSize>0 Then
  1738. for i := 0 to FHashTableSize-1 do
  1739. if ChainLength(i) > Result then
  1740. Result := ChainLength(i);
  1741. end;
  1742. function TFPCustomHashTable.FindOrCreateNew(const aKey: string): THTCustomNode;
  1743. var
  1744. hashCode: Longword;
  1745. chn: TFPObjectList;
  1746. i: Longword;
  1747. begin
  1748. hashCode := FHashFunction(aKey, FHashTableSize);
  1749. chn := Chain(hashCode);
  1750. if Assigned(chn) then
  1751. begin
  1752. if chn.count>0 then
  1753. for i := 0 to chn.Count - 1 do
  1754. if THTCustomNode(chn[i]).HasKey(aKey) then
  1755. begin
  1756. Result := THTNode(chn[i]);
  1757. exit;
  1758. end
  1759. end
  1760. else
  1761. begin
  1762. FHashTable[hashcode] := TFPObjectList.Create(true);
  1763. chn := Chain(hashcode);
  1764. end;
  1765. inc(FCount);
  1766. Result := CreateNewNode(aKey);
  1767. chn.Add(Result);
  1768. end;
  1769. function TFPCustomHashTable.ChainLength(const ChainIndex: Longword): Longword;
  1770. begin
  1771. if Assigned(Chain(ChainIndex)) then
  1772. Result := Chain(ChainIndex).Count
  1773. else
  1774. Result := 0;
  1775. end;
  1776. procedure TFPCustomHashTable.Clear;
  1777. var
  1778. i: Longword;
  1779. begin
  1780. if FHashTableSize>0 Then
  1781. for i := 0 to FHashTableSize - 1 do
  1782. begin
  1783. if Assigned(Chain(i)) then
  1784. Chain(i).Clear;
  1785. end;
  1786. FCount := 0;
  1787. end;
  1788. { TFPDataHashTable }
  1789. procedure TFPDataHashTable.Add(const aKey: string; aItem: pointer);
  1790. var
  1791. chn: TFPObjectList;
  1792. NewNode: THtDataNode;
  1793. begin
  1794. chn:=FindChainForAdd(akey);
  1795. NewNode := THtDataNode(CreateNewNode(aKey));
  1796. NewNode.Data := aItem;
  1797. chn.Add(NewNode);
  1798. end;
  1799. function TFPDataHashTable.GetData(const Index: string): Pointer;
  1800. var
  1801. node: THTDataNode;
  1802. begin
  1803. node := THTDataNode(Find(Index));
  1804. if Assigned(node) then
  1805. Result := node.Data
  1806. else
  1807. Result := nil;
  1808. end;
  1809. procedure TFPDataHashTable.SetData(const index: string; const AValue: Pointer);
  1810. begin
  1811. THTDataNode(FindOrCreateNew(index)).Data := AValue;
  1812. end;
  1813. Function TFPDataHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
  1814. begin
  1815. Result:=THTDataNode.CreateWith(aKey);
  1816. end;
  1817. function TFPDataHashTable.ForEachCall(aMethod: TDataIteratorMethod): THTDataNode;
  1818. var
  1819. i, j: Longword;
  1820. continue: boolean;
  1821. begin
  1822. Result := nil;
  1823. continue := true;
  1824. if FHashTableSize>0 then
  1825. for i := 0 to FHashTableSize-1 do
  1826. begin
  1827. if assigned(Chain(i)) then
  1828. begin
  1829. if chain(i).count>0 then
  1830. for j := 0 to Chain(i).Count-1 do
  1831. begin
  1832. aMethod(THTDataNode(Chain(i)[j]).Data, THTDataNode(Chain(i)[j]).Key, continue);
  1833. if not continue then
  1834. begin
  1835. Result := THTDataNode(Chain(i)[j]);
  1836. Exit;
  1837. end;
  1838. end;
  1839. end;
  1840. end;
  1841. end;
  1842. Procedure TFPDataHashTable.AddNode(ANode : THTCustomNode);
  1843. begin
  1844. With THTDataNode(ANode) do
  1845. Add(Key,Data);
  1846. end;
  1847. { TFPStringHashTable }
  1848. Procedure TFPStringHashTable.AddNode(ANode : THTCustomNode);
  1849. begin
  1850. With THTStringNode(ANode) do
  1851. Add(Key,Data);
  1852. end;
  1853. function TFPStringHashTable.GetData(const Index: string): String;
  1854. var
  1855. node: THTStringNode;
  1856. begin
  1857. node := THTStringNode(Find(Index));
  1858. if Assigned(node) then
  1859. Result := node.Data
  1860. else
  1861. Result := '';
  1862. end;
  1863. procedure TFPStringHashTable.SetData(const index, AValue: string);
  1864. begin
  1865. THTStringNode(FindOrCreateNew(index)).Data := AValue;
  1866. end;
  1867. procedure TFPStringHashTable.Add(const aKey, aItem: string);
  1868. var
  1869. chn: TFPObjectList;
  1870. NewNode: THtStringNode;
  1871. begin
  1872. chn:=FindChainForAdd(akey);
  1873. NewNode := THtStringNode(CreateNewNode(aKey));
  1874. NewNode.Data := aItem;
  1875. chn.Add(NewNode);
  1876. end;
  1877. Function TFPStringHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
  1878. begin
  1879. Result:=THTStringNode.CreateWith(aKey);
  1880. end;
  1881. function TFPStringHashTable.ForEachCall(aMethod: TStringIteratorMethod): THTStringNode;
  1882. var
  1883. i, j: Longword;
  1884. continue: boolean;
  1885. begin
  1886. Result := nil;
  1887. continue := true;
  1888. if FHashTableSize>0 then
  1889. for i := 0 to FHashTableSize-1 do
  1890. begin
  1891. if assigned(Chain(i)) then
  1892. begin
  1893. if chain(i).count>0 then
  1894. for j := 0 to Chain(i).Count-1 do
  1895. begin
  1896. aMethod(THTStringNode(Chain(i)[j]).Data, THTStringNode(Chain(i)[j]).Key, continue);
  1897. if not continue then
  1898. begin
  1899. Result := THTStringNode(Chain(i)[j]);
  1900. Exit;
  1901. end;
  1902. end;
  1903. end;
  1904. end;
  1905. end;
  1906. { TFPObjectHashTable }
  1907. Procedure TFPObjectHashTable.AddNode(ANode : THTCustomNode);
  1908. begin
  1909. With THTObjectNode(ANode) do
  1910. Add(Key,Data);
  1911. end;
  1912. function TFPObjectHashTable.GetData(const Index: string): TObject;
  1913. var
  1914. node: THTObjectNode;
  1915. begin
  1916. node := THTObjectNode(Find(Index));
  1917. if Assigned(node) then
  1918. Result := node.Data
  1919. else
  1920. Result := Nil;
  1921. end;
  1922. procedure TFPObjectHashTable.SetData(const index : string; AObject : TObject);
  1923. begin
  1924. THTObjectNode(FindOrCreateNew(index)).Data := AObject;
  1925. end;
  1926. procedure TFPObjectHashTable.Add(const aKey: string; AItem : TObject);
  1927. var
  1928. chn: TFPObjectList;
  1929. NewNode: THTObjectNode;
  1930. begin
  1931. chn:=FindChainForAdd(akey);
  1932. NewNode := THTObjectNode(CreateNewNode(aKey));
  1933. NewNode.Data := aItem;
  1934. chn.Add(NewNode);
  1935. end;
  1936. Function TFPObjectHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
  1937. begin
  1938. If OwnsObjects then
  1939. Result:=THTOwnedObjectNode.CreateWith(aKey)
  1940. else
  1941. Result:=THTObjectNode.CreateWith(aKey);
  1942. end;
  1943. function TFPObjectHashTable.ForEachCall(aMethod: TObjectIteratorMethod): THTObjectNode;
  1944. var
  1945. i, j: Longword;
  1946. continue: boolean;
  1947. begin
  1948. Result := nil;
  1949. continue := true;
  1950. if FHashTableSize>0 then
  1951. for i := 0 to FHashTableSize-1 do
  1952. begin
  1953. if assigned(Chain(i)) then
  1954. begin
  1955. if chain(i).count>0 then
  1956. for j := 0 to Chain(i).Count-1 do
  1957. begin
  1958. aMethod(THTObjectNode(Chain(i)[j]).Data, THTObjectNode(Chain(i)[j]).Key, continue);
  1959. if not continue then
  1960. begin
  1961. Result := THTObjectNode(Chain(i)[j]);
  1962. Exit;
  1963. end;
  1964. end;
  1965. end;
  1966. end;
  1967. end;
  1968. constructor TFPObjectHashTable.Create(AOwnsObjects : Boolean = True);
  1969. begin
  1970. Inherited Create;
  1971. FOwnsObjects:=AOwnsObjects;
  1972. end;
  1973. constructor TFPObjectHashTable.CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction; AOwnsObjects : Boolean = True);
  1974. begin
  1975. Inherited CreateWith(AHashTableSize,AHashFunc);
  1976. FOwnsObjects:=AOwnsObjects;
  1977. end;
  1978. Destructor THTOwnedObjectNode.Destroy;
  1979. begin
  1980. FreeAndNil(FData);
  1981. Inherited;
  1982. end;
  1983. end.