cclasses.pas 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
  3. This module provides some basic classes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  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. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cclasses;
  18. {$i fpcdefs.inc}
  19. {$define CCLASSESINLINE}
  20. interface
  21. uses
  22. {$IFNDEF USE_FAKE_SYSUTILS}
  23. SysUtils,
  24. {$ELSE}
  25. fksysutl,
  26. {$ENDIF}
  27. globtype,
  28. CUtils,CStreams;
  29. {********************************************
  30. TMemDebug
  31. ********************************************}
  32. type
  33. tmemdebug = class
  34. private
  35. totalmem,
  36. startmem : int64;
  37. infostr : string[40];
  38. public
  39. constructor Create(const s:string);
  40. destructor Destroy;override;
  41. procedure show;
  42. procedure start;
  43. procedure stop;
  44. end;
  45. {*******************************************************
  46. TFPList (From rtl/objpas/classes/classesh.inc)
  47. ********************************************************}
  48. const
  49. SListIndexError = 'List index exceeds bounds (%d)';
  50. SListCapacityError = 'The maximum list capacity is reached (%d)';
  51. SListCapacityPower2Error = 'The capacity has to be a power of 2, but is set to %d';
  52. SListCountError = 'List count too large (%d)';
  53. type
  54. EListError = class(Exception);
  55. const
  56. MaxListSize = Maxint div 16;
  57. type
  58. TListSortCompare = function (Item1, Item2: Pointer): Integer;
  59. TListCallback = procedure(data,arg:pointer) of object;
  60. TListStaticCallback = procedure(data,arg:pointer);
  61. TDynStringArray = Array Of String;
  62. TDirection = (FromBeginning,FromEnd);
  63. TFPList = class(TObject)
  64. private
  65. FList: PPointer;
  66. FCount: Integer;
  67. FCapacity: Integer;
  68. protected
  69. function Get(Index: Integer): Pointer;
  70. procedure Put(Index: Integer; Item: Pointer);
  71. procedure SetCapacity(NewCapacity: Integer);
  72. procedure SetCount(NewCount: Integer);
  73. Procedure RaiseIndexError(Index : Integer);
  74. property List: PPointer read FList;
  75. public
  76. destructor Destroy; override;
  77. function Add(Item: Pointer): Integer;
  78. procedure Clear;
  79. procedure Delete(Index: Integer);
  80. class procedure Error(const Msg: string; Data: PtrInt);
  81. procedure Exchange(Index1, Index2: Integer);
  82. function Expand: TFPList;
  83. function Extract(item: Pointer): Pointer;
  84. function First: Pointer;
  85. function IndexOf(Item: Pointer): Integer;
  86. function IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
  87. procedure Insert(Index: Integer; Item: Pointer);
  88. function Last: Pointer;
  89. procedure Move(CurIndex, NewIndex: Integer);
  90. procedure Assign(Obj:TFPList);
  91. function Remove(Item: Pointer): Integer;
  92. procedure Pack;
  93. procedure Sort(Compare: TListSortCompare);
  94. procedure ForEachCall(proc2call:TListCallback;arg:pointer);
  95. procedure ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  96. property Capacity: Integer read FCapacity write SetCapacity;
  97. property Count: Integer read FCount write SetCount;
  98. property Items[Index: Integer]: Pointer read Get write Put; default;
  99. { Add to list, creating it if required. }
  100. class procedure AddOnDemand(var Lst: TFPList; Item: Pointer); static;
  101. { FreeAndNil the list, and its items as TObjects. }
  102. class procedure FreeAndNilObjects(var Lst: TFPList); static;
  103. { FreeAndNil the list, and dispose() its items. 'ItemType' is TypeInfo() of items. }
  104. class procedure FreeAndNilDisposing(var Lst: TFPList; ItemType: Pointer); static;
  105. end;
  106. {*******************************************************
  107. TFPObjectList (From fcl/inc/contnrs.pp)
  108. ********************************************************}
  109. TObjectListCallback = procedure(data:TObject;arg:pointer) of object;
  110. TObjectListStaticCallback = procedure(data:TObject;arg:pointer);
  111. TFPObjectList = class(TObject)
  112. private
  113. FFreeObjects : Boolean;
  114. FList: TFPList;
  115. function GetCount: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  116. procedure SetCount(const AValue: integer);
  117. protected
  118. function GetItem(Index: Integer): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  119. procedure SetItem(Index: Integer; AObject: TObject);
  120. procedure SetCapacity(NewCapacity: Integer); {$ifdef CCLASSESINLINE}inline;{$endif}
  121. function GetCapacity: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  122. public
  123. constructor Create;
  124. constructor Create(FreeObjects : Boolean);
  125. destructor Destroy; override;
  126. procedure Clear;
  127. function Add(AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  128. procedure Delete(Index: Integer);
  129. procedure Exchange(Index1, Index2: Integer); {$ifdef CCLASSESINLINE}inline;{$endif}
  130. function Expand: TFPObjectList;{$ifdef CCLASSESINLINE}inline;{$endif}
  131. function Extract(Item: TObject): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  132. function Remove(AObject: TObject): Integer;
  133. function IndexOf(AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  134. function IndexOfItem(AObject: TObject; Direction: TDirection): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  135. function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
  136. procedure Insert(Index: Integer; AObject: TObject); {$ifdef CCLASSESINLINE}inline;{$endif}
  137. function First: TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  138. function Last: TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  139. procedure Move(CurIndex, NewIndex: Integer); {$ifdef CCLASSESINLINE}inline;{$endif}
  140. procedure Assign(Obj:TFPObjectList);
  141. procedure ConcatListCopy(Obj:TFPObjectList);
  142. procedure Pack; {$ifdef CCLASSESINLINE}inline;{$endif}
  143. procedure Sort(Compare: TListSortCompare); {$ifdef CCLASSESINLINE}inline;{$endif}
  144. procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
  145. procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
  146. property Capacity: Integer read GetCapacity write SetCapacity;
  147. property Count: Integer read GetCount write SetCount;
  148. property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
  149. property Items[Index: Integer]: TObject read GetItem write SetItem; default;
  150. property List: TFPList read FList;
  151. end;
  152. { Memory region that allocates chunks with .Push and frees them all at once with .Done, useful for storing shortstrings.
  153. Alignment of the sizes is the user's responsibility, but shortstrings are composed of bytes and unaffected,
  154. and, in general, objects of the same nature will have same alignment and be sized as its multiple,
  155. not to mention using such a region exclusively for arrays of the same type, for example. }
  156. PMemoryRegionNode = ^TMemoryRegionNode;
  157. TMemoryRegionNode = record
  158. n, alloc: uint32;
  159. next: PMemoryRegionNode;
  160. data: array[0 .. 0] of byte; { variable-sized; and aligned to pointer. }
  161. end;
  162. const
  163. MinMemoryRegionNodeSize=64;
  164. type
  165. TMemoryRegion = object
  166. procedure Init(preallocate: SizeUint=0);
  167. procedure Done; {$ifdef CCLASSESINLINE}inline;{$endif}
  168. function Push(n: SizeUint): pointer;
  169. procedure Clear;
  170. function CalcSumSize: SizeUint; { don't want to store it as its retrieval is logarithmic. }
  171. private
  172. FTop: PMemoryRegionNode;
  173. class function AllocateNode(n, alloc: SizeUint): PMemoryRegionNode; static;
  174. function PushNewNode(n: SizeUint): pointer;
  175. end;
  176. { "Vi" stands for variable-sized indices.
  177. Variable-sized indices use less space and reduce the size of a region with potentially chaotic accesses (FHash).
  178. Indices are bitpacked. For speed and simplicity, bitfield base type is the same as index type (SizeUint),
  179. and maximum bit size is bitsizeof(SizeUint) - 1, to allow unconditional masking with "1 shl bitsPerIndex - 1", etc. }
  180. function ViGet(data: PSizeUint; index, bitsPerIndex: SizeUint): SizeUint;
  181. procedure ViSet(data: PSizeUint; index, bitsPerIndex, value: SizeUint);
  182. function ViDataSize(n, bitsPerIndex: SizeUint): SizeUint;
  183. const
  184. ViEmpty = 0;
  185. ViRealIndexOffset = 1;
  186. type
  187. PViHashListItem = ^TViHashListItem;
  188. TViHashListItem = record
  189. HashValue: uint32;
  190. Next: int32;
  191. Str: {$ifdef symansistr} TSymStr {$else} PSymStr {$endif};
  192. Data: Pointer;
  193. end;
  194. TViRehashMode = (vi_Auto, vi_Tight, vi_Pack);
  195. TViHashList = class(TObject)
  196. private
  197. { When not special "empty list", that is, when Assigned(FItems), FHash is a memory region containing FHash + FItems. }
  198. FHash: PSizeUint; { Bitpacked hash table. ViEmpty means empty cell, ViRealIndexOffset+i references FItems[i]. }
  199. FItems: PViHashListItem;
  200. FBitsPerIndex: uint8; { Size of indices in FHash. }
  201. FHashMask: uint32; { Count of indices in FHash is always "FHashMask + 1" and is always a power of two. }
  202. FCount: int32;
  203. FCapacity: uint32; { Allocation size of FItems. Generally speaking, can be arbitrary, without any relation to "FHashMask + 1". }
  204. {$ifndef symansistr}
  205. FShortstringRegion: TMemoryRegion;
  206. {$endif}
  207. function Get(Index: SizeInt): Pointer;
  208. procedure Put(Index: SizeInt; Item: Pointer);
  209. class procedure RaiseIndexError(Index: SizeInt); static;
  210. procedure SetupEmptyTable;
  211. procedure Rehash(ForItems: SizeUint; mode: TViRehashMode=vi_Auto);
  212. {$ifndef symansistr}
  213. function AddStrToRegion(const s: TSymStr): PSymStr;
  214. {$endif}
  215. procedure Shrink;
  216. procedure AddToHashTable(Item: PViHashListItem; Index: SizeUint);
  217. function InternalFind(AHash:LongWord;const AName:TSymStr;out PrevIndex:SizeInt):SizeInt;
  218. procedure RemoveFromHashTable(AHash:LongWord;Index, PrevIndex: SizeInt);
  219. procedure SetCapacity(NewCapacity: uint32);
  220. public
  221. constructor Create;
  222. destructor Destroy; override;
  223. function Add(const AName:TSymStr;Item: Pointer): SizeInt;
  224. procedure Clear;
  225. function NameOfIndex(Index: SizeInt): TSymStr;
  226. function HashOfIndex(Index: SizeInt): LongWord;
  227. function GetNextCollision(Index: SizeInt): SizeInt; {$ifdef CCLASSESINLINE}inline;{$endif}
  228. procedure Delete(Index: SizeInt);
  229. function Extract(item: Pointer): Pointer;
  230. function IndexOf(Item: Pointer): SizeInt;
  231. function Find(const AName:TSymStr): Pointer; {$ifdef CCLASSESINLINE}inline;{$endif}
  232. function FindIndexOf(const AName:TSymStr): SizeInt; {$ifdef CCLASSESINLINE}inline;{$endif}
  233. function FindWithHash(const AName:TSymStr;AHash:LongWord): Pointer;
  234. function Rename(const AOldName,ANewName:TSymStr): SizeInt;
  235. function Remove(Item: Pointer): SizeInt;
  236. procedure Pack;
  237. procedure ShowStatistics;
  238. procedure ForEachCall(proc2call:TListCallback;arg:pointer);
  239. procedure ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  240. property Count: int32 read FCount;
  241. property Capacity: uint32 read FCapacity write SetCapacity;
  242. property Items[Index: SizeInt]: Pointer read Get write Put; default;
  243. property List: PViHashListItem read FItems;
  244. end;
  245. TFPHashList=TViHashList;
  246. const
  247. MaxHashListSize = Maxint div 16;
  248. {*******************************************************
  249. TFPHashObjectList (From fcl/inc/contnrs.pp)
  250. ********************************************************}
  251. type
  252. TFPHashObjectList = class;
  253. { TFPHashObject }
  254. TFPHashObject = class
  255. private
  256. FOwner : TFPHashObjectList;
  257. FStr : {$ifdef symansistr} TSymStr {$else} PSymStr {$endif};
  258. FHash : LongWord;
  259. procedure InternalChangeOwner(HashObjectList:TFPHashObjectList;const s:TSymStr);
  260. protected
  261. function GetName:TSymStr;virtual;
  262. function GetHash:Longword;virtual;
  263. public
  264. constructor CreateNotOwned;
  265. constructor Create(HashObjectList:TFPHashObjectList;const s:TSymStr);
  266. procedure ChangeOwner(HashObjectList:TFPHashObjectList);
  267. procedure ChangeOwnerAndName(HashObjectList:TFPHashObjectList;const s:TSymStr); {$ifdef CCLASSESINLINE}inline;{$endif}
  268. procedure Rename(const ANewName:TSymStr);
  269. property Name:TSymStr read GetName;
  270. property Hash:Longword read GetHash;
  271. property OwnerList: TFPHashObjectList read FOwner;
  272. end;
  273. TFPHashObjectList = class(TObject)
  274. private
  275. FFreeObjects : Boolean;
  276. FHashList: TFPHashList;
  277. function GetCount: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  278. protected
  279. function GetItem(Index: Integer): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  280. procedure SetItem(Index: Integer; AObject: TObject);
  281. procedure SetCapacity(NewCapacity: Integer); {$ifdef CCLASSESINLINE}inline;{$endif}
  282. function GetCapacity: integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  283. public
  284. constructor Create(FreeObjects : boolean = True);
  285. destructor Destroy; override;
  286. procedure Clear;
  287. function Add(const AName:TSymStr;AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  288. function NameOfIndex(Index: Integer): TSymStr; {$ifdef CCLASSESINLINE}inline;{$endif}
  289. function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
  290. function GetNextCollision(Index: Integer): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  291. procedure Delete(Index: Integer);
  292. function Extract(Item: TObject): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  293. function Remove(AObject: TObject): Integer;
  294. function IndexOf(AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  295. function Find(const s:TSymStr): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
  296. function FindIndexOf(const s:TSymStr): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  297. function FindWithHash(const AName:TSymStr;AHash:LongWord): Pointer; {$ifdef CCLASSESINLINE}inline;{$endif}
  298. function Rename(const AOldName,ANewName:TSymStr): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  299. function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
  300. procedure Pack; {$ifdef CCLASSESINLINE}inline;{$endif}
  301. procedure ShowStatistics; {$ifdef CCLASSESINLINE}inline;{$endif}
  302. procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
  303. procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer); {$ifdef CCLASSESINLINE}inline;{$endif}
  304. property Capacity: Integer read GetCapacity write SetCapacity;
  305. property Count: Integer read GetCount;
  306. property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
  307. property Items[Index: Integer]: TObject read GetItem write SetItem; default;
  308. property List: TFPHashList read FHashList;
  309. end;
  310. {********************************************
  311. TLinkedList
  312. ********************************************}
  313. type
  314. TLinkedListItem = class
  315. public
  316. Previous,
  317. Next : TLinkedListItem;
  318. Constructor Create;
  319. Destructor Destroy;override;
  320. Function GetCopy:TLinkedListItem;virtual;
  321. end;
  322. TLinkedListItemClass = class of TLinkedListItem;
  323. TLinkedList = class
  324. private
  325. FCount : integer;
  326. FFirst,
  327. FLast : TLinkedListItem;
  328. FNoClear : boolean;
  329. public
  330. constructor Create;
  331. destructor Destroy;override;
  332. { true when the List is empty }
  333. function Empty:boolean; {$ifdef CCLASSESINLINE}inline;{$endif}
  334. { deletes all Items }
  335. procedure Clear;
  336. { inserts an Item }
  337. procedure Insert(Item:TLinkedListItem);
  338. { inserts an Item before Loc }
  339. procedure InsertBefore(Item,Loc : TLinkedListItem);
  340. { inserts an Item after Loc }
  341. procedure InsertAfter(Item,Loc : TLinkedListItem);virtual;
  342. { concatenate an Item }
  343. procedure Concat(Item:TLinkedListItem);
  344. { deletes an Item }
  345. procedure Remove(Item:TLinkedListItem);
  346. { Gets First Item }
  347. function GetFirst:TLinkedListItem;
  348. { Gets last Item }
  349. function GetLast:TLinkedListItem;
  350. { inserts another List at the begin and make this List empty }
  351. procedure insertList(p : TLinkedList); virtual;
  352. { inserts another List before the provided item and make this List empty }
  353. procedure insertListBefore(Item:TLinkedListItem;p : TLinkedList); virtual;
  354. { inserts another List after the provided item and make this List empty }
  355. procedure insertListAfter(Item:TLinkedListItem;p : TLinkedList); virtual;
  356. { concatenate another List at the end and make this List empty }
  357. procedure concatList(p : TLinkedList); virtual;
  358. { concatenate another List at the start and makes a copy
  359. the list is ordered in reverse.
  360. }
  361. procedure insertListcopy(p : TLinkedList); virtual;
  362. { concatenate another List at the end and makes a copy }
  363. procedure concatListcopy(p : TLinkedList); virtual;
  364. { removes all items from the list, the items are not freed }
  365. procedure RemoveAll; virtual;
  366. property First:TLinkedListItem read FFirst;
  367. property Last:TLinkedListItem read FLast;
  368. property Count:Integer read FCount;
  369. property NoClear:boolean write FNoClear;
  370. end;
  371. {********************************************
  372. TCmdStrList
  373. ********************************************}
  374. { string containerItem }
  375. TCmdStrListItem = class(TLinkedListItem)
  376. FPStr : TCmdStr;
  377. public
  378. constructor Create(const s:TCmdStr);
  379. destructor Destroy;override;
  380. function GetCopy:TLinkedListItem;override;
  381. property Str: TCmdStr read FPStr;
  382. end;
  383. { string container }
  384. TCmdStrList = class(TLinkedList)
  385. private
  386. FDoubles : boolean; { if this is set to true, doubles (case insensitive!) are allowed }
  387. public
  388. constructor Create;
  389. constructor Create_No_Double;
  390. { inserts an Item }
  391. procedure Insert(const s:TCmdStr);
  392. { concatenate an Item }
  393. procedure Concat(const s:TCmdStr);
  394. { deletes an Item }
  395. procedure Remove(const s:TCmdStr);
  396. { Gets First Item }
  397. function GetFirst:TCmdStr;
  398. { Gets last Item }
  399. function GetLast:TCmdStr;
  400. { true if string is in the container, compare case sensitive }
  401. function FindCase(const s:TCmdStr):TCmdStrListItem;
  402. { true if string is in the container }
  403. function Find(const s:TCmdStr):TCmdStrListItem;
  404. { inserts an item }
  405. procedure InsertItem(item:TCmdStrListItem);
  406. { concatenate an item }
  407. procedure ConcatItem(item:TCmdStrListItem);
  408. property Doubles:boolean read FDoubles write FDoubles;
  409. end;
  410. {********************************************
  411. DynamicArray
  412. ********************************************}
  413. type
  414. { can't use sizeof(integer) because it crashes gdb }
  415. tdynamicblockdata=array[0..1024*1024-1] of byte;
  416. pdynamicblock = ^tdynamicblock;
  417. tdynamicblock = record
  418. pos,
  419. size,
  420. used : longword;
  421. Next : pdynamicblock;
  422. data : tdynamicblockdata;
  423. end;
  424. tdynamicblockarray = array of tdynamicblock;
  425. const
  426. dynamicblockbasesize = sizeof(tdynamicblock)-sizeof(tdynamicblockdata);
  427. mindynamicblocksize = 8*sizeof(pointer);
  428. type
  429. tdynamicarray = class
  430. private
  431. FPosn : longword;
  432. FPosnblock : pdynamicblock;
  433. FCurrBlocksize,
  434. FMaxBlocksize : longword;
  435. FFirstblock,
  436. FLastblock : pdynamicblock;
  437. procedure grow;
  438. public
  439. constructor Create(Ablocksize:longword);
  440. destructor Destroy;override;
  441. procedure reset;
  442. function size:longword; {$ifdef CCLASSESINLINE}inline;{$endif}
  443. procedure align(i:longword);
  444. procedure seek(i:longword);
  445. function read(var d;len:longword):longword;
  446. procedure write(const d;len:longword);
  447. procedure writestr(const s:string); {$ifdef CCLASSESINLINE}inline;{$endif}
  448. procedure readstream(f:TCStream;maxlen:longword);
  449. procedure writestream(f:TCStream);
  450. function equal(other:tdynamicarray):boolean;
  451. property CurrBlockSize : longword read FCurrBlocksize;
  452. property FirstBlock : PDynamicBlock read FFirstBlock;
  453. property Pos : longword read FPosn;
  454. end;
  455. {******************************************************************
  456. THashSet (keys not limited to ShortString, no indexed access)
  457. *******************************************************************}
  458. PPHashSetItem = ^PHashSetItem;
  459. PHashSetItem = ^THashSetItem;
  460. THashSetItem = record
  461. Next: PHashSetItem;
  462. Key: Pointer; { With FOwnKeys, item and its key are allocated at once, and Key points inside. }
  463. KeyLength: Integer;
  464. HashValue: LongWord;
  465. Data: TObject;
  466. end;
  467. THashSet = class(TObject)
  468. private
  469. FCount: LongWord;
  470. FOwnsObjects: Boolean;
  471. FOwnsKeys: Boolean;
  472. function Lookup(Key: Pointer; KeyLen: Integer; var Found: Boolean;
  473. CanCreate: Boolean): PHashSetItem;
  474. procedure Resize(NewCapacity: LongWord);
  475. protected
  476. FBucket: PPHashSetItem;
  477. FBucketCount: LongWord;
  478. class procedure FreeItem(item:PHashSetItem); virtual;
  479. class function SizeOfItem: Integer; virtual;
  480. function CreateItem(Key: Pointer; KeyLen: Integer; HashValue: LongWord): PHashSetItem;
  481. public
  482. constructor Create(InitSize: Integer; OwnKeys, OwnObjects: Boolean);
  483. destructor Destroy; override;
  484. procedure Clear;
  485. { finds an entry by key }
  486. function Find(Key: Pointer; KeyLen: Integer): PHashSetItem;virtual;
  487. { finds an entry, creates one if not exists }
  488. function FindOrAdd(Key: Pointer; KeyLen: Integer;
  489. var Found: Boolean): PHashSetItem;virtual;
  490. { finds an entry, creates one if not exists }
  491. function FindOrAdd(Key: Pointer; KeyLen: Integer): PHashSetItem;virtual;
  492. { returns Data by given Key }
  493. function Get(Key: Pointer; KeyLen: Integer): TObject;virtual;
  494. { removes an entry, returns False if entry wasn't there }
  495. function Remove(Entry: PHashSetItem): Boolean;
  496. property Count: LongWord read FCount;
  497. end;
  498. {******************************************************************
  499. TTagHasSet
  500. *******************************************************************}
  501. PPTagHashSetItem = ^PTagHashSetItem;
  502. PTagHashSetItem = ^TTagHashSetItem;
  503. TTagHashSetItem = record
  504. Item: THashSetItem;
  505. Tag: LongWord;
  506. end;
  507. TTagHashSet = class(THashSet)
  508. private
  509. function Lookup(Key: Pointer; KeyLen: Integer; Tag: LongWord; var Found: Boolean;
  510. CanCreate: Boolean): PTagHashSetItem;
  511. protected
  512. class function SizeOfItem: Integer; override;
  513. public
  514. { finds an entry by key }
  515. function Find(Key: Pointer; KeyLen: Integer; Tag: LongWord): PTagHashSetItem; reintroduce;
  516. { finds an entry, creates one if not exists }
  517. function FindOrAdd(Key: Pointer; KeyLen: Integer; Tag: LongWord;
  518. var Found: Boolean): PTagHashSetItem; reintroduce;
  519. { finds an entry, creates one if not exists }
  520. function FindOrAdd(Key: Pointer; KeyLen: Integer; Tag: LongWord): PTagHashSetItem; reintroduce;
  521. { returns Data by given Key }
  522. function Get(Key: Pointer; KeyLen: Integer; Tag: LongWord): TObject; reintroduce;
  523. end;
  524. {******************************************************************
  525. tbitset
  526. *******************************************************************}
  527. { tbitset }
  528. tbitset = class
  529. private
  530. fdata: TByteDynArray;
  531. function getdatasize: longint;
  532. public
  533. constructor create(initsize: longint);
  534. constructor create_bytesize(bytesize: longint);
  535. destructor destroy; override;
  536. procedure clear; {$ifdef CCLASSESINLINE}inline;{$endif}
  537. procedure grow(nsize: longint);
  538. { sets a bit }
  539. procedure include(index: longint);
  540. { clears a bit }
  541. procedure exclude(index: longint);
  542. { finds an entry, creates one if not exists }
  543. function isset(index: longint): boolean;
  544. procedure addset(aset: tbitset);
  545. procedure subset(aset: tbitset);
  546. property data: TByteDynArray read fdata;
  547. property datasize: longint read getdatasize;
  548. end;
  549. function FPHash(P: PChar; Len: Integer; Tag: LongWord): LongWord;
  550. function FPHash(P: PChar; Len: Integer): LongWord; inline;
  551. function FPHash(const s:shortstring):LongWord; inline;
  552. function FPHash(const a:ansistring):LongWord; inline;
  553. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; var Strings: TDynStringArray; AddEmptyStrings : Boolean = False): Integer;
  554. implementation
  555. {*****************************************************************************
  556. Memory debug
  557. *****************************************************************************}
  558. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; var Strings: TDynStringArray; AddEmptyStrings : Boolean = False): Integer;
  559. var
  560. b, c : pchar;
  561. procedure SkipWhitespace;
  562. begin
  563. while (c^ in Whitespace) do
  564. inc (c);
  565. end;
  566. procedure AddString;
  567. var
  568. l : integer;
  569. s : string;
  570. begin
  571. l := c-b;
  572. s:='';
  573. if (l > 0) or AddEmptyStrings then
  574. begin
  575. setlength(s, l);
  576. if l>0 then
  577. move (b^, s[1],l*SizeOf(char));
  578. l:=length(Strings);
  579. setlength(Strings,l+1);
  580. Strings[l]:=S;
  581. inc (result);
  582. end;
  583. end;
  584. var
  585. quoted : char;
  586. begin
  587. result := 0;
  588. c := Content;
  589. Quoted := #0;
  590. Separators := Separators + [#13, #10] - ['''','"'];
  591. SkipWhitespace;
  592. b := c;
  593. while (c^ <> #0) do
  594. begin
  595. if (c^ = Quoted) then
  596. begin
  597. if ((c+1)^ = Quoted) then
  598. inc (c)
  599. else
  600. Quoted := #0
  601. end
  602. else if (Quoted = #0) and (c^ in ['''','"']) then
  603. Quoted := c^;
  604. if (Quoted = #0) and (c^ in Separators) then
  605. begin
  606. AddString;
  607. inc (c);
  608. SkipWhitespace;
  609. b := c;
  610. end
  611. else
  612. inc (c);
  613. end;
  614. if (c <> b) then
  615. AddString;
  616. end;
  617. constructor tmemdebug.create(const s:string);
  618. begin
  619. infostr:=s;
  620. totalmem:=0;
  621. Start;
  622. end;
  623. procedure tmemdebug.start;
  624. var
  625. status : TFPCHeapStatus;
  626. begin
  627. status:=GetFPCHeapStatus;
  628. startmem:=status.CurrHeapUsed;
  629. end;
  630. procedure tmemdebug.stop;
  631. var
  632. status : TFPCHeapStatus;
  633. begin
  634. if startmem<>0 then
  635. begin
  636. status:=GetFPCHeapStatus;
  637. inc(TotalMem,startmem-status.CurrHeapUsed);
  638. startmem:=0;
  639. end;
  640. end;
  641. destructor tmemdebug.destroy;
  642. begin
  643. Stop;
  644. show;
  645. end;
  646. procedure tmemdebug.show;
  647. begin
  648. write('memory [',infostr,'] ');
  649. if TotalMem>0 then
  650. writeln(DStr(TotalMem shr 10),' Kb released')
  651. else
  652. writeln(DStr((-TotalMem) shr 10),' Kb allocated');
  653. end;
  654. {*****************************************************************************
  655. TFPObjectList (Copied from rtl/objpas/classes/lists.inc)
  656. *****************************************************************************}
  657. procedure TFPList.RaiseIndexError(Index : Integer);
  658. begin
  659. Error(SListIndexError, Index);
  660. end;
  661. function TFPList.Get(Index: Integer): Pointer;
  662. begin
  663. If (Index < 0) or (Index >= FCount) then
  664. RaiseIndexError(Index);
  665. Result:=FList[Index];
  666. end;
  667. procedure TFPList.Put(Index: Integer; Item: Pointer);
  668. begin
  669. if (Index < 0) or (Index >= FCount) then
  670. RaiseIndexError(Index);
  671. Flist[Index] := Item;
  672. end;
  673. function TFPList.Extract(item: Pointer): Pointer;
  674. var
  675. i : Integer;
  676. begin
  677. result := nil;
  678. i := IndexOf(item);
  679. if i >= 0 then
  680. begin
  681. Result := item;
  682. FList[i] := nil;
  683. Delete(i);
  684. end;
  685. end;
  686. procedure TFPList.SetCapacity(NewCapacity: Integer);
  687. begin
  688. If (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  689. Error (SListCapacityError, NewCapacity);
  690. if NewCapacity = FCapacity then
  691. exit;
  692. ReallocMem(FList, SizeOf(Pointer)*NewCapacity);
  693. FCapacity := NewCapacity;
  694. end;
  695. procedure TFPList.SetCount(NewCount: Integer);
  696. begin
  697. if (NewCount < 0) or (NewCount > MaxListSize)then
  698. Error(SListCountError, NewCount);
  699. If NewCount > FCount then
  700. begin
  701. If NewCount > FCapacity then
  702. SetCapacity(NewCount);
  703. If FCount < NewCount then
  704. FillChar(Flist[FCount], (NewCount-FCount) * sizeof(Pointer), 0);
  705. end;
  706. FCount := Newcount;
  707. end;
  708. destructor TFPList.Destroy;
  709. begin
  710. Self.Clear;
  711. inherited Destroy;
  712. end;
  713. function TFPList.Add(Item: Pointer): Integer;
  714. begin
  715. if FCount = FCapacity then
  716. Self.Expand;
  717. FList[FCount] := Item;
  718. Result := FCount;
  719. inc(FCount);
  720. end;
  721. procedure TFPList.Clear;
  722. begin
  723. if Assigned(FList) then
  724. begin
  725. SetCount(0);
  726. SetCapacity(0);
  727. FList := nil;
  728. end;
  729. end;
  730. procedure TFPList.Delete(Index: Integer);
  731. begin
  732. If (Index<0) or (Index>=FCount) then
  733. Error (SListIndexError, Index);
  734. dec(FCount);
  735. System.Move (FList[Index+1], FList[Index], (FCount - Index) * SizeOf(Pointer));
  736. { Shrink the list if appropriate }
  737. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  738. begin
  739. FCapacity := FCapacity shr 1;
  740. ReallocMem(FList, SizeOf(Pointer) * FCapacity);
  741. end;
  742. end;
  743. class procedure TFPList.Error(const Msg: string; Data: PtrInt);
  744. begin
  745. Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  746. end;
  747. procedure TFPList.Exchange(Index1, Index2: Integer);
  748. var
  749. Temp : Pointer;
  750. begin
  751. If ((Index1 >= FCount) or (Index1 < 0)) then
  752. Error(SListIndexError, Index1);
  753. If ((Index2 >= FCount) or (Index2 < 0)) then
  754. Error(SListIndexError, Index2);
  755. Temp := FList[Index1];
  756. FList[Index1] := FList[Index2];
  757. FList[Index2] := Temp;
  758. end;
  759. function TFPList.Expand: TFPList;
  760. var
  761. IncSize : Longint;
  762. begin
  763. Result := Self;
  764. if FCount < FCapacity then
  765. exit;
  766. IncSize := sizeof(ptrint)*2;
  767. if FCapacity > 127 then
  768. Inc(IncSize, FCapacity shr 2)
  769. else if FCapacity > sizeof(ptrint)*4 then
  770. Inc(IncSize, FCapacity shr 1)
  771. else if FCapacity >= sizeof(ptrint) then
  772. inc(IncSize,sizeof(ptrint));
  773. SetCapacity(FCapacity + IncSize);
  774. end;
  775. function TFPList.First: Pointer;
  776. begin
  777. If FCount<>0 then
  778. Result := Items[0]
  779. else
  780. Result := Nil;
  781. end;
  782. function TFPList.IndexOf(Item: Pointer): Integer;
  783. begin
  784. Result:=
  785. {$if sizeof(pointer)=sizeof(dword)}
  786. IndexDWord
  787. {$elseif sizeof(pointer)=sizeof(qword)}
  788. IndexQWord
  789. {$else}
  790. {$error unknown pointer size}
  791. {$endif}
  792. (FList^, FCount, PtrUint(Item));
  793. end;
  794. function TFPList.IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
  795. var
  796. psrc : PPointer;
  797. Index : Integer;
  798. begin
  799. if Direction=FromBeginning then
  800. Result:=IndexOf(Item)
  801. else
  802. begin
  803. Result:=-1;
  804. if FCount>0 then
  805. begin
  806. psrc:=@FList[FCount-1];
  807. For Index:=FCount-1 downto 0 Do
  808. begin
  809. if psrc^=Item then
  810. begin
  811. Result:=Index;
  812. exit;
  813. end;
  814. dec(psrc);
  815. end;
  816. end;
  817. end;
  818. end;
  819. procedure TFPList.Insert(Index: Integer; Item: Pointer);
  820. begin
  821. if (Index < 0) or (Index > FCount )then
  822. Error(SlistIndexError, Index);
  823. iF FCount = FCapacity then Self.Expand;
  824. if Index<FCount then
  825. System.Move(Flist[Index], Flist[Index+1], (FCount - Index) * SizeOf(Pointer));
  826. FList[Index] := Item;
  827. FCount := FCount + 1;
  828. end;
  829. function TFPList.Last: Pointer;
  830. begin
  831. If FCount<>0 then
  832. Result := Items[FCount - 1]
  833. else
  834. Result := nil
  835. end;
  836. procedure TFPList.Move(CurIndex, NewIndex: Integer);
  837. var
  838. Temp : Pointer;
  839. begin
  840. if ((CurIndex < 0) or (CurIndex > Count - 1)) then
  841. Error(SListIndexError, CurIndex);
  842. if (NewINdex < 0) then
  843. Error(SlistIndexError, NewIndex);
  844. Temp := FList[CurIndex];
  845. FList[CurIndex] := nil;
  846. Self.Delete(CurIndex);
  847. Self.Insert(NewIndex, nil);
  848. FList[NewIndex] := Temp;
  849. end;
  850. function TFPList.Remove(Item: Pointer): Integer;
  851. begin
  852. Result := IndexOf(Item);
  853. If Result <> -1 then
  854. Self.Delete(Result);
  855. end;
  856. procedure TFPList.Pack;
  857. var
  858. NewCount,
  859. i : integer;
  860. pdest,
  861. psrc : PPointer;
  862. begin
  863. NewCount:=0;
  864. psrc:=@FList[0];
  865. pdest:=psrc;
  866. For I:=0 To FCount-1 Do
  867. begin
  868. if assigned(psrc^) then
  869. begin
  870. pdest^:=psrc^;
  871. inc(pdest);
  872. inc(NewCount);
  873. end;
  874. inc(psrc);
  875. end;
  876. FCount:=NewCount;
  877. end;
  878. Procedure QuickSort(FList: PPointer; L, R : Longint;Compare: TListSortCompare);
  879. var
  880. I, J, P: Longint;
  881. PItem, Q : Pointer;
  882. begin
  883. repeat
  884. I := L;
  885. J := R;
  886. P := (L + R) div 2;
  887. repeat
  888. PItem := FList[P];
  889. while Compare(PItem, FList[i]) > 0 do
  890. I := I + 1;
  891. while Compare(PItem, FList[J]) < 0 do
  892. J := J - 1;
  893. If I <= J then
  894. begin
  895. Q := FList[I];
  896. Flist[I] := FList[J];
  897. FList[J] := Q;
  898. if P = I then
  899. P := J
  900. else if P = J then
  901. P := I;
  902. I := I + 1;
  903. J := J - 1;
  904. end;
  905. until I > J;
  906. if L < J then
  907. QuickSort(FList, L, J, Compare);
  908. L := I;
  909. until I >= R;
  910. end;
  911. procedure TFPList.Sort(Compare: TListSortCompare);
  912. begin
  913. if Not Assigned(FList) or (FCount < 2) then exit;
  914. QuickSort(Flist, 0, FCount-1, Compare);
  915. end;
  916. procedure TFPList.Assign(Obj: TFPList);
  917. var
  918. i: Integer;
  919. begin
  920. Clear;
  921. for I := 0 to Obj.Count - 1 do
  922. Add(Obj[i]);
  923. end;
  924. procedure TFPList.ForEachCall(proc2call:TListCallback;arg:pointer);
  925. var
  926. i : integer;
  927. p : pointer;
  928. begin
  929. For I:=0 To Count-1 Do
  930. begin
  931. p:=FList[i];
  932. if assigned(p) then
  933. proc2call(p,arg);
  934. end;
  935. end;
  936. procedure TFPList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  937. var
  938. i : integer;
  939. p : pointer;
  940. begin
  941. For I:=0 To Count-1 Do
  942. begin
  943. p:=FList[i];
  944. if assigned(p) then
  945. proc2call(p,arg);
  946. end;
  947. end;
  948. class procedure TFPList.AddOnDemand(var Lst: TFPList; Item: Pointer);
  949. begin
  950. if not Assigned(Lst) then
  951. Lst := TFPList.Create;
  952. Lst.Add(Item);
  953. end;
  954. class procedure TFPList.FreeAndNilObjects(var Lst: TFPList);
  955. var
  956. Lp: PPointer;
  957. I: SizeInt;
  958. begin
  959. if not Assigned(Lst) then
  960. exit;
  961. Lp := Lst.FList;
  962. for I := 0 to Lst.Count-1 do
  963. TObject(Lp[I]).Free; // no nil needed
  964. Lst.Free;
  965. Lst := nil;
  966. end;
  967. procedure fpc_finalize(data, typeinfo: pointer); external;
  968. class procedure TFPList.FreeAndNilDisposing(var Lst: TFPList; ItemType: Pointer);
  969. var
  970. Lp: PPointer;
  971. I: SizeInt;
  972. begin
  973. if not Assigned(Lst) then
  974. exit;
  975. Lp := Lst.FList;
  976. for I := 0 to Lst.Count-1 do
  977. if Assigned(Lp[I]) then
  978. begin
  979. fpc_finalize(Lp[I],ItemType);
  980. FreeMem(Lp[I]);
  981. end;
  982. Lst.Free;
  983. Lst := nil;
  984. end;
  985. {*****************************************************************************
  986. TFPObjectList (Copied from rtl/objpas/classes/lists.inc)
  987. *****************************************************************************}
  988. constructor TFPObjectList.Create(FreeObjects : boolean);
  989. begin
  990. Create;
  991. FFreeObjects := Freeobjects;
  992. end;
  993. destructor TFPObjectList.Destroy;
  994. begin
  995. if (FList <> nil) then
  996. begin
  997. Clear;
  998. FList.Destroy;
  999. FList:=nil;
  1000. end;
  1001. inherited Destroy;
  1002. end;
  1003. procedure TFPObjectList.Clear;
  1004. var
  1005. i: integer;
  1006. begin
  1007. if FFreeObjects then
  1008. for i := 0 to FList.Count - 1 do
  1009. TObject(FList[i]).Free; // no nil needed
  1010. FList.Clear;
  1011. end;
  1012. constructor TFPObjectList.Create;
  1013. begin
  1014. inherited Create;
  1015. FList := TFPList.Create;
  1016. FFreeObjects := True;
  1017. end;
  1018. function TFPObjectList.IndexOf(AObject: TObject): Integer;
  1019. begin
  1020. Result := FList.IndexOf(Pointer(AObject));
  1021. end;
  1022. function TFPObjectList.IndexOfItem(AObject: TObject; Direction: TDirection): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
  1023. begin
  1024. Result := FList.IndexOfItem(Pointer(AObject),Direction);
  1025. end;
  1026. function TFPObjectList.GetCount: integer;
  1027. begin
  1028. Result := FList.Count;
  1029. end;
  1030. procedure TFPObjectList.SetCount(const AValue: integer);
  1031. begin
  1032. if FList.Count <> AValue then
  1033. FList.Count := AValue;
  1034. end;
  1035. function TFPObjectList.GetItem(Index: Integer): TObject;
  1036. begin
  1037. Result := TObject(FList[Index]);
  1038. end;
  1039. procedure TFPObjectList.SetItem(Index: Integer; AObject: TObject);
  1040. begin
  1041. if OwnsObjects then
  1042. TObject(FList[Index]).Free; // no nil needed
  1043. FList[index] := AObject;
  1044. end;
  1045. procedure TFPObjectList.SetCapacity(NewCapacity: Integer);
  1046. begin
  1047. FList.Capacity := NewCapacity;
  1048. end;
  1049. function TFPObjectList.GetCapacity: integer;
  1050. begin
  1051. Result := FList.Capacity;
  1052. end;
  1053. function TFPObjectList.Add(AObject: TObject): Integer;
  1054. begin
  1055. Result := FList.Add(AObject);
  1056. end;
  1057. procedure TFPObjectList.Delete(Index: Integer);
  1058. begin
  1059. if OwnsObjects then
  1060. TObject(FList[Index]).Free; // no nil needed
  1061. FList.Delete(Index);
  1062. end;
  1063. procedure TFPObjectList.Exchange(Index1, Index2: Integer);
  1064. begin
  1065. FList.Exchange(Index1, Index2);
  1066. end;
  1067. function TFPObjectList.Expand: TFPObjectList;
  1068. begin
  1069. FList.Expand;
  1070. Result := Self;
  1071. end;
  1072. function TFPObjectList.Extract(Item: TObject): TObject;
  1073. begin
  1074. Result := TObject(FList.Extract(Item));
  1075. end;
  1076. function TFPObjectList.Remove(AObject: TObject): Integer;
  1077. begin
  1078. Result := IndexOf(AObject);
  1079. if (Result <> -1) then
  1080. begin
  1081. if OwnsObjects then
  1082. TObject(FList[Result]).Free; // no nil needed
  1083. FList.Delete(Result);
  1084. end;
  1085. end;
  1086. function TFPObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
  1087. var
  1088. I : Integer;
  1089. begin
  1090. I:=AStartAt;
  1091. Result:=-1;
  1092. If AExact then
  1093. while (I<Count) and (Result=-1) do
  1094. If Items[i].ClassType=AClass then
  1095. Result:=I
  1096. else
  1097. Inc(I)
  1098. else
  1099. while (I<Count) and (Result=-1) do
  1100. If Items[i].InheritsFrom(AClass) then
  1101. Result:=I
  1102. else
  1103. Inc(I);
  1104. end;
  1105. procedure TFPObjectList.Insert(Index: Integer; AObject: TObject);
  1106. begin
  1107. FList.Insert(Index, Pointer(AObject));
  1108. end;
  1109. procedure TFPObjectList.Move(CurIndex, NewIndex: Integer);
  1110. begin
  1111. FList.Move(CurIndex, NewIndex);
  1112. end;
  1113. procedure TFPObjectList.Assign(Obj: TFPObjectList);
  1114. begin
  1115. Clear;
  1116. ConcatListCopy(Obj);
  1117. end;
  1118. procedure TFPObjectList.ConcatListCopy(Obj: TFPObjectList);
  1119. var
  1120. i: Integer;
  1121. begin
  1122. for I := 0 to Obj.Count - 1 do
  1123. Add(Obj[i]);
  1124. end;
  1125. procedure TFPObjectList.Pack;
  1126. begin
  1127. FList.Pack;
  1128. end;
  1129. procedure TFPObjectList.Sort(Compare: TListSortCompare);
  1130. begin
  1131. FList.Sort(Compare);
  1132. end;
  1133. function TFPObjectList.First: TObject;
  1134. begin
  1135. Result := TObject(FList.First);
  1136. end;
  1137. function TFPObjectList.Last: TObject;
  1138. begin
  1139. Result := TObject(FList.Last);
  1140. end;
  1141. procedure TFPObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  1142. begin
  1143. FList.ForEachCall(TListCallBack(proc2call),arg);
  1144. end;
  1145. procedure TFPObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  1146. begin
  1147. FList.ForEachCall(TListStaticCallBack(proc2call),arg);
  1148. end;
  1149. {*****************************************************************************
  1150. TFPHashList
  1151. *****************************************************************************}
  1152. // MurmurHash3_32
  1153. function FPHash(P: PChar; Len: Integer; Tag: LongWord): LongWord;
  1154. const
  1155. C1 = uint32($cc9e2d51);
  1156. C2 = uint32($1b873593);
  1157. var
  1158. h, tail: uint32;
  1159. e4: pChar;
  1160. len4, nTail: SizeUint;
  1161. begin
  1162. {$push}
  1163. {$q-,r-}
  1164. h := tag;
  1165. len4 := len and not integer(sizeof(uint32) - 1); { len div sizeof(uint32) * sizeof(uint32) }
  1166. e4 := p + len4;
  1167. nTail := len - len4;
  1168. while p < e4 do
  1169. begin
  1170. { If independence on endianness is desired, unaligned(pUint32(p)^) can be replaced with LEtoN(unaligned(pUint32(p)^)). }
  1171. h := RolDWord(h xor (RolDWord(unaligned(pUint32(p)^) * C1, 15) * C2), 13) * 5 + $e6546b64;
  1172. p := p + sizeof(uint32);
  1173. end;
  1174. if nTail > 0 then
  1175. begin
  1176. { tail is 1 to 3 bytes }
  1177. case nTail of
  1178. 3: tail := unaligned(pUint16(p)^) or uint32(p[2]) shl 16; { unaligned(pUint16(p^)) can be LEtoNed for portability }
  1179. 2: tail := unaligned(pUint16(p)^); { unaligned(pUint16(p^)) can be LEtoNed for portability }
  1180. {1:} else tail := uint32(p^);
  1181. end;
  1182. h := h xor (RolDWord(tail * C1, 15) * C2);
  1183. end;
  1184. h := h xor uint32(len);
  1185. h := (h xor (h shr 16)) * $85ebca6b;
  1186. h := (h xor (h shr 13)) * $c2b2ae35;
  1187. result := h xor (h shr 16);
  1188. {$pop}
  1189. end;
  1190. function FPHash(P: PChar; Len: Integer): LongWord; inline;
  1191. begin
  1192. result:=fphash(P,Len, 0);
  1193. end;
  1194. function FPHash(const s: shortstring): LongWord; inline;
  1195. begin
  1196. result:=fphash(pchar(@s[1]),length(s));
  1197. end;
  1198. function FPHash(const a: ansistring): LongWord; inline;
  1199. begin
  1200. result:=fphash(pchar(a),length(a));
  1201. end;
  1202. procedure TMemoryRegion.Init(preallocate: SizeUint=0);
  1203. begin
  1204. FTop:=nil;
  1205. if preallocate>MinMemoryRegionNodeSize then
  1206. FTop:=AllocateNode(0, preallocate);
  1207. end;
  1208. procedure TMemoryRegion.Done;
  1209. begin
  1210. Clear;
  1211. end;
  1212. function TMemoryRegion.Push(n: SizeUint): pointer;
  1213. var
  1214. top: PMemoryRegionNode;
  1215. start: SizeUint;
  1216. begin
  1217. top:=FTop;
  1218. if Assigned(top) then
  1219. begin
  1220. start:=top^.n;
  1221. if n<=SizeUint(top^.alloc-start) then
  1222. begin
  1223. top^.n:=start+n;
  1224. exit(PByte(top^.data)+start);
  1225. end;
  1226. end;
  1227. result:=PushNewNode(n);
  1228. end;
  1229. procedure TMemoryRegion.Clear;
  1230. var
  1231. cur, next: PMemoryRegionNode;
  1232. begin
  1233. cur:=FTop;
  1234. FTop:=nil;
  1235. while Assigned(cur) do
  1236. begin
  1237. next:=cur^.next;
  1238. FreeMem(cur);
  1239. cur:=next;
  1240. end;
  1241. end;
  1242. function TMemoryRegion.CalcSumSize: SizeUint;
  1243. var
  1244. n: PMemoryRegionNode;
  1245. begin
  1246. result:=0;
  1247. n:=FTop;
  1248. while Assigned(n) do
  1249. begin
  1250. result:=result+n^.n;
  1251. n:=n^.next;
  1252. end;
  1253. end;
  1254. class function TMemoryRegion.AllocateNode(n, alloc: SizeUint): PMemoryRegionNode;
  1255. begin
  1256. result:=GetMem(PtrUint(@PMemoryRegionNode(nil)^.data)+alloc);
  1257. result^.n:=n;
  1258. result^.alloc:=alloc;
  1259. result^.next:=nil;
  1260. end;
  1261. function TMemoryRegion.PushNewNode(n: SizeUint): pointer;
  1262. var
  1263. alloc, sumSize: SizeUint;
  1264. newNode: PMemoryRegionNode;
  1265. begin
  1266. { The absolute minimum to allocate is the required contiguous n. }
  1267. sumSize:=CalcSumSize;
  1268. alloc:=MinMemoryRegionNodeSize+n+sumSize div 4; { const+n+25%. }
  1269. newNode:=AllocateNode(n, alloc);
  1270. newNode^.next:=FTop;
  1271. FTop:=newNode;
  1272. result:=PByte(newNode^.data);
  1273. end;
  1274. function ViGet(data: PSizeUint; index, bitsPerIndex: SizeUint): SizeUint;
  1275. begin
  1276. index:=index*bitsPerIndex;
  1277. data:=data+index div bitsizeof(SizeUint);
  1278. index:=index mod bitsizeof(SizeUint);
  1279. result:=data^ shr index;
  1280. index:=bitsizeof(data^)-index;
  1281. if bitsPerIndex<=index then
  1282. result:=result and (SizeUint(1) shl bitsPerIndex-1)
  1283. else
  1284. result:=result or data[1] shl index and (SizeUint(1) shl bitsPerIndex-1);
  1285. end;
  1286. procedure ViSet(data: PSizeUint; index, bitsPerIndex, value: SizeUint);
  1287. begin
  1288. index:=index*bitsPerIndex;
  1289. data:=data+index div bitsizeof(SizeUint);
  1290. index:=index mod bitsizeof(SizeUint);
  1291. if index+bitsPerIndex<=bitsizeof(data^) then
  1292. data^:=data^ and not ((SizeUint(1) shl bitsPerIndex-1) shl index) or value shl index
  1293. else
  1294. begin
  1295. data^:=SizeUint(data^ and (SizeUint(1) shl index - 1) or value shl index);
  1296. index:=bitsizeof(data^)-index;
  1297. value:=value shr index;
  1298. index:=bitsPerIndex-index;
  1299. data[1]:=data[1] shr index shl index or value;
  1300. end;
  1301. end;
  1302. function ViDataSize(n, bitsPerIndex: SizeUint): SizeUint;
  1303. begin
  1304. result:=(n*bitsPerIndex+(bitsizeof(SizeUint)-1)) div bitsizeof(SizeUint)*sizeof(SizeUint);
  1305. end;
  1306. function TViHashList.Get(Index: SizeInt): Pointer;
  1307. begin
  1308. If SizeUint(Index)>=SizeUint(FCount) then
  1309. RaiseIndexError(Index);
  1310. Result:=FItems[Index].Data;
  1311. end;
  1312. procedure TViHashList.Put(Index: SizeInt; Item: Pointer);
  1313. begin
  1314. If SizeUint(Index)>=SizeUint(FCount) then
  1315. RaiseIndexError(Index);
  1316. FItems[Index].Data:=Item;
  1317. end;
  1318. class procedure TViHashList.RaiseIndexError(Index: SizeInt);
  1319. begin
  1320. TFPList.Error(SListIndexError, Index);
  1321. end;
  1322. procedure TViHashList.SetupEmptyTable;
  1323. const
  1324. { 1-element FHash array containing one zero, which is ViEmpty.
  1325. Any searches will answer "not found", and any additions will instantly rehash. }
  1326. EmptyFHash: SizeUint = 0;
  1327. begin
  1328. FHash:=@EmptyFHash;
  1329. FItems:=nil;
  1330. FBitsPerIndex:=1;
  1331. FHashMask:=0;
  1332. FCapacity:=0;
  1333. end;
  1334. procedure TViHashList.Rehash(ForItems: SizeUint; mode: TViRehashMode=vi_Auto);
  1335. var
  1336. newCapacity, newHashMask, newBitsPerIndex, itemsOffset, regionSize: SizeUint;
  1337. i: SizeInt;
  1338. newHash: PSizeUint;
  1339. newItems: PViHashListItem;
  1340. shortcutReAdd: boolean;
  1341. begin
  1342. if ForItems=0 then
  1343. begin
  1344. Clear;
  1345. exit;
  1346. end;
  1347. if ForItems>MaxHashListSize then
  1348. TFPList.Error(SListCapacityError, ForItems);
  1349. { Can be something like "137.5% ForItems", but with bitwise indices, better to just derive the capacity later from chosen index type limit,
  1350. which will be 200% at most -
  1351. this way, both capacity and hash mask size become beautiful powers of two,
  1352. saving on rehashes ("shortcutReAdd" branch, while still required for degenerate scenarios, becomes de facto unreachable),
  1353. and often even on memory (though the reason for the latter is unclear to me; maybe "137.5%" in conjunction with "UpToPow2" introduces extra breakpoints). }
  1354. newCapacity:=ForItems;
  1355. { Max index for "capacity" items is "ViRealIndexOffset + (capacity - 1)", which can be rewritten as "capacity + (ViRealIndexOffset - 1)". }
  1356. newBitsPerIndex:=1+BsrDWord(newCapacity+(ViRealIndexOffset-1));
  1357. if not ((newBitsPerIndex>=1) and (newBitsPerIndex<=bitsizeof(SizeUint)-1)) then
  1358. InternalErrorProc(2022120701);
  1359. { In place of explicit over-allocation, increase capacity to index type limit. }
  1360. if mode<>vi_Tight then
  1361. newCapacity:=(SizeUint(1) shl newBitsPerIndex-1)-(ViRealIndexOffset-1);
  1362. { Take item list capacity rounded up to power of two. This can give 50% to 100% load factor.
  1363. If it gives more than 3/4, double the hash capacity again. After that, possible load factors will range from 37.5% to 75%.
  1364. Even load factors greater than 100% will work though. Low factors are just slightly faster, at the expense of memory. }
  1365. newHashMask:=SizeUint(1) shl (1+BsrDWord((newCapacity-1) or 1))-1; { UpToPow2(newCapacity)-1 }
  1366. if newHashMask div 4*3<newCapacity then
  1367. newHashMask:=newHashMask*2+1;
  1368. { Allocating and marking up the region for FHash + FItems. }
  1369. itemsOffset:=Align(ViDataSize(newHashMask+1,newBitsPerIndex), SizeUint(sizeof(pointer)));
  1370. regionSize:=itemsOffset+sizeof(TViHashListItem)*newCapacity;
  1371. newHash:=GetMem(regionSize);
  1372. newItems:=pointer(newHash)+itemsOffset;
  1373. { If hash mask hasn't changed (this is possible because of arbitrariness of FCapacity),
  1374. items re-adding can be, and is, shortcutted.
  1375. .Pack corrupts indices and expects from .Rehash to recalculate them, so is incompatible with this. }
  1376. shortcutReAdd:=(FHashMask=newHashMask) and (mode<>vi_Pack);
  1377. if shortcutReAdd then
  1378. begin
  1379. { If even index type hasn't changed, just copy FHash. Else convert. }
  1380. if newBitsPerIndex=FBitsPerIndex then
  1381. Move(FHash^, newHash^, ViDataSize(newHashMask+1,newBitsPerIndex))
  1382. else
  1383. for i:=0 to newHashMask do
  1384. ViSet(newHash, i, newBitsPerIndex, ViGet(FHash, i, FBitsPerIndex));
  1385. end
  1386. else
  1387. { Otherwise set all indices to ViEmpty. }
  1388. FillChar(newHash^, ViDataSize(newHashMask+1,newBitsPerIndex), 0);
  1389. { Move items as raw memory, even managed (old area is then deallocated without finalizing). }
  1390. Move(FItems^, newItems^, FCount*sizeof(TViHashListItem));
  1391. { Free the old table. "Assigned(FItems)" means that the table was not the fake table set up by SetupEmptyTable.
  1392. Items were just moved into a new place so shouldn't be finalized. }
  1393. if Assigned(FItems) then
  1394. FreeMem(FHash);
  1395. FHash:=newHash;
  1396. FItems:=newItems;
  1397. FBitsPerIndex:=newBitsPerIndex;
  1398. FHashMask:=newHashMask;
  1399. FCapacity:=newCapacity;
  1400. { Re-add items if re-adding was not shortcutted before. }
  1401. if not shortcutReAdd then
  1402. for i:=0 to FCount-1 do
  1403. AddToHashTable(FItems+i, i);
  1404. end;
  1405. {$ifndef symansistr}
  1406. function TViHashList.AddStrToRegion(const s: TSymStr): PSymStr;
  1407. var
  1408. size: SizeUint;
  1409. begin
  1410. size:=1+length(s);
  1411. result:=FShortstringRegion.Push(size);
  1412. System.Move(s[0],result^,size);
  1413. end;
  1414. {$endif}
  1415. procedure TViHashList.Shrink;
  1416. begin
  1417. if (FCapacity >= 64) and (uint32(FCount) < FCapacity div 4) then
  1418. Rehash(uint32(FCount)+uint32(FCount) div 4);
  1419. end;
  1420. procedure TViHashList.AddToHashTable(Item: PViHashListItem; Index: SizeUint);
  1421. var
  1422. HashIndex: SizeUint;
  1423. begin
  1424. if not Assigned(Item^.Data) then
  1425. exit;
  1426. HashIndex:=Item^.HashValue and FHashMask;
  1427. FItems[Index].Next:=SizeInt(ViGet(FHash, HashIndex, FBitsPerIndex))-ViRealIndexOffset;
  1428. ViSet(FHash, HashIndex, FBitsPerIndex, ViRealIndexOffset+Index);
  1429. end;
  1430. function TViHashList.InternalFind(AHash:LongWord;const AName:TSymStr;out PrevIndex:SizeInt):SizeInt;
  1431. var
  1432. it: PViHashListItem;
  1433. begin
  1434. Result:=SizeInt(ViGet(FHash, AHash and FHashMask, FBitsPerIndex))-ViRealIndexOffset;
  1435. PrevIndex:=-1;
  1436. repeat
  1437. if Result<0 then
  1438. exit;
  1439. it:=FItems+Result;
  1440. if Assigned(it^.Data) and (AHash=it^.HashValue) and (AName=it^.Str {$ifndef symansistr} ^ {$endif}) then
  1441. exit;
  1442. PrevIndex:=Result;
  1443. Result:=FItems[Result].Next;
  1444. until false;
  1445. end;
  1446. procedure TViHashList.RemoveFromHashTable(AHash:LongWord;Index, PrevIndex: SizeInt);
  1447. var
  1448. next: SizeInt;
  1449. begin
  1450. next:=SizeInt(FItems[Index].Next);
  1451. if PrevIndex<0 then
  1452. ViSet(FHash, AHash and FHashMask, FBitsPerIndex, ViRealIndexOffset+next)
  1453. else
  1454. FItems[PrevIndex].Next:=next;
  1455. end;
  1456. procedure TViHashList.SetCapacity(NewCapacity: uint32);
  1457. begin
  1458. if NewCapacity < uint32(FCount) then internalerrorproc(2021122605);
  1459. Rehash(NewCapacity, vi_Tight);
  1460. end;
  1461. constructor TViHashList.Create;
  1462. begin
  1463. inherited Create;
  1464. {$ifndef symansistr}
  1465. FShortstringRegion.Init;
  1466. {$endif}
  1467. SetupEmptyTable;
  1468. end;
  1469. destructor TViHashList.Destroy;
  1470. begin
  1471. Clear;
  1472. {$ifndef symansistr}
  1473. FShortstringRegion.Done;
  1474. {$endif}
  1475. inherited Destroy;
  1476. end;
  1477. function TViHashList.Add(const AName:TSymStr;Item: Pointer): SizeInt;
  1478. var
  1479. it: PViHashListItem;
  1480. begin
  1481. result:=FCount;
  1482. if uint32(result)=FCapacity then
  1483. Rehash(result+1);
  1484. it:=FItems+result;
  1485. Initialize(it^);
  1486. it^.HashValue:=FPHash(AName);
  1487. it^.Data:=Item;
  1488. {$ifdef symansistr}
  1489. it^.Str:=AName;
  1490. {$else}
  1491. it^.Str:=AddStrToRegion(AName);
  1492. {$endif}
  1493. AddToHashTable(it, result);
  1494. FCount:=result+1;
  1495. end;
  1496. procedure TViHashList.Clear;
  1497. begin
  1498. if Assigned(FItems) then
  1499. begin
  1500. Finalize(FItems^, FCount);
  1501. FreeMem(FHash);
  1502. SetupEmptyTable;
  1503. FCount:=0;
  1504. {$ifndef symansistr}
  1505. FShortstringRegion.Clear;
  1506. {$endif}
  1507. end;
  1508. end;
  1509. function TViHashList.NameOfIndex(Index: SizeInt): TSymStr;
  1510. begin
  1511. if SizeUint(Index)>=SizeUint(FCount) then
  1512. RaiseIndexError(Index);
  1513. result:=FItems[Index].Str {$ifndef symansistr} ^ {$endif};
  1514. end;
  1515. function TViHashList.HashOfIndex(Index: SizeInt): LongWord;
  1516. begin
  1517. if SizeUint(Index)>=SizeUint(FCount) then
  1518. RaiseIndexError(Index);
  1519. result:=FItems[Index].HashValue;
  1520. end;
  1521. function TViHashList.GetNextCollision(Index: SizeInt): SizeInt;
  1522. begin
  1523. Result:=FItems[Index].Next;
  1524. end;
  1525. procedure TViHashList.Delete(Index: SizeInt);
  1526. var
  1527. it: PViHashListItem;
  1528. prev, i: SizeInt;
  1529. begin
  1530. If SizeUint(Index)>=SizeUint(FCount) then
  1531. RaiseIndexError(Index);
  1532. { Remove from array, shifting items above. }
  1533. Finalize(FItems[Index]);
  1534. Move(FItems[Index+1], FItems[Index], (FCount-Index-1)*sizeof(TViHashListItem));
  1535. dec(FCount);
  1536. { Rebuild the table. This is much faster than trying to fix up indices. :( }
  1537. FillChar(FHash^, ViDataSize(FHashMask+1, FBitsPerIndex), 0);
  1538. for i:=0 to FCount-1 do
  1539. AddToHashTable(FItems+i, i);
  1540. Shrink;
  1541. end;
  1542. function TViHashList.Extract(item: Pointer): Pointer;
  1543. var
  1544. i : SizeInt;
  1545. begin
  1546. result:=nil;
  1547. i:=IndexOf(item);
  1548. if i>=0 then
  1549. begin
  1550. Result:=item;
  1551. Delete(i);
  1552. end;
  1553. end;
  1554. function TViHashList.IndexOf(Item: Pointer): SizeInt;
  1555. var
  1556. itemp, iteme: PViHashListItem;
  1557. begin
  1558. Result:=0;
  1559. itemp:=FItems;
  1560. iteme:=itemp+FCount;
  1561. while itemp<iteme do
  1562. begin
  1563. if itemp^.Data=Item then
  1564. exit;
  1565. inc(itemp);
  1566. inc(Result);
  1567. end;
  1568. Result:=-1;
  1569. end;
  1570. function TViHashList.Find(const AName:TSymStr): Pointer;
  1571. begin
  1572. Result:=FindWithHash(AName, FPHash(ANAme));
  1573. end;
  1574. function TViHashList.FindIndexOf(const AName:TSymStr): SizeInt;
  1575. var
  1576. PrevIndex : SizeInt;
  1577. begin
  1578. Result:=InternalFind(FPHash(AName),AName,PrevIndex);
  1579. end;
  1580. function TViHashList.FindWithHash(const AName:TSymStr;AHash:LongWord): Pointer;
  1581. var
  1582. Index,
  1583. PrevIndex : SizeInt;
  1584. begin
  1585. Result:=nil;
  1586. Index:=InternalFind(AHash,AName,PrevIndex);
  1587. if Index>=0 then
  1588. Result:=FItems[Index].Data;
  1589. end;
  1590. function TViHashList.Rename(const AOldName,ANewName:TSymStr): SizeInt;
  1591. var
  1592. PrevIndex : SizeInt;
  1593. OldHash : LongWord;
  1594. it: PViHashListItem;
  1595. begin
  1596. OldHash:=FPHash(AOldName);
  1597. result:=InternalFind(OldHash,AOldName,PrevIndex);
  1598. if result<0 then
  1599. exit;
  1600. RemoveFromHashTable(OldHash, result, PrevIndex);
  1601. it:=FItems+result;
  1602. it^.HashValue:=FPHash(ANewName);
  1603. {$ifdef symansistr}
  1604. it^.Str:=ANewName;
  1605. {$else}
  1606. it^.Str:=AddStrToRegion(ANewName);
  1607. {$endif}
  1608. AddToHashTable(it, result);
  1609. end;
  1610. function TViHashList.Remove(Item: Pointer): SizeInt;
  1611. begin
  1612. Result:=IndexOf(Item);
  1613. if Result>=0 then
  1614. Delete(Result);
  1615. end;
  1616. procedure TViHashList.Pack;
  1617. var
  1618. itemp, iteme, target: PViHashListItem;
  1619. removed: SizeUint;
  1620. begin
  1621. itemp:=FItems;
  1622. iteme:=itemp+FCount;
  1623. while itemp<iteme do
  1624. if Assigned(itemp^.Data) then
  1625. inc(itemp)
  1626. else
  1627. break;
  1628. if itemp<iteme then
  1629. begin
  1630. target:=itemp;
  1631. inc(itemp);
  1632. while itemp<iteme do
  1633. begin
  1634. if Assigned(itemp^.data) then
  1635. begin
  1636. target^:=itemp^;
  1637. inc(target);
  1638. end;
  1639. inc(itemp);
  1640. end;
  1641. removed:=SizeUint(pointer(iteme)-pointer(target)) div sizeof(TViHashListItem);
  1642. Finalize(target^, removed);
  1643. FCount:=FCount-removed;
  1644. end;
  1645. if uint32(FCount)<>FCapacity then
  1646. Rehash(FCount, vi_Pack);
  1647. end;
  1648. procedure TViHashList.ShowStatistics;
  1649. var
  1650. HashMean,
  1651. HashStdDev : Double;
  1652. Index,
  1653. i,j : SizeInt;
  1654. begin
  1655. { Calculate Mean and StdDev }
  1656. HashMean:=0;
  1657. HashStdDev:=0;
  1658. for i:=0 to FHashMask do
  1659. begin
  1660. j:=0;
  1661. Index:=SizeInt(ViGet(FHash, i, FBitsPerIndex))-ViRealIndexOffset;
  1662. while Index>=0 do
  1663. begin
  1664. inc(j);
  1665. Index:=FItems[Index].Next;
  1666. end;
  1667. HashMean:=HashMean+j;
  1668. HashStdDev:=HashStdDev+Sqr(j);
  1669. end;
  1670. HashMean:=HashMean/(FHashMask+1);
  1671. HashStdDev:=(HashStdDev-(FHashMask+1)*Sqr(HashMean));
  1672. If FHashMask>0 then
  1673. HashStdDev:=Sqrt(HashStdDev/FHashMask)
  1674. else
  1675. HashStdDev:=0;
  1676. { Print info to stdout }
  1677. Writeln('HashSize : ',FHashMask+1);
  1678. Writeln('HashMean : ',HashMean:1:4);
  1679. Writeln('HashStdDev : ',HashStdDev:1:4);
  1680. Writeln('ListSize : ',FCount,'/',FCapacity);
  1681. {$ifndef symansistr}
  1682. Writeln('StringSize : ',FShortstringRegion.CalcSumSize);
  1683. {$endif}
  1684. end;
  1685. procedure TViHashList.ForEachCall(proc2call:TListCallback;arg:pointer);
  1686. var
  1687. i: SizeInt;
  1688. p: pointer;
  1689. begin
  1690. for i:=0 to FCount-1 do
  1691. begin
  1692. p:=FItems[i].Data;
  1693. if assigned(p) then
  1694. proc2call(p,arg);
  1695. end;
  1696. end;
  1697. procedure TViHashList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  1698. var
  1699. i: SizeInt;
  1700. p: pointer;
  1701. begin
  1702. for i:=0 to FCount-1 do
  1703. begin
  1704. p:=FItems[i].Data;
  1705. if assigned(p) then
  1706. proc2call(p,arg);
  1707. end;
  1708. end;
  1709. {*****************************************************************************
  1710. TFPHashObjectList (Copied from rtl/objpas/classes/lists.inc)
  1711. *****************************************************************************}
  1712. constructor TFPHashObjectList.Create(FreeObjects : boolean = True);
  1713. begin
  1714. inherited Create;
  1715. FHashList := TFPHashList.Create;
  1716. FFreeObjects := Freeobjects;
  1717. end;
  1718. destructor TFPHashObjectList.Destroy;
  1719. begin
  1720. if (FHashList <> nil) then
  1721. begin
  1722. Clear;
  1723. FHashList.Destroy;
  1724. FHashList:=nil;
  1725. end;
  1726. inherited Destroy;
  1727. end;
  1728. procedure TFPHashObjectList.Clear;
  1729. var
  1730. i: integer;
  1731. begin
  1732. if FFreeObjects then
  1733. for i := 0 to FHashList.Count - 1 do
  1734. TObject(FHashList[i]).Free; // no nil needed
  1735. FHashList.Clear;
  1736. end;
  1737. function TFPHashObjectList.IndexOf(AObject: TObject): Integer;
  1738. begin
  1739. Result := FHashList.IndexOf(Pointer(AObject));
  1740. end;
  1741. function TFPHashObjectList.GetCount: integer;
  1742. begin
  1743. Result := FHashList.Count;
  1744. end;
  1745. function TFPHashObjectList.GetItem(Index: Integer): TObject;
  1746. begin
  1747. Result := TObject(FHashList[Index]);
  1748. end;
  1749. procedure TFPHashObjectList.SetItem(Index: Integer; AObject: TObject);
  1750. begin
  1751. if OwnsObjects then
  1752. TObject(FHashList[Index]).Free; // no nil needed
  1753. FHashList[index] := AObject;
  1754. end;
  1755. procedure TFPHashObjectList.SetCapacity(NewCapacity: Integer);
  1756. begin
  1757. FHashList.Capacity := NewCapacity;
  1758. end;
  1759. function TFPHashObjectList.GetCapacity: integer;
  1760. begin
  1761. Result := FHashList.Capacity;
  1762. end;
  1763. function TFPHashObjectList.Add(const AName:TSymStr;AObject: TObject): Integer;
  1764. begin
  1765. Result := FHashList.Add(AName,AObject);
  1766. end;
  1767. function TFPHashObjectList.NameOfIndex(Index: Integer): TSymStr;
  1768. begin
  1769. Result := FHashList.NameOfIndex(Index);
  1770. end;
  1771. function TFPHashObjectList.HashOfIndex(Index: Integer): LongWord;
  1772. begin
  1773. Result := FHashList.HashOfIndex(Index);
  1774. end;
  1775. function TFPHashObjectList.GetNextCollision(Index: Integer): Integer;
  1776. begin
  1777. Result := FHashList.GetNextCollision(Index);
  1778. end;
  1779. procedure TFPHashObjectList.Delete(Index: Integer);
  1780. begin
  1781. if OwnsObjects then
  1782. TObject(FHashList[Index]).Free; // no nil needed
  1783. FHashList.Delete(Index);
  1784. end;
  1785. function TFPHashObjectList.Extract(Item: TObject): TObject;
  1786. begin
  1787. Result := TObject(FHashList.Extract(Item));
  1788. end;
  1789. function TFPHashObjectList.Remove(AObject: TObject): Integer;
  1790. begin
  1791. Result := IndexOf(AObject);
  1792. if (Result <> -1) then
  1793. begin
  1794. if OwnsObjects then
  1795. TObject(FHashList[Result]).Free; // no nil needed
  1796. FHashList.Delete(Result);
  1797. end;
  1798. end;
  1799. function TFPHashObjectList.Find(const s:TSymStr): TObject;
  1800. begin
  1801. result:=TObject(FHashList.Find(s));
  1802. end;
  1803. function TFPHashObjectList.FindIndexOf(const s:TSymStr): Integer;
  1804. begin
  1805. result:=FHashList.FindIndexOf(s);
  1806. end;
  1807. function TFPHashObjectList.FindWithHash(const AName:TSymStr;AHash:LongWord): Pointer;
  1808. begin
  1809. Result:=TObject(FHashList.FindWithHash(AName,AHash));
  1810. end;
  1811. function TFPHashObjectList.Rename(const AOldName,ANewName:TSymStr): Integer;
  1812. begin
  1813. Result:=FHashList.Rename(AOldName,ANewName);
  1814. end;
  1815. function TFPHashObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
  1816. var
  1817. I : Integer;
  1818. begin
  1819. I:=AStartAt;
  1820. Result:=-1;
  1821. If AExact then
  1822. while (I<Count) and (Result=-1) do
  1823. If Items[i].ClassType=AClass then
  1824. Result:=I
  1825. else
  1826. Inc(I)
  1827. else
  1828. while (I<Count) and (Result=-1) do
  1829. If Items[i].InheritsFrom(AClass) then
  1830. Result:=I
  1831. else
  1832. Inc(I);
  1833. end;
  1834. procedure TFPHashObjectList.Pack;
  1835. begin
  1836. FHashList.Pack;
  1837. end;
  1838. procedure TFPHashObjectList.ShowStatistics;
  1839. begin
  1840. FHashList.ShowStatistics;
  1841. end;
  1842. procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  1843. begin
  1844. FHashList.ForEachCall(TListCallBack(proc2call),arg);
  1845. end;
  1846. procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  1847. begin
  1848. FHashList.ForEachCall(TListStaticCallBack(proc2call),arg);
  1849. end;
  1850. {*****************************************************************************
  1851. TFPHashObject
  1852. *****************************************************************************}
  1853. procedure TFPHashObject.InternalChangeOwner(HashObjectList:TFPHashObjectList;const s:TSymStr);
  1854. var
  1855. Index : SizeInt;
  1856. it : PViHashListItem;
  1857. begin
  1858. FOwner:=HashObjectList;
  1859. Index:=HashObjectList.Add(s,Self);
  1860. it:=HashObjectList.List.List+Index;
  1861. {$ifdef symansistr}
  1862. FStr:=s;
  1863. {$else}
  1864. FStr:=it^.Str;
  1865. {$endif}
  1866. FHash:=it^.HashValue;
  1867. end;
  1868. constructor TFPHashObject.CreateNotOwned;
  1869. {$ifndef symansistr}
  1870. const
  1871. EmptyString: string[1] = '';
  1872. {$endif}
  1873. begin
  1874. {$ifdef symansistr}
  1875. FStr:='';
  1876. {$else}
  1877. FStr:=@EmptyString;
  1878. {$endif}
  1879. int32(FHash):=-1;
  1880. end;
  1881. constructor TFPHashObject.Create(HashObjectList:TFPHashObjectList;const s:TSymStr);
  1882. begin
  1883. InternalChangeOwner(HashObjectList,s);
  1884. end;
  1885. procedure TFPHashObject.ChangeOwner(HashObjectList:TFPHashObjectList);
  1886. begin
  1887. InternalChangeOwner(HashObjectList, FStr {$ifndef symansistr} ^ {$endif});
  1888. end;
  1889. procedure TFPHashObject.ChangeOwnerAndName(HashObjectList:TFPHashObjectList;const s:TSymStr);
  1890. begin
  1891. InternalChangeOwner(HashObjectList,s);
  1892. end;
  1893. procedure TFPHashObject.Rename(const ANewName:TSymStr);
  1894. var
  1895. Index : integer;
  1896. it : PViHashListItem;
  1897. begin
  1898. Index:=FOwner.Rename(FStr {$ifndef symansistr} ^ {$endif},ANewName);
  1899. if Index>=0 then
  1900. begin
  1901. it:=FOwner.List.List+Index;
  1902. {$ifdef symansistr}
  1903. FStr:=ANewName;
  1904. {$else}
  1905. FStr:=it^.Str;
  1906. {$endif}
  1907. FHash:=it^.HashValue;
  1908. end;
  1909. end;
  1910. function TFPHashObject.GetName:TSymStr;
  1911. begin
  1912. Result:=FStr {$ifndef symansistr} ^ {$endif};
  1913. end;
  1914. function TFPHashObject.GetHash:Longword;
  1915. begin
  1916. Result:=FHash;
  1917. end;
  1918. {****************************************************************************
  1919. TLinkedListItem
  1920. ****************************************************************************}
  1921. constructor TLinkedListItem.Create;
  1922. begin
  1923. Previous:=nil;
  1924. Next:=nil;
  1925. end;
  1926. destructor TLinkedListItem.Destroy;
  1927. begin
  1928. end;
  1929. function TLinkedListItem.GetCopy:TLinkedListItem;
  1930. var
  1931. p : TLinkedListItem;
  1932. l : integer;
  1933. begin
  1934. p:=TLinkedListItemClass(ClassType).Create;
  1935. l:=InstanceSize;
  1936. Move(pointer(self)^,pointer(p)^,l);
  1937. Result:=p;
  1938. end;
  1939. {****************************************************************************
  1940. TLinkedList
  1941. ****************************************************************************}
  1942. constructor TLinkedList.Create;
  1943. begin
  1944. FFirst:=nil;
  1945. Flast:=nil;
  1946. FCount:=0;
  1947. FNoClear:=False;
  1948. end;
  1949. destructor TLinkedList.destroy;
  1950. begin
  1951. if not FNoClear then
  1952. Clear;
  1953. end;
  1954. function TLinkedList.empty:boolean;
  1955. begin
  1956. Empty:=(FFirst=nil);
  1957. end;
  1958. procedure TLinkedList.Insert(Item:TLinkedListItem);
  1959. begin
  1960. if FFirst=nil then
  1961. begin
  1962. FLast:=Item;
  1963. Item.Previous:=nil;
  1964. Item.Next:=nil;
  1965. end
  1966. else
  1967. begin
  1968. FFirst.Previous:=Item;
  1969. Item.Previous:=nil;
  1970. Item.Next:=FFirst;
  1971. end;
  1972. FFirst:=Item;
  1973. inc(FCount);
  1974. end;
  1975. procedure TLinkedList.InsertBefore(Item,Loc : TLinkedListItem);
  1976. begin
  1977. Item.Previous:=Loc.Previous;
  1978. Item.Next:=Loc;
  1979. Loc.Previous:=Item;
  1980. if assigned(Item.Previous) then
  1981. Item.Previous.Next:=Item
  1982. else
  1983. { if we've no next item, we've to adjust FFist }
  1984. FFirst:=Item;
  1985. inc(FCount);
  1986. end;
  1987. procedure TLinkedList.InsertAfter(Item,Loc : TLinkedListItem);
  1988. begin
  1989. Item.Next:=Loc.Next;
  1990. Loc.Next:=Item;
  1991. Item.Previous:=Loc;
  1992. if assigned(Item.Next) then
  1993. Item.Next.Previous:=Item
  1994. else
  1995. { if we've no next item, we've to adjust FLast }
  1996. FLast:=Item;
  1997. inc(FCount);
  1998. end;
  1999. procedure TLinkedList.Concat(Item:TLinkedListItem);
  2000. begin
  2001. if FFirst=nil then
  2002. begin
  2003. FFirst:=Item;
  2004. Item.Previous:=nil;
  2005. Item.Next:=nil;
  2006. end
  2007. else
  2008. begin
  2009. Flast.Next:=Item;
  2010. Item.Previous:=Flast;
  2011. Item.Next:=nil;
  2012. end;
  2013. Flast:=Item;
  2014. inc(FCount);
  2015. end;
  2016. procedure TLinkedList.remove(Item:TLinkedListItem);
  2017. begin
  2018. if Item=nil then
  2019. exit;
  2020. if (FFirst=Item) and (Flast=Item) then
  2021. begin
  2022. FFirst:=nil;
  2023. Flast:=nil;
  2024. end
  2025. else if FFirst=Item then
  2026. begin
  2027. FFirst:=Item.Next;
  2028. if assigned(FFirst) then
  2029. FFirst.Previous:=nil;
  2030. end
  2031. else if Flast=Item then
  2032. begin
  2033. Flast:=Flast.Previous;
  2034. if assigned(Flast) then
  2035. Flast.Next:=nil;
  2036. end
  2037. else
  2038. begin
  2039. Item.Previous.Next:=Item.Next;
  2040. Item.Next.Previous:=Item.Previous;
  2041. end;
  2042. Item.Next:=nil;
  2043. Item.Previous:=nil;
  2044. dec(FCount);
  2045. end;
  2046. procedure TLinkedList.clear;
  2047. var
  2048. NewNode, Next : TLinkedListItem;
  2049. begin
  2050. NewNode:=FFirst;
  2051. while assigned(NewNode) do
  2052. begin
  2053. Next:=NewNode.Next;
  2054. prefetch(pointer(Next)^);
  2055. NewNode.Free;
  2056. NewNode:=Next;
  2057. end;
  2058. FLast:=nil;
  2059. FFirst:=nil;
  2060. FCount:=0;
  2061. end;
  2062. function TLinkedList.GetFirst:TLinkedListItem;
  2063. begin
  2064. if FFirst=nil then
  2065. GetFirst:=nil
  2066. else
  2067. begin
  2068. GetFirst:=FFirst;
  2069. if FFirst=FLast then
  2070. FLast:=nil;
  2071. FFirst:=FFirst.Next;
  2072. dec(FCount);
  2073. end;
  2074. end;
  2075. function TLinkedList.GetLast:TLinkedListItem;
  2076. begin
  2077. if FLast=nil then
  2078. Getlast:=nil
  2079. else
  2080. begin
  2081. Getlast:=FLast;
  2082. if FLast=FFirst then
  2083. FFirst:=nil;
  2084. FLast:=FLast.Previous;
  2085. dec(FCount);
  2086. end;
  2087. end;
  2088. procedure TLinkedList.insertList(p : TLinkedList);
  2089. begin
  2090. { empty List ? }
  2091. if (p.FFirst=nil) then
  2092. exit;
  2093. p.Flast.Next:=FFirst;
  2094. { we have a double Linked List }
  2095. if assigned(FFirst) then
  2096. FFirst.Previous:=p.Flast;
  2097. FFirst:=p.FFirst;
  2098. if (FLast=nil) then
  2099. Flast:=p.Flast;
  2100. inc(FCount,p.FCount);
  2101. { p becomes empty }
  2102. p.FFirst:=nil;
  2103. p.Flast:=nil;
  2104. p.FCount:=0;
  2105. end;
  2106. procedure TLinkedList.insertListBefore(Item:TLinkedListItem;p : TLinkedList);
  2107. begin
  2108. { empty List ? }
  2109. if (p.FFirst=nil) then
  2110. exit;
  2111. if (Item=nil) then
  2112. begin
  2113. { Insert at begin }
  2114. InsertList(p);
  2115. exit;
  2116. end
  2117. else
  2118. begin
  2119. p.FLast.Next:=Item;
  2120. p.FFirst.Previous:=Item.Previous;
  2121. if assigned(Item.Previous) then
  2122. Item.Previous.Next:=p.FFirst
  2123. else
  2124. FFirst:=p.FFirst;
  2125. Item.Previous:=p.FLast;
  2126. inc(FCount,p.FCount);
  2127. end;
  2128. { p becomes empty }
  2129. p.FFirst:=nil;
  2130. p.Flast:=nil;
  2131. p.FCount:=0;
  2132. end;
  2133. procedure TLinkedList.insertListAfter(Item:TLinkedListItem;p : TLinkedList);
  2134. begin
  2135. { empty List ? }
  2136. if (p.FFirst=nil) then
  2137. exit;
  2138. if (Item=nil) then
  2139. begin
  2140. { Insert at begin }
  2141. InsertList(p);
  2142. exit;
  2143. end
  2144. else
  2145. begin
  2146. p.FFirst.Previous:=Item;
  2147. p.FLast.Next:=Item.Next;
  2148. if assigned(Item.Next) then
  2149. Item.Next.Previous:=p.FLast
  2150. else
  2151. FLast:=p.FLast;
  2152. Item.Next:=p.FFirst;
  2153. inc(FCount,p.FCount);
  2154. end;
  2155. { p becomes empty }
  2156. p.FFirst:=nil;
  2157. p.Flast:=nil;
  2158. p.FCount:=0;
  2159. end;
  2160. procedure TLinkedList.concatList(p : TLinkedList);
  2161. begin
  2162. if (p.FFirst=nil) then
  2163. exit;
  2164. if FFirst=nil then
  2165. FFirst:=p.FFirst
  2166. else
  2167. begin
  2168. FLast.Next:=p.FFirst;
  2169. p.FFirst.Previous:=Flast;
  2170. end;
  2171. Flast:=p.Flast;
  2172. inc(FCount,p.FCount);
  2173. { make p empty }
  2174. p.Flast:=nil;
  2175. p.FFirst:=nil;
  2176. p.FCount:=0;
  2177. end;
  2178. procedure TLinkedList.insertListcopy(p : TLinkedList);
  2179. var
  2180. NewNode,NewNode2 : TLinkedListItem;
  2181. begin
  2182. NewNode:=p.Last;
  2183. while assigned(NewNode) do
  2184. begin
  2185. NewNode2:=NewNode.Getcopy;
  2186. if assigned(NewNode2) then
  2187. Insert(NewNode2);
  2188. NewNode:=NewNode.Previous;
  2189. end;
  2190. end;
  2191. procedure TLinkedList.concatListcopy(p : TLinkedList);
  2192. var
  2193. NewNode,NewNode2 : TLinkedListItem;
  2194. begin
  2195. NewNode:=p.First;
  2196. while assigned(NewNode) do
  2197. begin
  2198. NewNode2:=NewNode.Getcopy;
  2199. if assigned(NewNode2) then
  2200. Concat(NewNode2);
  2201. NewNode:=NewNode.Next;
  2202. end;
  2203. end;
  2204. procedure TLinkedList.RemoveAll;
  2205. begin
  2206. FFirst:=nil;
  2207. FLast:=nil;
  2208. FCount:=0;
  2209. end;
  2210. {****************************************************************************
  2211. TCmdStrListItem
  2212. ****************************************************************************}
  2213. constructor TCmdStrListItem.Create(const s:TCmdStr);
  2214. begin
  2215. inherited Create;
  2216. FPStr:=s;
  2217. end;
  2218. destructor TCmdStrListItem.Destroy;
  2219. begin
  2220. FPStr:='';
  2221. end;
  2222. function TCmdStrListItem.GetCopy:TLinkedListItem;
  2223. begin
  2224. Result:=(inherited GetCopy);
  2225. { TLinkedListItem.GetCopy performs a "move" to copy all data -> reinit
  2226. the ansistring, so the refcount is properly increased }
  2227. Initialize(TCmdStrListItem(Result).FPStr);
  2228. TCmdStrListItem(Result).FPStr:=FPstr;
  2229. end;
  2230. {****************************************************************************
  2231. TCmdStrList
  2232. ****************************************************************************}
  2233. constructor TCmdStrList.Create;
  2234. begin
  2235. inherited Create;
  2236. FDoubles:=true;
  2237. end;
  2238. constructor TCmdStrList.Create_no_double;
  2239. begin
  2240. inherited Create;
  2241. FDoubles:=false;
  2242. end;
  2243. procedure TCmdStrList.insert(const s : TCmdStr);
  2244. begin
  2245. if (s='') or
  2246. ((not FDoubles) and (findcase(s)<>nil)) then
  2247. exit;
  2248. inherited insert(TCmdStrListItem.create(s));
  2249. end;
  2250. procedure TCmdStrList.concat(const s : TCmdStr);
  2251. begin
  2252. if (s='') or
  2253. ((not FDoubles) and (findcase(s)<>nil)) then
  2254. exit;
  2255. inherited concat(TCmdStrListItem.create(s));
  2256. end;
  2257. procedure TCmdStrList.remove(const s : TCmdStr);
  2258. var
  2259. p : TCmdStrListItem;
  2260. begin
  2261. if s='' then
  2262. exit;
  2263. p:=findcase(s);
  2264. if assigned(p) then
  2265. begin
  2266. inherited Remove(p);
  2267. p.Free;
  2268. p := nil;
  2269. end;
  2270. end;
  2271. function TCmdStrList.GetFirst : TCmdStr;
  2272. var
  2273. p : TCmdStrListItem;
  2274. begin
  2275. p:=TCmdStrListItem(inherited GetFirst);
  2276. if p=nil then
  2277. GetFirst:=''
  2278. else
  2279. begin
  2280. GetFirst:=p.FPStr;
  2281. p.free;
  2282. p := nil;
  2283. end;
  2284. end;
  2285. function TCmdStrList.Getlast : TCmdStr;
  2286. var
  2287. p : TCmdStrListItem;
  2288. begin
  2289. p:=TCmdStrListItem(inherited Getlast);
  2290. if p=nil then
  2291. Getlast:=''
  2292. else
  2293. begin
  2294. Getlast:=p.FPStr;
  2295. p.free;
  2296. p := nil;
  2297. end;
  2298. end;
  2299. function TCmdStrList.FindCase(const s:TCmdStr):TCmdStrListItem;
  2300. var
  2301. NewNode : TCmdStrListItem;
  2302. begin
  2303. result:=nil;
  2304. if s='' then
  2305. exit;
  2306. NewNode:=TCmdStrListItem(FFirst);
  2307. while assigned(NewNode) do
  2308. begin
  2309. if NewNode.FPStr=s then
  2310. begin
  2311. result:=NewNode;
  2312. exit;
  2313. end;
  2314. NewNode:=TCmdStrListItem(NewNode.Next);
  2315. end;
  2316. end;
  2317. function TCmdStrList.Find(const s:TCmdStr):TCmdStrListItem;
  2318. var
  2319. NewNode : TCmdStrListItem;
  2320. begin
  2321. result:=nil;
  2322. if s='' then
  2323. exit;
  2324. NewNode:=TCmdStrListItem(FFirst);
  2325. while assigned(NewNode) do
  2326. begin
  2327. if SysUtils.CompareText(s, NewNode.FPStr)=0 then
  2328. begin
  2329. result:=NewNode;
  2330. exit;
  2331. end;
  2332. NewNode:=TCmdStrListItem(NewNode.Next);
  2333. end;
  2334. end;
  2335. procedure TCmdStrList.InsertItem(item:TCmdStrListItem);
  2336. begin
  2337. inherited Insert(item);
  2338. end;
  2339. procedure TCmdStrList.ConcatItem(item:TCmdStrListItem);
  2340. begin
  2341. inherited Concat(item);
  2342. end;
  2343. {****************************************************************************
  2344. tdynamicarray
  2345. ****************************************************************************}
  2346. constructor tdynamicarray.create(Ablocksize:longword);
  2347. begin
  2348. FPosn:=0;
  2349. FPosnblock:=nil;
  2350. FFirstblock:=nil;
  2351. FLastblock:=nil;
  2352. FCurrBlockSize:=0;
  2353. { Every block needs at least a header and alignment slack,
  2354. therefore its size cannot be arbitrarily small. However,
  2355. the blocksize argument is often confused with data size.
  2356. See e.g. Mantis #20929. }
  2357. if Ablocksize<mindynamicblocksize then
  2358. Ablocksize:=mindynamicblocksize;
  2359. FMaxBlockSize:=Ablocksize;
  2360. grow;
  2361. end;
  2362. destructor tdynamicarray.destroy;
  2363. var
  2364. hp : pdynamicblock;
  2365. begin
  2366. while assigned(FFirstblock) do
  2367. begin
  2368. hp:=FFirstblock;
  2369. FFirstblock:=FFirstblock^.Next;
  2370. Freemem(hp);
  2371. end;
  2372. end;
  2373. function tdynamicarray.size:longword;
  2374. begin
  2375. if assigned(FLastblock) then
  2376. size:=FLastblock^.pos+FLastblock^.used
  2377. else
  2378. size:=0;
  2379. end;
  2380. procedure tdynamicarray.reset;
  2381. var
  2382. hp : pdynamicblock;
  2383. begin
  2384. while assigned(FFirstblock) do
  2385. begin
  2386. hp:=FFirstblock;
  2387. FFirstblock:=FFirstblock^.Next;
  2388. Freemem(hp);
  2389. end;
  2390. FPosn:=0;
  2391. FPosnblock:=nil;
  2392. FFirstblock:=nil;
  2393. FLastblock:=nil;
  2394. grow;
  2395. end;
  2396. procedure tdynamicarray.grow;
  2397. var
  2398. nblock : pdynamicblock;
  2399. OptBlockSize,
  2400. IncSize : integer;
  2401. begin
  2402. if CurrBlockSize<FMaxBlocksize then
  2403. begin
  2404. IncSize := mindynamicblocksize;
  2405. if FCurrBlockSize > 255 then
  2406. Inc(IncSize, FCurrBlockSize shr 2);
  2407. inc(FCurrBlockSize,IncSize);
  2408. end;
  2409. if CurrBlockSize>FMaxBlocksize then
  2410. FCurrBlockSize:=FMaxBlocksize;
  2411. { Calculate the most optimal size so there is no alignment overhead
  2412. lost in the heap manager }
  2413. OptBlockSize:=cutils.Align(CurrBlockSize+dynamicblockbasesize,16)-dynamicblockbasesize-sizeof(ptrint);
  2414. Getmem(nblock,OptBlockSize+dynamicblockbasesize);
  2415. if not assigned(FFirstblock) then
  2416. begin
  2417. FFirstblock:=nblock;
  2418. FPosnblock:=nblock;
  2419. nblock^.pos:=0;
  2420. end
  2421. else
  2422. begin
  2423. FLastblock^.Next:=nblock;
  2424. nblock^.pos:=FLastblock^.pos+FLastblock^.size;
  2425. end;
  2426. nblock^.used:=0;
  2427. nblock^.size:=OptBlockSize;
  2428. nblock^.Next:=nil;
  2429. fillchar(nblock^.data,nblock^.size,0);
  2430. FLastblock:=nblock;
  2431. end;
  2432. procedure tdynamicarray.align(i:longword);
  2433. var
  2434. j : longword;
  2435. begin
  2436. j:=(FPosn mod i);
  2437. if j<>0 then
  2438. begin
  2439. j:=i-j;
  2440. if FPosnblock^.used+j>FPosnblock^.size then
  2441. begin
  2442. dec(j,FPosnblock^.size-FPosnblock^.used);
  2443. FPosnblock^.used:=FPosnblock^.size;
  2444. grow;
  2445. FPosnblock:=FLastblock;
  2446. end;
  2447. inc(FPosnblock^.used,j);
  2448. inc(FPosn,j);
  2449. end;
  2450. end;
  2451. procedure tdynamicarray.seek(i:longword);
  2452. begin
  2453. if (i<FPosnblock^.pos) or (i>=FPosnblock^.pos+FPosnblock^.size) then
  2454. begin
  2455. { set FPosnblock correct if the size is bigger then
  2456. the current block }
  2457. if FPosnblock^.pos>i then
  2458. FPosnblock:=FFirstblock;
  2459. while assigned(FPosnblock) do
  2460. begin
  2461. if FPosnblock^.pos+FPosnblock^.size>i then
  2462. break;
  2463. FPosnblock:=FPosnblock^.Next;
  2464. end;
  2465. { not found ? then increase blocks }
  2466. if not assigned(FPosnblock) then
  2467. begin
  2468. repeat
  2469. { the current FLastblock is now also fully used }
  2470. FLastblock^.used:=FLastblock^.size;
  2471. grow;
  2472. FPosnblock:=FLastblock;
  2473. until FPosnblock^.pos+FPosnblock^.size>=i;
  2474. end;
  2475. end;
  2476. FPosn:=i;
  2477. if FPosn-FPosnblock^.pos>FPosnblock^.used then
  2478. FPosnblock^.used:=FPosn-FPosnblock^.pos;
  2479. end;
  2480. procedure tdynamicarray.write(const d;len:longword);
  2481. var
  2482. p : pchar;
  2483. i,j : longword;
  2484. begin
  2485. p:=pchar(@d);
  2486. while (len>0) do
  2487. begin
  2488. i:=FPosn-FPosnblock^.pos;
  2489. if i+len>=FPosnblock^.size then
  2490. begin
  2491. j:=FPosnblock^.size-i;
  2492. move(p^,FPosnblock^.data[i],j);
  2493. inc(p,j);
  2494. inc(FPosn,j);
  2495. dec(len,j);
  2496. FPosnblock^.used:=FPosnblock^.size;
  2497. if assigned(FPosnblock^.Next) then
  2498. FPosnblock:=FPosnblock^.Next
  2499. else
  2500. begin
  2501. grow;
  2502. FPosnblock:=FLastblock;
  2503. end;
  2504. end
  2505. else
  2506. begin
  2507. move(p^,FPosnblock^.data[i],len);
  2508. inc(p,len);
  2509. inc(FPosn,len);
  2510. i:=FPosn-FPosnblock^.pos;
  2511. if i>FPosnblock^.used then
  2512. FPosnblock^.used:=i;
  2513. len:=0;
  2514. end;
  2515. end;
  2516. end;
  2517. procedure tdynamicarray.writestr(const s:string);
  2518. begin
  2519. write(s[1],length(s));
  2520. end;
  2521. function tdynamicarray.read(var d;len:longword):longword;
  2522. var
  2523. p : pchar;
  2524. i,j,res : longword;
  2525. begin
  2526. res:=0;
  2527. p:=pchar(@d);
  2528. while (len>0) do
  2529. begin
  2530. i:=FPosn-FPosnblock^.pos;
  2531. if i+len>=FPosnblock^.used then
  2532. begin
  2533. j:=FPosnblock^.used-i;
  2534. move(FPosnblock^.data[i],p^,j);
  2535. inc(p,j);
  2536. inc(FPosn,j);
  2537. inc(res,j);
  2538. dec(len,j);
  2539. if assigned(FPosnblock^.Next) then
  2540. FPosnblock:=FPosnblock^.Next
  2541. else
  2542. break;
  2543. end
  2544. else
  2545. begin
  2546. move(FPosnblock^.data[i],p^,len);
  2547. inc(p,len);
  2548. inc(FPosn,len);
  2549. inc(res,len);
  2550. len:=0;
  2551. end;
  2552. end;
  2553. read:=res;
  2554. end;
  2555. procedure tdynamicarray.readstream(f:TCStream;maxlen:longword);
  2556. var
  2557. i,left : longword;
  2558. begin
  2559. repeat
  2560. left:=FPosnblock^.size-FPosnblock^.used;
  2561. if left>maxlen then
  2562. left:=maxlen;
  2563. i:=f.Read(FPosnblock^.data[FPosnblock^.used],left);
  2564. dec(maxlen,i);
  2565. inc(FPosnblock^.used,i);
  2566. if FPosnblock^.used=FPosnblock^.size then
  2567. begin
  2568. if assigned(FPosnblock^.Next) then
  2569. FPosnblock:=FPosnblock^.Next
  2570. else
  2571. begin
  2572. grow;
  2573. FPosnblock:=FLastblock;
  2574. end;
  2575. end;
  2576. until (i<left) or (maxlen=0);
  2577. end;
  2578. procedure tdynamicarray.writestream(f:TCStream);
  2579. var
  2580. hp : pdynamicblock;
  2581. begin
  2582. hp:=FFirstblock;
  2583. while assigned(hp) do
  2584. begin
  2585. f.Write(hp^.data,hp^.used);
  2586. hp:=hp^.Next;
  2587. end;
  2588. end;
  2589. function tdynamicarray.equal(other:tdynamicarray):boolean;
  2590. var
  2591. ofsthis,
  2592. ofsother,
  2593. remthis,
  2594. remother,
  2595. len : sizeint;
  2596. blockthis,
  2597. blockother : pdynamicblock;
  2598. begin
  2599. if not assigned(other) then
  2600. exit(false);
  2601. if size<>other.size then
  2602. exit(false);
  2603. blockthis:=Firstblock;
  2604. blockother:=other.FirstBlock;
  2605. ofsthis:=0;
  2606. ofsother:=0;
  2607. while assigned(blockthis) and assigned(blockother) do
  2608. begin
  2609. remthis:=blockthis^.used-ofsthis;
  2610. remother:=blockother^.used-ofsother;
  2611. len:=min(remthis,remother);
  2612. if not CompareMem(@blockthis^.data[ofsthis],@blockother^.data[ofsother],len) then
  2613. exit(false);
  2614. inc(ofsthis,len);
  2615. inc(ofsother,len);
  2616. if ofsthis=blockthis^.used then
  2617. begin
  2618. blockthis:=blockthis^.next;
  2619. ofsthis:=0;
  2620. end;
  2621. if ofsother=blockother^.used then
  2622. begin
  2623. blockother:=blockother^.next;
  2624. ofsother:=0;
  2625. end;
  2626. end;
  2627. if assigned(blockthis) and not assigned(blockother) then
  2628. result:=blockthis^.used=0
  2629. else if assigned(blockother) and not assigned(blockthis) then
  2630. result:=blockother^.used=0
  2631. else
  2632. result:=true;
  2633. end;
  2634. {****************************************************************************
  2635. thashset
  2636. ****************************************************************************}
  2637. constructor THashSet.Create(InitSize: Integer; OwnKeys, OwnObjects: Boolean);
  2638. var
  2639. I: Integer;
  2640. begin
  2641. inherited Create;
  2642. FOwnsObjects := OwnObjects;
  2643. FOwnsKeys := OwnKeys;
  2644. I := 64;
  2645. while I < InitSize do I := I shl 1;
  2646. FBucketCount := I;
  2647. FBucket := AllocMem(I * sizeof(PHashSetItem));
  2648. end;
  2649. destructor THashSet.Destroy;
  2650. begin
  2651. Clear;
  2652. FreeMem(FBucket);
  2653. inherited Destroy;
  2654. end;
  2655. procedure THashSet.Clear;
  2656. var
  2657. I: Integer;
  2658. item, next: PHashSetItem;
  2659. begin
  2660. for I := 0 to FBucketCount-1 do
  2661. begin
  2662. item := FBucket[I];
  2663. while Assigned(item) do
  2664. begin
  2665. next := item^.Next;
  2666. if FOwnsObjects then
  2667. FreeAndNil(item^.Data);
  2668. FreeItem(item);
  2669. item := next;
  2670. end;
  2671. end;
  2672. FillChar(FBucket^, FBucketCount * sizeof(PHashSetItem), 0);
  2673. end;
  2674. function THashSet.Find(Key: Pointer; KeyLen: Integer): PHashSetItem;
  2675. var
  2676. Dummy: Boolean;
  2677. begin
  2678. Result := Lookup(Key, KeyLen, Dummy, False);
  2679. end;
  2680. function THashSet.FindOrAdd(Key: Pointer; KeyLen: Integer;
  2681. var Found: Boolean): PHashSetItem;
  2682. begin
  2683. Result := Lookup(Key, KeyLen, Found, True);
  2684. end;
  2685. function THashSet.FindOrAdd(Key: Pointer; KeyLen: Integer): PHashSetItem;
  2686. var
  2687. Dummy: Boolean;
  2688. begin
  2689. Result := Lookup(Key, KeyLen, Dummy, True);
  2690. end;
  2691. function THashSet.Get(Key: Pointer; KeyLen: Integer): TObject;
  2692. var
  2693. e: PHashSetItem;
  2694. Dummy: Boolean;
  2695. begin
  2696. e := Lookup(Key, KeyLen, Dummy, False);
  2697. if Assigned(e) then
  2698. Result := e^.Data
  2699. else
  2700. Result := nil;
  2701. end;
  2702. function THashSet.Lookup(Key: Pointer; KeyLen: Integer;
  2703. var Found: Boolean; CanCreate: Boolean): PHashSetItem;
  2704. var
  2705. EntryPtr: PPHashSetItem;
  2706. Entry: PHashSetItem;
  2707. h: LongWord;
  2708. begin
  2709. h := FPHash(Key, KeyLen);
  2710. EntryPtr := @FBucket[h and (FBucketCount-1)];
  2711. Entry := EntryPtr^;
  2712. while Assigned(Entry) and
  2713. not ((Entry^.HashValue = h) and (Entry^.KeyLength = KeyLen) and
  2714. (CompareByte(Entry^.Key^, Key^, KeyLen) = 0)) do
  2715. begin
  2716. EntryPtr := @Entry^.Next;
  2717. Entry := EntryPtr^;
  2718. end;
  2719. Found := Assigned(Entry);
  2720. if Found or (not CanCreate) then
  2721. begin
  2722. Result := Entry;
  2723. Exit;
  2724. end;
  2725. if FCount > FBucketCount then { arbitrary limit, probably too high }
  2726. begin
  2727. { rehash and repeat search }
  2728. Resize(FBucketCount * 2);
  2729. Result := Lookup(Key, KeyLen, Found, CanCreate);
  2730. end
  2731. else
  2732. begin
  2733. Result := CreateItem(Key, KeyLen, h);
  2734. Inc(FCount);
  2735. EntryPtr^ := Result;
  2736. end;
  2737. end;
  2738. procedure THashSet.Resize(NewCapacity: LongWord);
  2739. var
  2740. p, chain: PPHashSetItem;
  2741. i: Integer;
  2742. e, n: PHashSetItem;
  2743. begin
  2744. p := AllocMem(NewCapacity * SizeOf(PHashSetItem));
  2745. for i := 0 to FBucketCount-1 do
  2746. begin
  2747. e := FBucket[i];
  2748. while Assigned(e) do
  2749. begin
  2750. chain := @p[e^.HashValue and (NewCapacity-1)];
  2751. n := e^.Next;
  2752. e^.Next := chain^;
  2753. chain^ := e;
  2754. e := n;
  2755. end;
  2756. end;
  2757. FBucketCount := NewCapacity;
  2758. FreeMem(FBucket);
  2759. FBucket := p;
  2760. end;
  2761. class procedure THashSet.FreeItem(item: PHashSetItem);
  2762. begin
  2763. Dispose(item);
  2764. end;
  2765. class function THashSet.SizeOfItem: Integer;
  2766. begin
  2767. Result := SizeOf(THashSetItem);
  2768. end;
  2769. function THashSet.CreateItem(Key: Pointer; KeyLen: Integer; HashValue: LongWord): PHashSetItem;
  2770. var
  2771. itemSize, keyOfs: SizeUint;
  2772. begin
  2773. itemSize := SizeOfItem;
  2774. if FOwnsKeys then
  2775. begin
  2776. keyOfs := itemSize;
  2777. Result := GetMem(keyOfs + SizeUint(KeyLen));
  2778. Result^.Key := Pointer(Result) + keyOfs;
  2779. Move(Key^, Result^.Key^, KeyLen);
  2780. end
  2781. else
  2782. begin
  2783. Result := GetMem(itemSize);
  2784. Result^.Key := Key;
  2785. end;
  2786. Result^.Next := nil;
  2787. Result^.KeyLength := KeyLen;
  2788. Result^.HashValue := HashValue;
  2789. Result^.Data := nil;
  2790. end;
  2791. function THashSet.Remove(Entry: PHashSetItem): Boolean;
  2792. var
  2793. chain: PPHashSetItem;
  2794. begin
  2795. chain := @FBucket[Entry^.HashValue mod FBucketCount];
  2796. while Assigned(chain^) do
  2797. begin
  2798. if chain^ = Entry then
  2799. begin
  2800. chain^ := Entry^.Next;
  2801. if FOwnsObjects then
  2802. FreeAndNil(Entry^.Data);
  2803. FreeItem(Entry);
  2804. Dec(FCount);
  2805. Result := True;
  2806. Exit;
  2807. end;
  2808. chain := @chain^^.Next;
  2809. end;
  2810. Result := False;
  2811. end;
  2812. {****************************************************************************
  2813. ttaghashset
  2814. ****************************************************************************}
  2815. function TTagHashSet.Lookup(Key: Pointer; KeyLen: Integer;
  2816. Tag: LongWord; var Found: Boolean; CanCreate: Boolean): PTagHashSetItem;
  2817. var
  2818. EntryPtr: PPTagHashSetItem;
  2819. Entry: PTagHashSetItem;
  2820. h: LongWord;
  2821. begin
  2822. h := FPHash(Key, KeyLen, Tag);
  2823. EntryPtr := @PPTagHashSetItem(FBucket)[h and (FBucketCount-1)];
  2824. Entry := EntryPtr^;
  2825. while Assigned(Entry) and
  2826. not ((Entry^.Item.HashValue = h) and (Entry^.Item.KeyLength = KeyLen) and
  2827. (Entry^.Tag = Tag) and (CompareByte(Entry^.Item.Key^, Key^, KeyLen) = 0)) do
  2828. begin
  2829. EntryPtr := @Entry^.Item.Next;
  2830. Entry := EntryPtr^;
  2831. end;
  2832. Found := Assigned(Entry);
  2833. if Found or (not CanCreate) then
  2834. begin
  2835. Result := Entry;
  2836. Exit;
  2837. end;
  2838. if FCount > FBucketCount then { arbitrary limit, probably too high }
  2839. begin
  2840. { rehash and repeat search }
  2841. Resize(FBucketCount * 2);
  2842. Result := Lookup(Key, KeyLen, Tag, Found, CanCreate);
  2843. end
  2844. else
  2845. begin
  2846. Result := PTagHashSetItem(CreateItem(Key, KeyLen, h));
  2847. Result^.Tag := Tag;
  2848. Inc(FCount);
  2849. EntryPtr^ := Result;
  2850. end;
  2851. end;
  2852. class function TTagHashSet.SizeOfItem: Integer;
  2853. begin
  2854. Result := SizeOf(TTagHashSetItem);
  2855. end;
  2856. function TTagHashSet.Find(Key: Pointer; KeyLen: Integer; Tag: LongWord): PTagHashSetItem;
  2857. var
  2858. Dummy: Boolean;
  2859. begin
  2860. Result := Lookup(Key, KeyLen, Tag, Dummy, False);
  2861. end;
  2862. function TTagHashSet.FindOrAdd(Key: Pointer; KeyLen: Integer; Tag: LongWord;
  2863. var Found: Boolean): PTagHashSetItem;
  2864. begin
  2865. Result := Lookup(Key, KeyLen, Tag, Found, True);
  2866. end;
  2867. function TTagHashSet.FindOrAdd(Key: Pointer; KeyLen: Integer; Tag: LongWord): PTagHashSetItem;
  2868. var
  2869. Dummy: Boolean;
  2870. begin
  2871. Result := Lookup(Key, KeyLen, Tag, Dummy, True);
  2872. end;
  2873. function TTagHashSet.Get(Key: Pointer; KeyLen: Integer; Tag: LongWord): TObject;
  2874. var
  2875. e: PTagHashSetItem;
  2876. Dummy: Boolean;
  2877. begin
  2878. e := Lookup(Key, KeyLen, Tag, Dummy, False);
  2879. if Assigned(e) then
  2880. Result := e^.Item.Data
  2881. else
  2882. Result := nil;
  2883. end;
  2884. {****************************************************************************
  2885. tbitset
  2886. ****************************************************************************}
  2887. function tbitset.getdatasize: longint;
  2888. begin
  2889. result:=length(fdata);
  2890. end;
  2891. constructor tbitset.create(initsize: longint);
  2892. begin
  2893. create_bytesize((initsize+7) div 8);
  2894. end;
  2895. constructor tbitset.create_bytesize(bytesize: longint);
  2896. begin
  2897. setLength(fdata,bytesize);
  2898. clear;
  2899. end;
  2900. destructor tbitset.destroy;
  2901. begin
  2902. fdata:=Nil;
  2903. inherited destroy;
  2904. end;
  2905. procedure tbitset.clear;
  2906. begin
  2907. if assigned(fdata) then
  2908. fillchar(fdata[0],length(fdata),0);
  2909. end;
  2910. procedure tbitset.grow(nsize: longint);
  2911. begin
  2912. setlength(fdata,nsize);
  2913. end;
  2914. procedure tbitset.include(index: longint);
  2915. var
  2916. dataindex: longint;
  2917. begin
  2918. { don't use bitpacked array, not endian-safe }
  2919. dataindex:=index shr 3;
  2920. if (dataindex>=datasize) then
  2921. grow(dataindex+16);
  2922. fdata[dataindex]:=fdata[dataindex] or (1 shl (index and 7));
  2923. end;
  2924. procedure tbitset.exclude(index: longint);
  2925. var
  2926. dataindex: longint;
  2927. begin
  2928. dataindex:=index shr 3;
  2929. if (dataindex>=datasize) then
  2930. exit;
  2931. fdata[dataindex]:=fdata[dataindex] and not(1 shl (index and 7));
  2932. end;
  2933. function tbitset.isset(index: longint): boolean;
  2934. var
  2935. dataindex: longint;
  2936. begin
  2937. dataindex:=index shr 3;
  2938. result:=
  2939. (dataindex<datasize) and
  2940. (((fdata[dataindex] shr (index and 7)) and 1)<>0);
  2941. end;
  2942. procedure tbitset.addset(aset: tbitset);
  2943. var
  2944. i: longint;
  2945. begin
  2946. if (aset.datasize>datasize) then
  2947. grow(aset.datasize);
  2948. for i:=0 to aset.datasize-1 do
  2949. fdata[i]:=fdata[i] or aset.data[i];
  2950. end;
  2951. procedure tbitset.subset(aset: tbitset);
  2952. var
  2953. i: longint;
  2954. begin
  2955. for i:=0 to min(datasize,aset.datasize)-1 do
  2956. fdata[i]:=fdata[i] and not(aset.data[i]);
  2957. end;
  2958. end.