cclasses.pas 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279
  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. interface
  20. uses
  21. SysUtils,
  22. CUtils,CStreams;
  23. {********************************************
  24. TMemDebug
  25. ********************************************}
  26. type
  27. tmemdebug = class
  28. private
  29. totalmem,
  30. startmem : integer;
  31. infostr : string[40];
  32. public
  33. constructor Create(const s:string);
  34. destructor Destroy;override;
  35. procedure show;
  36. procedure start;
  37. procedure stop;
  38. end;
  39. {*******************************************************
  40. TFPList (From rtl/objpas/classes/classesh.inc)
  41. ********************************************************}
  42. const
  43. SListIndexError = 'List index exceeds bounds (%d)';
  44. SListCapacityError = 'The maximum list capacity is reached (%d)';
  45. SListCountError = 'List count too large (%d)';
  46. type
  47. EListError = class(Exception);
  48. const
  49. MaxListSize = Maxint div 16;
  50. type
  51. PPointerList = ^TPointerList;
  52. TPointerList = array[0..MaxListSize - 1] of Pointer;
  53. TListSortCompare = function (Item1, Item2: Pointer): Integer;
  54. TListCallback = procedure(data,arg:pointer) of object;
  55. TListStaticCallback = procedure(data,arg:pointer);
  56. TFPList = class(TObject)
  57. private
  58. FList: PPointerList;
  59. FCount: Integer;
  60. FCapacity: Integer;
  61. protected
  62. function Get(Index: Integer): Pointer; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  63. procedure Put(Index: Integer; Item: Pointer); {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  64. procedure SetCapacity(NewCapacity: Integer);
  65. procedure SetCount(NewCount: Integer);
  66. Procedure RaiseIndexError(Index : Integer);
  67. public
  68. destructor Destroy; override;
  69. function Add(Item: Pointer): Integer; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  70. procedure Clear;
  71. procedure Delete(Index: Integer); {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  72. class procedure Error(const Msg: string; Data: PtrInt);
  73. procedure Exchange(Index1, Index2: Integer);
  74. function Expand: TFPList; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  75. function Extract(item: Pointer): Pointer;
  76. function First: Pointer;
  77. function IndexOf(Item: Pointer): Integer;
  78. procedure Insert(Index: Integer; Item: Pointer); {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  79. function Last: Pointer;
  80. procedure Move(CurIndex, NewIndex: Integer);
  81. procedure Assign(Obj:TFPList);
  82. function Remove(Item: Pointer): Integer;
  83. procedure Pack;
  84. procedure Sort(Compare: TListSortCompare);
  85. procedure ForEachCall(proc2call:TListCallback;arg:pointer);
  86. procedure ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  87. property Capacity: Integer read FCapacity write SetCapacity;
  88. property Count: Integer read FCount write SetCount;
  89. property Items[Index: Integer]: Pointer read Get write Put; default;
  90. property List: PPointerList read FList;
  91. end;
  92. {*******************************************************
  93. TFPObjectList (From fcl/inc/contnrs.pp)
  94. ********************************************************}
  95. TObjectListCallback = procedure(data:TObject;arg:pointer) of object;
  96. TObjectListStaticCallback = procedure(data:TObject;arg:pointer);
  97. TFPObjectList = class(TObject)
  98. private
  99. FFreeObjects : Boolean;
  100. FList: TFPList;
  101. function GetCount: integer;
  102. procedure SetCount(const AValue: integer);
  103. protected
  104. function GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
  105. procedure SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  106. procedure SetCapacity(NewCapacity: Integer);
  107. function GetCapacity: integer;
  108. public
  109. constructor Create;
  110. constructor Create(FreeObjects : Boolean);
  111. destructor Destroy; override;
  112. procedure Clear;
  113. function Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
  114. procedure Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
  115. procedure Exchange(Index1, Index2: Integer);
  116. function Expand: TFPObjectList;
  117. function Extract(Item: TObject): TObject;
  118. function Remove(AObject: TObject): Integer;
  119. function IndexOf(AObject: TObject): Integer;
  120. function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
  121. procedure Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  122. function First: TObject;
  123. function Last: TObject;
  124. procedure Move(CurIndex, NewIndex: Integer);
  125. procedure Assign(Obj:TFPObjectList);
  126. procedure Pack;
  127. procedure Sort(Compare: TListSortCompare);
  128. procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  129. procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  130. property Capacity: Integer read GetCapacity write SetCapacity;
  131. property Count: Integer read GetCount write SetCount;
  132. property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
  133. property Items[Index: Integer]: TObject read GetItem write SetItem; default;
  134. property List: TFPList read FList;
  135. end;
  136. type
  137. THashItem=record
  138. HashValue : LongWord;
  139. StrIndex : Integer;
  140. NextIndex : Integer;
  141. Data : Pointer;
  142. end;
  143. PHashItem=^THashItem;
  144. const
  145. MaxHashListSize = Maxint div 16;
  146. MaxHashStrSize = Maxint;
  147. MaxHashTableSize = Maxint div 4;
  148. MaxItemsPerHash = 3;
  149. type
  150. PHashItemList = ^THashItemList;
  151. THashItemList = array[0..MaxHashListSize - 1] of THashItem;
  152. PHashTable = ^THashTable;
  153. THashTable = array[0..MaxHashTableSize - 1] of Integer;
  154. TFPHashList = class(TObject)
  155. private
  156. { ItemList }
  157. FHashList : PHashItemList;
  158. FCount,
  159. FCapacity : Integer;
  160. { Hash }
  161. FHashTable : PHashTable;
  162. FHashCapacity : Integer;
  163. { Strings }
  164. FStrs : PChar;
  165. FStrCount,
  166. FStrCapacity : Integer;
  167. protected
  168. function Get(Index: Integer): Pointer;
  169. procedure SetCapacity(NewCapacity: Integer);
  170. procedure SetCount(NewCount: Integer);
  171. Procedure RaiseIndexError(Index : Integer);
  172. function AddStr(const s:string): Integer;
  173. procedure AddToHashTable(Index: Integer);
  174. procedure StrExpand(MinIncSize:Integer);
  175. procedure SetStrCapacity(NewCapacity: Integer);
  176. procedure SetHashCapacity(NewCapacity: Integer);
  177. procedure ReHash;
  178. public
  179. constructor Create;
  180. destructor Destroy; override;
  181. function Add(const AName:string;Item: Pointer): Integer;
  182. procedure Clear;
  183. function NameOfIndex(Index: Integer): String;
  184. procedure Delete(Index: Integer);
  185. class procedure Error(const Msg: string; Data: PtrInt);
  186. function Expand: TFPHashList;
  187. function Extract(item: Pointer): Pointer;
  188. function IndexOf(Item: Pointer): Integer;
  189. function Find(const s:string): Pointer;
  190. function Remove(Item: Pointer): Integer;
  191. procedure Pack;
  192. procedure ShowStatistics;
  193. procedure ForEachCall(proc2call:TListCallback;arg:pointer);
  194. procedure ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  195. property Capacity: Integer read FCapacity write SetCapacity;
  196. property Count: Integer read FCount write SetCount;
  197. property Items[Index: Integer]: Pointer read Get; default;
  198. property List: PHashItemList read FHashList;
  199. property Strs: PChar read FStrs;
  200. end;
  201. {*******************************************************
  202. TFPHashObjectList (From fcl/inc/contnrs.pp)
  203. ********************************************************}
  204. TFPHashObjectList = class;
  205. TFPHashObject = class
  206. private
  207. FOwner : TFPHashObjectList;
  208. FStrIndex : Integer;
  209. protected
  210. function GetName:string;
  211. public
  212. constructor Create(HashObjectList:TFPHashObjectList;const s:string);
  213. property Name:string read GetName;
  214. end;
  215. TFPHashObjectList = class(TObject)
  216. private
  217. FFreeObjects : Boolean;
  218. FHashList: TFPHashList;
  219. function GetCount: integer;
  220. procedure SetCount(const AValue: integer);
  221. protected
  222. function GetItem(Index: Integer): TObject;
  223. procedure SetCapacity(NewCapacity: Integer);
  224. function GetCapacity: integer;
  225. public
  226. constructor Create(FreeObjects : boolean = True);
  227. destructor Destroy; override;
  228. procedure Clear;
  229. function Add(const AName:string;AObject: TObject): Integer;
  230. function NameOfIndex(Index: Integer): String;
  231. procedure Delete(Index: Integer);
  232. function Expand: TFPHashObjectList;
  233. function Extract(Item: TObject): TObject;
  234. function Remove(AObject: TObject): Integer;
  235. function IndexOf(AObject: TObject): Integer;
  236. function Find(const s:string): TObject;
  237. function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
  238. procedure Pack;
  239. procedure ShowStatistics;
  240. procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  241. procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  242. property Capacity: Integer read GetCapacity write SetCapacity;
  243. property Count: Integer read GetCount write SetCount;
  244. property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
  245. property Items[Index: Integer]: TObject read GetItem; default;
  246. property List: TFPHashList read FHashList;
  247. end;
  248. {********************************************
  249. TLinkedList
  250. ********************************************}
  251. type
  252. TLinkedListItem = class
  253. public
  254. Previous,
  255. Next : TLinkedListItem;
  256. Constructor Create;
  257. Destructor Destroy;override;
  258. Function GetCopy:TLinkedListItem;virtual;
  259. end;
  260. TLinkedListItemClass = class of TLinkedListItem;
  261. TLinkedList = class
  262. private
  263. FCount : integer;
  264. FFirst,
  265. FLast : TLinkedListItem;
  266. FNoClear : boolean;
  267. public
  268. constructor Create;
  269. destructor Destroy;override;
  270. { true when the List is empty }
  271. function Empty:boolean;
  272. { deletes all Items }
  273. procedure Clear;
  274. { inserts an Item }
  275. procedure Insert(Item:TLinkedListItem);
  276. { inserts an Item before Loc }
  277. procedure InsertBefore(Item,Loc : TLinkedListItem);
  278. { inserts an Item after Loc }
  279. procedure InsertAfter(Item,Loc : TLinkedListItem);virtual;
  280. { concats an Item }
  281. procedure Concat(Item:TLinkedListItem);
  282. { deletes an Item }
  283. procedure Remove(Item:TLinkedListItem);
  284. { Gets First Item }
  285. function GetFirst:TLinkedListItem;
  286. { Gets last Item }
  287. function GetLast:TLinkedListItem;
  288. { inserts another List at the begin and make this List empty }
  289. procedure insertList(p : TLinkedList);
  290. { inserts another List before the provided item and make this List empty }
  291. procedure insertListBefore(Item:TLinkedListItem;p : TLinkedList);
  292. { inserts another List after the provided item and make this List empty }
  293. procedure insertListAfter(Item:TLinkedListItem;p : TLinkedList);
  294. { concats another List at the end and make this List empty }
  295. procedure concatList(p : TLinkedList);
  296. { concats another List at the start and makes a copy
  297. the list is ordered in reverse.
  298. }
  299. procedure insertListcopy(p : TLinkedList);
  300. { concats another List at the end and makes a copy }
  301. procedure concatListcopy(p : TLinkedList);
  302. property First:TLinkedListItem read FFirst;
  303. property Last:TLinkedListItem read FLast;
  304. property Count:Integer read FCount;
  305. property NoClear:boolean write FNoClear;
  306. end;
  307. {********************************************
  308. TStringList
  309. ********************************************}
  310. { string containerItem }
  311. TStringListItem = class(TLinkedListItem)
  312. FPStr : PString;
  313. public
  314. constructor Create(const s:string);
  315. destructor Destroy;override;
  316. function GetCopy:TLinkedListItem;override;
  317. function Str:string;
  318. end;
  319. { string container }
  320. TStringList = class(TLinkedList)
  321. private
  322. FDoubles : boolean; { if this is set to true, doubles are allowed }
  323. public
  324. constructor Create;
  325. constructor Create_No_Double;
  326. { inserts an Item }
  327. procedure Insert(const s:string);
  328. { concats an Item }
  329. procedure Concat(const s:string);
  330. { deletes an Item }
  331. procedure Remove(const s:string);
  332. { Gets First Item }
  333. function GetFirst:string;
  334. { Gets last Item }
  335. function GetLast:string;
  336. { true if string is in the container, compare case sensitive }
  337. function FindCase(const s:string):TStringListItem;
  338. { true if string is in the container }
  339. function Find(const s:string):TStringListItem;
  340. { inserts an item }
  341. procedure InsertItem(item:TStringListItem);
  342. { concats an item }
  343. procedure ConcatItem(item:TStringListItem);
  344. property Doubles:boolean read FDoubles write FDoubles;
  345. procedure readstream(f:TCStream);
  346. procedure writestream(f:TCStream);
  347. end;
  348. {********************************************
  349. Dictionary
  350. ********************************************}
  351. const
  352. { the real size will be [0..hasharray-1] ! }
  353. hasharraysize = 512;
  354. type
  355. { namedindexobect for use with dictionary and indexarray }
  356. TNamedIndexItem=class
  357. private
  358. { indexarray }
  359. FIndexNr : integer;
  360. FIndexNext : TNamedIndexItem;
  361. { dictionary }
  362. FLeft,
  363. FRight : TNamedIndexItem;
  364. FSpeedValue : cardinal;
  365. FName : Pstring;
  366. protected
  367. function GetName:string;virtual;
  368. procedure SetName(const n:string);virtual;
  369. public
  370. constructor Create;
  371. constructor CreateName(const n:string);
  372. destructor Destroy;override;
  373. property IndexNr:integer read FIndexNr write FIndexNr;
  374. property IndexNext:TNamedIndexItem read FIndexNext write FIndexNext;
  375. property Name:string read GetName write SetName;
  376. property SpeedValue:cardinal read FSpeedValue;
  377. property Left:TNamedIndexItem read FLeft write FLeft;
  378. property Right:TNamedIndexItem read FRight write FRight;
  379. end;
  380. Pdictionaryhasharray=^Tdictionaryhasharray;
  381. Tdictionaryhasharray=array[0..hasharraysize-1] of TNamedIndexItem;
  382. TnamedIndexCallback = procedure(p:TNamedIndexItem;arg:pointer) of object;
  383. TnamedIndexStaticCallback = procedure(p:TNamedIndexItem;arg:pointer);
  384. Tdictionary=class
  385. private
  386. FRoot : TNamedIndexItem;
  387. FCount : longint;
  388. FHashArray : Pdictionaryhasharray;
  389. procedure cleartree(var obj:TNamedIndexItem);
  390. function insertNode(NewNode:TNamedIndexItem;var currNode:TNamedIndexItem):TNamedIndexItem;
  391. procedure inserttree(currtree,currroot:TNamedIndexItem);
  392. public
  393. noclear : boolean;
  394. delete_doubles : boolean;
  395. constructor Create;
  396. destructor Destroy;override;
  397. procedure usehash;
  398. procedure clear;
  399. function delete(const s:string):TNamedIndexItem;
  400. function empty:boolean;
  401. procedure foreach(proc2call:TNamedIndexcallback;arg:pointer);
  402. procedure foreach_static(proc2call:TNamedIndexStaticCallback;arg:pointer);
  403. function insert(obj:TNamedIndexItem):TNamedIndexItem;
  404. function replace(oldobj,newobj:TNamedIndexItem):boolean;
  405. function rename(const olds,News : string):TNamedIndexItem;
  406. function search(const s:string):TNamedIndexItem;
  407. function speedsearch(const s:string;SpeedValue:cardinal):TNamedIndexItem;
  408. property Items[const s:string]:TNamedIndexItem read Search;default;
  409. property Count:longint read FCount;
  410. end;
  411. tindexobjectarray=array[1..16000] of TNamedIndexItem;
  412. pnamedindexobjectarray=^tindexobjectarray;
  413. tindexarray=class
  414. noclear : boolean;
  415. First : TNamedIndexItem;
  416. count : integer;
  417. constructor Create(Agrowsize:integer);
  418. destructor destroy;override;
  419. procedure clear;
  420. procedure foreach(proc2call : Tnamedindexcallback;arg:pointer);
  421. procedure foreach_static(proc2call : Tnamedindexstaticcallback;arg:pointer);
  422. procedure deleteindex(p:TNamedIndexItem);
  423. procedure delete(var p:TNamedIndexItem);
  424. procedure insert(p:TNamedIndexItem);
  425. procedure replace(oldp,newp:TNamedIndexItem);
  426. function search(nr:integer):TNamedIndexItem;
  427. property Items[Index: Integer]: TNamedIndexItem read Search; default;
  428. private
  429. growsize,
  430. size : integer;
  431. data : pnamedindexobjectarray;
  432. procedure grow(gsize:integer);
  433. end;
  434. {********************************************
  435. DynamicArray
  436. ********************************************}
  437. const
  438. dynamicblockbasesize = 12;
  439. type
  440. pdynamicblock = ^tdynamicblock;
  441. tdynamicblock = record
  442. pos,
  443. used : integer;
  444. Next : pdynamicblock;
  445. { can't use sizeof(integer) because it crashes gdb }
  446. data : array[0..1024*1024] of byte;
  447. end;
  448. tdynamicarray = class
  449. private
  450. FPosn : integer;
  451. FPosnblock : pdynamicblock;
  452. FBlocksize : integer;
  453. FFirstblock,
  454. FLastblock : pdynamicblock;
  455. procedure grow;
  456. public
  457. constructor Create(Ablocksize:integer);
  458. destructor Destroy;override;
  459. procedure reset;
  460. function size:integer;
  461. procedure align(i:integer);
  462. procedure seek(i:integer);
  463. function read(var d;len:integer):integer;
  464. procedure write(const d;len:integer);
  465. procedure writestr(const s:string);
  466. procedure readstream(f:TCStream;maxlen:longint);
  467. procedure writestream(f:TCStream);
  468. property BlockSize : integer read FBlocksize;
  469. property FirstBlock : PDynamicBlock read FFirstBlock;
  470. property Pos : integer read FPosn;
  471. end;
  472. implementation
  473. {*****************************************************************************
  474. Memory debug
  475. *****************************************************************************}
  476. constructor tmemdebug.create(const s:string);
  477. begin
  478. infostr:=s;
  479. totalmem:=0;
  480. Start;
  481. end;
  482. procedure tmemdebug.start;
  483. var
  484. status : TFPCHeapStatus;
  485. begin
  486. status:=GetFPCHeapStatus;
  487. startmem:=status.CurrHeapUsed;
  488. end;
  489. procedure tmemdebug.stop;
  490. var
  491. status : TFPCHeapStatus;
  492. begin
  493. if startmem<>0 then
  494. begin
  495. status:=GetFPCHeapStatus;
  496. inc(TotalMem,startmem-status.CurrHeapUsed);
  497. startmem:=0;
  498. end;
  499. end;
  500. destructor tmemdebug.destroy;
  501. begin
  502. Stop;
  503. show;
  504. end;
  505. procedure tmemdebug.show;
  506. begin
  507. write('memory [',infostr,'] ');
  508. if TotalMem>0 then
  509. writeln(DStr(TotalMem shr 10),' Kb released')
  510. else
  511. writeln(DStr((-TotalMem) shr 10),' Kb allocated');
  512. end;
  513. {*****************************************************************************
  514. TFPObjectList (Copied from rtl/objpas/classes/lists.inc)
  515. *****************************************************************************}
  516. Const
  517. // Ratio of Pointer and Word Size.
  518. WordRatio = SizeOf(Pointer) Div SizeOf(Word);
  519. procedure TFPList.RaiseIndexError(Index : Integer);
  520. begin
  521. Error(SListIndexError, Index);
  522. end;
  523. function TFPList.Get(Index: Integer): Pointer; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  524. begin
  525. If (Index < 0) or (Index >= FCount) then
  526. RaiseIndexError(Index);
  527. Result:=FList^[Index];
  528. end;
  529. procedure TFPList.Put(Index: Integer; Item: Pointer); {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  530. begin
  531. if (Index < 0) or (Index >= FCount) then
  532. RaiseIndexError(Index);
  533. Flist^[Index] := Item;
  534. end;
  535. function TFPList.Extract(item: Pointer): Pointer;
  536. var
  537. i : Integer;
  538. begin
  539. result := nil;
  540. i := IndexOf(item);
  541. if i >= 0 then
  542. begin
  543. Result := item;
  544. FList^[i] := nil;
  545. Delete(i);
  546. end;
  547. end;
  548. procedure TFPList.SetCapacity(NewCapacity: Integer);
  549. begin
  550. If (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  551. Error (SListCapacityError, NewCapacity);
  552. if NewCapacity = FCapacity then
  553. exit;
  554. ReallocMem(FList, SizeOf(Pointer)*NewCapacity);
  555. FCapacity := NewCapacity;
  556. end;
  557. procedure TFPList.SetCount(NewCount: Integer);
  558. begin
  559. if (NewCount < 0) or (NewCount > MaxListSize)then
  560. Error(SListCountError, NewCount);
  561. If NewCount > FCount then
  562. begin
  563. If NewCount > FCapacity then
  564. SetCapacity(NewCount);
  565. If FCount < NewCount then
  566. FillWord(Flist^[FCount], (NewCount-FCount) * WordRatio, 0);
  567. end;
  568. FCount := Newcount;
  569. end;
  570. destructor TFPList.Destroy;
  571. begin
  572. Self.Clear;
  573. inherited Destroy;
  574. end;
  575. function TFPList.Add(Item: Pointer): Integer; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  576. begin
  577. if FCount = FCapacity then
  578. Self.Expand;
  579. FList^[FCount] := Item;
  580. Result := FCount;
  581. FCount := FCount + 1;
  582. end;
  583. procedure TFPList.Clear;
  584. begin
  585. if Assigned(FList) then
  586. begin
  587. SetCount(0);
  588. SetCapacity(0);
  589. FList := nil;
  590. end;
  591. end;
  592. procedure TFPList.Delete(Index: Integer); {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  593. begin
  594. If (Index<0) or (Index>=FCount) then
  595. Error (SListIndexError, Index);
  596. FCount := FCount-1;
  597. System.Move (FList^[Index+1], FList^[Index], (FCount - Index) * SizeOf(Pointer));
  598. // Shrink the list if appropriate
  599. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  600. begin
  601. FCapacity := FCapacity shr 1;
  602. ReallocMem(FList, SizeOf(Pointer) * FCapacity);
  603. end;
  604. end;
  605. class procedure TFPList.Error(const Msg: string; Data: PtrInt);
  606. begin
  607. Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  608. end;
  609. procedure TFPList.Exchange(Index1, Index2: Integer);
  610. var
  611. Temp : Pointer;
  612. begin
  613. If ((Index1 >= FCount) or (Index1 < 0)) then
  614. Error(SListIndexError, Index1);
  615. If ((Index2 >= FCount) or (Index2 < 0)) then
  616. Error(SListIndexError, Index2);
  617. Temp := FList^[Index1];
  618. FList^[Index1] := FList^[Index2];
  619. FList^[Index2] := Temp;
  620. end;
  621. function TFPList.Expand: TFPList; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  622. var
  623. IncSize : Longint;
  624. begin
  625. if FCount < FCapacity then exit;
  626. IncSize := 4;
  627. if FCapacity > 3 then IncSize := IncSize + 4;
  628. if FCapacity > 8 then IncSize := IncSize+8;
  629. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  630. SetCapacity(FCapacity + IncSize);
  631. Result := Self;
  632. end;
  633. function TFPList.First: Pointer;
  634. begin
  635. If FCount = 0 then
  636. Result := Nil
  637. else
  638. Result := Items[0];
  639. end;
  640. function TFPList.IndexOf(Item: Pointer): Integer;
  641. begin
  642. Result := 0;
  643. while(Result < FCount) and (Flist^[Result] <> Item) do Result := Result + 1;
  644. If Result = FCount then Result := -1;
  645. end;
  646. procedure TFPList.Insert(Index: Integer; Item: Pointer); {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  647. begin
  648. if (Index < 0) or (Index > FCount )then
  649. Error(SlistIndexError, Index);
  650. iF FCount = FCapacity then Self.Expand;
  651. if Index<FCount then
  652. System.Move(Flist^[Index], Flist^[Index+1], (FCount - Index) * SizeOf(Pointer));
  653. FList^[Index] := Item;
  654. FCount := FCount + 1;
  655. end;
  656. function TFPList.Last: Pointer;
  657. begin
  658. { Wouldn't it be better to return nil if the count is zero ?}
  659. If FCount = 0 then
  660. Result := nil
  661. else
  662. Result := Items[FCount - 1];
  663. end;
  664. procedure TFPList.Move(CurIndex, NewIndex: Integer);
  665. var
  666. Temp : Pointer;
  667. begin
  668. if ((CurIndex < 0) or (CurIndex > Count - 1)) then
  669. Error(SListIndexError, CurIndex);
  670. if (NewINdex < 0) then
  671. Error(SlistIndexError, NewIndex);
  672. Temp := FList^[CurIndex];
  673. FList^[CurIndex] := nil;
  674. Self.Delete(CurIndex);
  675. Self.Insert(NewIndex, nil);
  676. FList^[NewIndex] := Temp;
  677. end;
  678. function TFPList.Remove(Item: Pointer): Integer;
  679. begin
  680. Result := IndexOf(Item);
  681. If Result <> -1 then
  682. Self.Delete(Result);
  683. end;
  684. procedure TFPList.Pack;
  685. var
  686. NewCount,
  687. i : integer;
  688. pdest,
  689. psrc : PPointer;
  690. begin
  691. NewCount:=0;
  692. psrc:=@FList[0];
  693. pdest:=psrc;
  694. For I:=0 To FCount-1 Do
  695. begin
  696. if assigned(psrc^) then
  697. begin
  698. pdest^:=psrc^;
  699. inc(pdest);
  700. inc(NewCount);
  701. end;
  702. inc(psrc);
  703. end;
  704. FCount:=NewCount;
  705. end;
  706. // Needed by Sort method.
  707. Procedure QuickSort(FList: PPointerList; L, R : Longint;
  708. Compare: TListSortCompare);
  709. var
  710. I, J : Longint;
  711. P, Q : Pointer;
  712. begin
  713. repeat
  714. I := L;
  715. J := R;
  716. P := FList^[ (L + R) div 2 ];
  717. repeat
  718. while Compare(P, FList^[i]) > 0 do
  719. I := I + 1;
  720. while Compare(P, FList^[J]) < 0 do
  721. J := J - 1;
  722. If I <= J then
  723. begin
  724. Q := FList^[I];
  725. Flist^[I] := FList^[J];
  726. FList^[J] := Q;
  727. I := I + 1;
  728. J := J - 1;
  729. end;
  730. until I > J;
  731. if L < J then
  732. QuickSort(FList, L, J, Compare);
  733. L := I;
  734. until I >= R;
  735. end;
  736. procedure TFPList.Sort(Compare: TListSortCompare);
  737. begin
  738. if Not Assigned(FList) or (FCount < 2) then exit;
  739. QuickSort(Flist, 0, FCount-1, Compare);
  740. end;
  741. procedure TFPList.Assign(Obj: TFPList);
  742. var
  743. i: Integer;
  744. begin
  745. Clear;
  746. for I := 0 to Obj.Count - 1 do
  747. Add(Obj[i]);
  748. end;
  749. procedure TFPList.ForEachCall(proc2call:TListCallback;arg:pointer);
  750. var
  751. i : integer;
  752. p : pointer;
  753. begin
  754. For I:=0 To Count-1 Do
  755. begin
  756. p:=FList^[i];
  757. if assigned(p) then
  758. proc2call(p,arg);
  759. end;
  760. end;
  761. procedure TFPList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  762. var
  763. i : integer;
  764. p : pointer;
  765. begin
  766. For I:=0 To Count-1 Do
  767. begin
  768. p:=FList^[i];
  769. if assigned(p) then
  770. proc2call(p,arg);
  771. end;
  772. end;
  773. {*****************************************************************************
  774. TFPObjectList (Copied from rtl/objpas/classes/lists.inc)
  775. *****************************************************************************}
  776. constructor TFPObjectList.Create(FreeObjects : boolean);
  777. begin
  778. Create;
  779. FFreeObjects := Freeobjects;
  780. end;
  781. destructor TFPObjectList.Destroy;
  782. begin
  783. if (FList <> nil) then
  784. begin
  785. Clear;
  786. FList.Destroy;
  787. end;
  788. inherited Destroy;
  789. end;
  790. procedure TFPObjectList.Clear;
  791. var
  792. i: integer;
  793. begin
  794. if FFreeObjects then
  795. for i := 0 to FList.Count - 1 do
  796. TObject(FList[i]).Free;
  797. FList.Clear;
  798. end;
  799. constructor TFPObjectList.Create;
  800. begin
  801. inherited Create;
  802. FList := TFPList.Create;
  803. FFreeObjects := True;
  804. end;
  805. function TFPObjectList.GetCount: integer;
  806. begin
  807. Result := FList.Count;
  808. end;
  809. procedure TFPObjectList.SetCount(const AValue: integer);
  810. begin
  811. if FList.Count <> AValue then
  812. FList.Count := AValue;
  813. end;
  814. function TFPObjectList.GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
  815. begin
  816. Result := TObject(FList[Index]);
  817. end;
  818. procedure TFPObjectList.SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  819. begin
  820. if OwnsObjects then
  821. TObject(FList[Index]).Free;
  822. FList[index] := AObject;
  823. end;
  824. procedure TFPObjectList.SetCapacity(NewCapacity: Integer);
  825. begin
  826. FList.Capacity := NewCapacity;
  827. end;
  828. function TFPObjectList.GetCapacity: integer;
  829. begin
  830. Result := FList.Capacity;
  831. end;
  832. function TFPObjectList.Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
  833. begin
  834. Result := FList.Add(AObject);
  835. end;
  836. procedure TFPObjectList.Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
  837. begin
  838. if OwnsObjects then
  839. TObject(FList[Index]).Free;
  840. FList.Delete(Index);
  841. end;
  842. procedure TFPObjectList.Exchange(Index1, Index2: Integer);
  843. begin
  844. FList.Exchange(Index1, Index2);
  845. end;
  846. function TFPObjectList.Expand: TFPObjectList;
  847. begin
  848. FList.Expand;
  849. Result := Self;
  850. end;
  851. function TFPObjectList.Extract(Item: TObject): TObject;
  852. begin
  853. Result := TObject(FList.Extract(Item));
  854. end;
  855. function TFPObjectList.Remove(AObject: TObject): Integer;
  856. begin
  857. Result := IndexOf(AObject);
  858. if (Result <> -1) then
  859. begin
  860. if OwnsObjects then
  861. TObject(FList[Result]).Free;
  862. FList.Delete(Result);
  863. end;
  864. end;
  865. function TFPObjectList.IndexOf(AObject: TObject): Integer;
  866. begin
  867. Result := FList.IndexOf(Pointer(AObject));
  868. end;
  869. function TFPObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
  870. var
  871. I : Integer;
  872. begin
  873. I:=AStartAt;
  874. Result:=-1;
  875. If AExact then
  876. while (I<Count) and (Result=-1) do
  877. If Items[i].ClassType=AClass then
  878. Result:=I
  879. else
  880. Inc(I)
  881. else
  882. while (I<Count) and (Result=-1) do
  883. If Items[i].InheritsFrom(AClass) then
  884. Result:=I
  885. else
  886. Inc(I);
  887. end;
  888. procedure TFPObjectList.Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
  889. begin
  890. FList.Insert(Index, Pointer(AObject));
  891. end;
  892. procedure TFPObjectList.Move(CurIndex, NewIndex: Integer);
  893. begin
  894. FList.Move(CurIndex, NewIndex);
  895. end;
  896. procedure TFPObjectList.Assign(Obj: TFPObjectList);
  897. var
  898. i: Integer;
  899. begin
  900. Clear;
  901. for I := 0 to Obj.Count - 1 do
  902. Add(Obj[i]);
  903. end;
  904. procedure TFPObjectList.Pack;
  905. begin
  906. FList.Pack;
  907. end;
  908. procedure TFPObjectList.Sort(Compare: TListSortCompare);
  909. begin
  910. FList.Sort(Compare);
  911. end;
  912. function TFPObjectList.First: TObject;
  913. begin
  914. Result := TObject(FList.First);
  915. end;
  916. function TFPObjectList.Last: TObject;
  917. begin
  918. Result := TObject(FList.Last);
  919. end;
  920. procedure TFPObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  921. begin
  922. FList.ForEachCall(TListCallBack(proc2call),arg);
  923. end;
  924. procedure TFPObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  925. begin
  926. FList.ForEachCall(TListStaticCallBack(proc2call),arg);
  927. end;
  928. {*****************************************************************************
  929. TFPHashList
  930. *****************************************************************************}
  931. function FPHash1(const s:string):LongWord;
  932. Var
  933. g : LongWord;
  934. p,pmax : pchar;
  935. begin
  936. result:=0;
  937. p:=@s[1];
  938. pmax:=@s[length(s)+1];
  939. while (p<pmax) do
  940. begin
  941. result:=result shl 4 + LongWord(p^);
  942. g:=result and LongWord($F0000000);
  943. if g<>0 then
  944. result:=result xor (g shr 24) xor g;
  945. inc(p);
  946. end;
  947. If result=0 then
  948. result:=$ffffffff;
  949. end;
  950. function FPHash(const s:string):LongWord;
  951. Var
  952. p,pmax : pchar;
  953. begin
  954. {$ifopt Q+}
  955. {$define overflowon}
  956. {$Q-}
  957. {$endif}
  958. result:=0;
  959. p:=@s[1];
  960. pmax:=@s[length(s)+1];
  961. while (p<pmax) do
  962. begin
  963. result:=LongWord((result shl 5) - result) xor LongWord(P^);
  964. inc(p);
  965. end;
  966. {$ifdef overflowon}
  967. {$Q+}
  968. {$undef overflowon}
  969. {$endif}
  970. end;
  971. procedure TFPHashList.RaiseIndexError(Index : Integer);
  972. begin
  973. Error(SListIndexError, Index);
  974. end;
  975. function TFPHashList.Get(Index: Integer): Pointer;
  976. begin
  977. If (Index < 0) or (Index >= FCount) then
  978. RaiseIndexError(Index);
  979. Result:=FHashList^[Index].Data;
  980. end;
  981. function TFPHashList.NameOfIndex(Index: Integer): String;
  982. begin
  983. If (Index < 0) or (Index >= FCount) then
  984. RaiseIndexError(Index);
  985. Result:=PShortString(@FStrs[FHashList^[Index].StrIndex])^;
  986. end;
  987. function TFPHashList.Extract(item: Pointer): Pointer;
  988. var
  989. i : Integer;
  990. begin
  991. result := nil;
  992. i := IndexOf(item);
  993. if i >= 0 then
  994. begin
  995. Result := item;
  996. Delete(i);
  997. end;
  998. end;
  999. procedure TFPHashList.SetCapacity(NewCapacity: Integer);
  1000. begin
  1001. If (NewCapacity < FCount) or (NewCapacity > MaxHashListSize) then
  1002. Error (SListCapacityError, NewCapacity);
  1003. if NewCapacity = FCapacity then
  1004. exit;
  1005. ReallocMem(FHashList, NewCapacity*SizeOf(THashItem));
  1006. FCapacity := NewCapacity;
  1007. end;
  1008. procedure TFPHashList.SetCount(NewCount: Integer);
  1009. begin
  1010. if (NewCount < 0) or (NewCount > MaxHashListSize)then
  1011. Error(SListCountError, NewCount);
  1012. If NewCount > FCount then
  1013. begin
  1014. If NewCount > FCapacity then
  1015. SetCapacity(NewCount);
  1016. If FCount < NewCount then
  1017. FillChar(FHashList^[FCount], (NewCount-FCount) div Sizeof(THashItem), 0);
  1018. end;
  1019. FCount := Newcount;
  1020. end;
  1021. procedure TFPHashList.SetStrCapacity(NewCapacity: Integer);
  1022. begin
  1023. If (NewCapacity < FStrCount) or (NewCapacity > MaxHashStrSize) then
  1024. Error (SListCapacityError, NewCapacity);
  1025. if NewCapacity = FStrCapacity then
  1026. exit;
  1027. ReallocMem(FStrs, NewCapacity);
  1028. FStrCapacity := NewCapacity;
  1029. end;
  1030. procedure TFPHashList.SetHashCapacity(NewCapacity: Integer);
  1031. begin
  1032. If (NewCapacity < 1) then
  1033. Error (SListCapacityError, NewCapacity);
  1034. if FHashCapacity=NewCapacity then
  1035. exit;
  1036. FHashCapacity:=NewCapacity;
  1037. ReallocMem(FHashTable, FHashCapacity*sizeof(Integer));
  1038. ReHash;
  1039. end;
  1040. procedure TFPHashList.ReHash;
  1041. var
  1042. i : Integer;
  1043. begin
  1044. FillDword(FHashTable^,FHashCapacity,LongWord(-1));
  1045. For i:=0 To FCount-1 Do
  1046. AddToHashTable(i);
  1047. end;
  1048. constructor TFPHashList.Create;
  1049. begin
  1050. SetHashCapacity(1);
  1051. end;
  1052. destructor TFPHashList.Destroy;
  1053. begin
  1054. Clear;
  1055. if assigned(FHashTable) then
  1056. FreeMem(FHashTable);
  1057. inherited Destroy;
  1058. end;
  1059. function TFPHashList.AddStr(const s:string): Integer;
  1060. var
  1061. Len : Integer;
  1062. begin
  1063. len:=length(s)+1;
  1064. if FStrCount+Len >= FStrCapacity then
  1065. StrExpand(Len);
  1066. System.Move(s[0],FStrs[FStrCount],Len);
  1067. result:=FStrCount;
  1068. inc(FStrCount,Len);
  1069. end;
  1070. procedure TFPHashList.AddToHashTable(Index: Integer);
  1071. var
  1072. HashIndex : Integer;
  1073. begin
  1074. with FHashList^[Index] do
  1075. begin
  1076. if not assigned(Data) then
  1077. exit;
  1078. HashIndex:=HashValue mod LongWord(FHashCapacity);
  1079. NextIndex:=FHashTable^[HashIndex];
  1080. FHashTable^[HashIndex]:=Index;
  1081. end;
  1082. end;
  1083. function TFPHashList.Add(const AName:string;Item: Pointer): Integer;
  1084. begin
  1085. if FCount = FCapacity then
  1086. Expand;
  1087. with FHashList^[FCount] do
  1088. begin
  1089. HashValue:=FPHash(AName);
  1090. Data:=Item;
  1091. StrIndex:=AddStr(AName);
  1092. end;
  1093. AddToHashTable(FCount);
  1094. Result := FCount;
  1095. inc(FCount);
  1096. end;
  1097. procedure TFPHashList.Clear;
  1098. begin
  1099. if Assigned(FHashList) then
  1100. begin
  1101. FCount:=0;
  1102. SetCapacity(0);
  1103. FHashList := nil;
  1104. end;
  1105. SetHashCapacity(1);
  1106. if Assigned(FStrs) then
  1107. begin
  1108. FStrCount:=0;
  1109. SetStrCapacity(0);
  1110. FStrs := nil;
  1111. end;
  1112. end;
  1113. procedure TFPHashList.Delete(Index: Integer);
  1114. begin
  1115. If (Index<0) or (Index>=FCount) then
  1116. Error (SListIndexError, Index);
  1117. FHashList^[Index].Data:=nil;
  1118. end;
  1119. class procedure TFPHashList.Error(const Msg: string; Data: PtrInt);
  1120. begin
  1121. Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  1122. end;
  1123. function TFPHashList.Expand: TFPHashList;
  1124. var
  1125. IncSize : Longint;
  1126. begin
  1127. Result := Self;
  1128. if FCount < FCapacity then
  1129. exit;
  1130. IncSize := 4;
  1131. if FCapacity > 127 then
  1132. Inc(IncSize, FCapacity shr 2)
  1133. else if FCapacity > 8 then
  1134. inc(IncSize,8)
  1135. else if FCapacity > 3 then
  1136. inc(IncSize,4);
  1137. SetCapacity(FCapacity + IncSize);
  1138. { Maybe expand hash also }
  1139. if FCount>FHashCapacity*MaxItemsPerHash then
  1140. SetHashCapacity(FCount div MaxItemsPerHash);
  1141. end;
  1142. procedure TFPHashList.StrExpand(MinIncSize:Integer);
  1143. var
  1144. IncSize : Longint;
  1145. begin
  1146. if FStrCount+MinIncSize < FStrCapacity then
  1147. exit;
  1148. IncSize := 64+MinIncSize;
  1149. if FStrCapacity > 255 then
  1150. Inc(IncSize, FStrCapacity shr 2);
  1151. SetStrCapacity(FStrCapacity + IncSize);
  1152. end;
  1153. function TFPHashList.IndexOf(Item: Pointer): Integer;
  1154. begin
  1155. Result := 0;
  1156. while(Result < FCount) and (FHashList^[Result].Data <> Item) do Result := Result + 1;
  1157. If Result = FCount then Result := -1;
  1158. end;
  1159. function TFPHashList.Find(const s:string): Pointer;
  1160. var
  1161. CurrHash : LongWord;
  1162. Index,
  1163. HashIndex : Integer;
  1164. Len,
  1165. LastChar : Char;
  1166. begin
  1167. CurrHash:=FPHash(s);
  1168. HashIndex:=CurrHash mod LongWord(FHashCapacity);
  1169. Index:=FHashTable^[HashIndex];
  1170. Len:=Char(Length(s));
  1171. LastChar:=s[Byte(Len)];
  1172. while Index<>-1 do
  1173. begin
  1174. with FHashList^[Index] do
  1175. begin
  1176. if assigned(Data) and
  1177. (HashValue=CurrHash) and
  1178. (Len=FStrs[StrIndex]) and
  1179. (LastChar=FStrs[StrIndex+Byte(Len)]) and
  1180. (s=PShortString(@FStrs[StrIndex])^) then
  1181. begin
  1182. Result:=Data;
  1183. exit;
  1184. end;
  1185. Index:=NextIndex;
  1186. end;
  1187. end;
  1188. Result:=nil;
  1189. end;
  1190. function TFPHashList.Remove(Item: Pointer): Integer;
  1191. begin
  1192. Result := IndexOf(Item);
  1193. If Result <> -1 then
  1194. Self.Delete(Result);
  1195. end;
  1196. procedure TFPHashList.Pack;
  1197. var
  1198. NewCount,
  1199. i : integer;
  1200. pdest,
  1201. psrc : PHashItem;
  1202. begin
  1203. NewCount:=0;
  1204. psrc:=@FHashList[0];
  1205. pdest:=psrc;
  1206. For I:=0 To FCount-1 Do
  1207. begin
  1208. if assigned(psrc^.Data) then
  1209. begin
  1210. pdest^:=psrc^;
  1211. inc(pdest);
  1212. inc(NewCount);
  1213. end;
  1214. inc(psrc);
  1215. end;
  1216. FCount:=NewCount;
  1217. { We need to ReHash to update the IndexNext }
  1218. ReHash;
  1219. { Release over-capacity }
  1220. SetCapacity(FCount);
  1221. SetStrCapacity(FStrCount);
  1222. end;
  1223. procedure TFPHashList.ShowStatistics;
  1224. var
  1225. HashMean,
  1226. HashStdDev : Double;
  1227. Index,
  1228. i,j : Integer;
  1229. begin
  1230. { Calculate Mean and StdDev }
  1231. HashMean:=0;
  1232. HashStdDev:=0;
  1233. for i:=0 to FHashCapacity-1 do
  1234. begin
  1235. j:=0;
  1236. Index:=FHashTable^[i];
  1237. while (Index<>-1) do
  1238. begin
  1239. inc(j);
  1240. Index:=FHashList^[Index].NextIndex;
  1241. end;
  1242. HashMean:=HashMean+j;
  1243. HashStdDev:=HashStdDev+Sqr(j);
  1244. end;
  1245. HashMean:=HashMean/FHashCapacity;
  1246. HashStdDev:=(HashStdDev-FHashCapacity*Sqr(HashMean));
  1247. If FHashCapacity>1 then
  1248. HashStdDev:=Sqrt(HashStdDev/(FHashCapacity-1))
  1249. else
  1250. HashStdDev:=0;
  1251. { Print info to stdout }
  1252. Writeln('HashSize : ',FHashCapacity);
  1253. Writeln('HashMean : ',HashMean:1:4);
  1254. Writeln('HashStdDev : ',HashStdDev:1:4);
  1255. Writeln('ListSize : ',FCount,'/',FCapacity);
  1256. Writeln('StringSize : ',FStrCount,'/',FStrCapacity);
  1257. end;
  1258. procedure TFPHashList.ForEachCall(proc2call:TListCallback;arg:pointer);
  1259. var
  1260. i : integer;
  1261. p : pointer;
  1262. begin
  1263. For I:=0 To Count-1 Do
  1264. begin
  1265. p:=FHashList^[i].Data;
  1266. if assigned(p) then
  1267. proc2call(p,arg);
  1268. end;
  1269. end;
  1270. procedure TFPHashList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  1271. var
  1272. i : integer;
  1273. p : pointer;
  1274. begin
  1275. For I:=0 To Count-1 Do
  1276. begin
  1277. p:=FHashList^[i].Data;
  1278. if assigned(p) then
  1279. proc2call(p,arg);
  1280. end;
  1281. end;
  1282. {*****************************************************************************
  1283. TFPHashObject
  1284. *****************************************************************************}
  1285. constructor TFPHashObject.Create(HashObjectList:TFPHashObjectList;const s:string);
  1286. var
  1287. Index : Integer;
  1288. begin
  1289. FOwner:=HashObjectList;
  1290. Index:=HashObjectList.Add(s,Self);
  1291. FStrIndex:=HashObjectList.List.List^[Index].StrIndex;
  1292. end;
  1293. function TFPHashObject.GetName:string;
  1294. begin
  1295. Result:=PShortString(@FOwner.List.Strs[FStrIndex])^;
  1296. end;
  1297. {*****************************************************************************
  1298. TFPHashObjectList (Copied from rtl/objpas/classes/lists.inc)
  1299. *****************************************************************************}
  1300. constructor TFPHashObjectList.Create(FreeObjects : boolean = True);
  1301. begin
  1302. inherited Create;
  1303. FHashList := TFPHashList.Create;
  1304. FFreeObjects := Freeobjects;
  1305. end;
  1306. destructor TFPHashObjectList.Destroy;
  1307. begin
  1308. if (FHashList <> nil) then
  1309. begin
  1310. Clear;
  1311. FHashList.Destroy;
  1312. end;
  1313. inherited Destroy;
  1314. end;
  1315. procedure TFPHashObjectList.Clear;
  1316. var
  1317. i: integer;
  1318. begin
  1319. if FFreeObjects then
  1320. for i := 0 to FHashList.Count - 1 do
  1321. TObject(FHashList[i]).Free;
  1322. FHashList.Clear;
  1323. end;
  1324. function TFPHashObjectList.GetCount: integer;
  1325. begin
  1326. Result := FHashList.Count;
  1327. end;
  1328. procedure TFPHashObjectList.SetCount(const AValue: integer);
  1329. begin
  1330. if FHashList.Count <> AValue then
  1331. FHashList.Count := AValue;
  1332. end;
  1333. function TFPHashObjectList.GetItem(Index: Integer): TObject;
  1334. begin
  1335. Result := TObject(FHashList[Index]);
  1336. end;
  1337. procedure TFPHashObjectList.SetCapacity(NewCapacity: Integer);
  1338. begin
  1339. FHashList.Capacity := NewCapacity;
  1340. end;
  1341. function TFPHashObjectList.GetCapacity: integer;
  1342. begin
  1343. Result := FHashList.Capacity;
  1344. end;
  1345. function TFPHashObjectList.Add(const AName:string;AObject: TObject): Integer;
  1346. begin
  1347. Result := FHashList.Add(AName,AObject);
  1348. end;
  1349. function TFPHashObjectList.NameOfIndex(Index: Integer): String;
  1350. begin
  1351. Result := FHashList.NameOfIndex(Index);
  1352. end;
  1353. procedure TFPHashObjectList.Delete(Index: Integer);
  1354. begin
  1355. if OwnsObjects then
  1356. TObject(FHashList[Index]).Free;
  1357. FHashList.Delete(Index);
  1358. end;
  1359. function TFPHashObjectList.Expand: TFPHashObjectList;
  1360. begin
  1361. FHashList.Expand;
  1362. Result := Self;
  1363. end;
  1364. function TFPHashObjectList.Extract(Item: TObject): TObject;
  1365. begin
  1366. Result := TObject(FHashList.Extract(Item));
  1367. end;
  1368. function TFPHashObjectList.Remove(AObject: TObject): Integer;
  1369. begin
  1370. Result := IndexOf(AObject);
  1371. if (Result <> -1) then
  1372. begin
  1373. if OwnsObjects then
  1374. TObject(FHashList[Result]).Free;
  1375. FHashList.Delete(Result);
  1376. end;
  1377. end;
  1378. function TFPHashObjectList.IndexOf(AObject: TObject): Integer;
  1379. begin
  1380. Result := FHashList.IndexOf(Pointer(AObject));
  1381. end;
  1382. function TFPHashObjectList.Find(const s:string): TObject;
  1383. begin
  1384. result:=TObject(FHashList.Find(s));
  1385. end;
  1386. function TFPHashObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
  1387. var
  1388. I : Integer;
  1389. begin
  1390. I:=AStartAt;
  1391. Result:=-1;
  1392. If AExact then
  1393. while (I<Count) and (Result=-1) do
  1394. If Items[i].ClassType=AClass then
  1395. Result:=I
  1396. else
  1397. Inc(I)
  1398. else
  1399. while (I<Count) and (Result=-1) do
  1400. If Items[i].InheritsFrom(AClass) then
  1401. Result:=I
  1402. else
  1403. Inc(I);
  1404. end;
  1405. procedure TFPHashObjectList.Pack;
  1406. begin
  1407. FHashList.Pack;
  1408. end;
  1409. procedure TFPHashObjectList.ShowStatistics;
  1410. begin
  1411. FHashList.ShowStatistics;
  1412. end;
  1413. procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
  1414. begin
  1415. FHashList.ForEachCall(TListCallBack(proc2call),arg);
  1416. end;
  1417. procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
  1418. begin
  1419. FHashList.ForEachCall(TListStaticCallBack(proc2call),arg);
  1420. end;
  1421. {****************************************************************************
  1422. TLinkedListItem
  1423. ****************************************************************************}
  1424. constructor TLinkedListItem.Create;
  1425. begin
  1426. Previous:=nil;
  1427. Next:=nil;
  1428. end;
  1429. destructor TLinkedListItem.Destroy;
  1430. begin
  1431. end;
  1432. function TLinkedListItem.GetCopy:TLinkedListItem;
  1433. var
  1434. p : TLinkedListItem;
  1435. l : integer;
  1436. begin
  1437. p:=TLinkedListItemClass(ClassType).Create;
  1438. l:=InstanceSize;
  1439. Move(pointer(self)^,pointer(p)^,l);
  1440. Result:=p;
  1441. end;
  1442. {****************************************************************************
  1443. TLinkedList
  1444. ****************************************************************************}
  1445. constructor TLinkedList.Create;
  1446. begin
  1447. FFirst:=nil;
  1448. Flast:=nil;
  1449. FCount:=0;
  1450. FNoClear:=False;
  1451. end;
  1452. destructor TLinkedList.destroy;
  1453. begin
  1454. if not FNoClear then
  1455. Clear;
  1456. end;
  1457. function TLinkedList.empty:boolean;
  1458. begin
  1459. Empty:=(FFirst=nil);
  1460. end;
  1461. procedure TLinkedList.Insert(Item:TLinkedListItem);
  1462. begin
  1463. if FFirst=nil then
  1464. begin
  1465. FLast:=Item;
  1466. Item.Previous:=nil;
  1467. Item.Next:=nil;
  1468. end
  1469. else
  1470. begin
  1471. FFirst.Previous:=Item;
  1472. Item.Previous:=nil;
  1473. Item.Next:=FFirst;
  1474. end;
  1475. FFirst:=Item;
  1476. inc(FCount);
  1477. end;
  1478. procedure TLinkedList.InsertBefore(Item,Loc : TLinkedListItem);
  1479. begin
  1480. Item.Previous:=Loc.Previous;
  1481. Item.Next:=Loc;
  1482. Loc.Previous:=Item;
  1483. if assigned(Item.Previous) then
  1484. Item.Previous.Next:=Item
  1485. else
  1486. { if we've no next item, we've to adjust FFist }
  1487. FFirst:=Item;
  1488. inc(FCount);
  1489. end;
  1490. procedure TLinkedList.InsertAfter(Item,Loc : TLinkedListItem);
  1491. begin
  1492. Item.Next:=Loc.Next;
  1493. Loc.Next:=Item;
  1494. Item.Previous:=Loc;
  1495. if assigned(Item.Next) then
  1496. Item.Next.Previous:=Item
  1497. else
  1498. { if we've no next item, we've to adjust FLast }
  1499. FLast:=Item;
  1500. inc(FCount);
  1501. end;
  1502. procedure TLinkedList.Concat(Item:TLinkedListItem);
  1503. begin
  1504. if FFirst=nil then
  1505. begin
  1506. FFirst:=Item;
  1507. Item.Previous:=nil;
  1508. Item.Next:=nil;
  1509. end
  1510. else
  1511. begin
  1512. Flast.Next:=Item;
  1513. Item.Previous:=Flast;
  1514. Item.Next:=nil;
  1515. end;
  1516. Flast:=Item;
  1517. inc(FCount);
  1518. end;
  1519. procedure TLinkedList.remove(Item:TLinkedListItem);
  1520. begin
  1521. if Item=nil then
  1522. exit;
  1523. if (FFirst=Item) and (Flast=Item) then
  1524. begin
  1525. FFirst:=nil;
  1526. Flast:=nil;
  1527. end
  1528. else if FFirst=Item then
  1529. begin
  1530. FFirst:=Item.Next;
  1531. if assigned(FFirst) then
  1532. FFirst.Previous:=nil;
  1533. end
  1534. else if Flast=Item then
  1535. begin
  1536. Flast:=Flast.Previous;
  1537. if assigned(Flast) then
  1538. Flast.Next:=nil;
  1539. end
  1540. else
  1541. begin
  1542. Item.Previous.Next:=Item.Next;
  1543. Item.Next.Previous:=Item.Previous;
  1544. end;
  1545. Item.Next:=nil;
  1546. Item.Previous:=nil;
  1547. dec(FCount);
  1548. end;
  1549. procedure TLinkedList.clear;
  1550. var
  1551. NewNode : TLinkedListItem;
  1552. begin
  1553. NewNode:=FFirst;
  1554. while assigned(NewNode) do
  1555. begin
  1556. FFirst:=NewNode.Next;
  1557. NewNode.Free;
  1558. NewNode:=FFirst;
  1559. end;
  1560. FLast:=nil;
  1561. FFirst:=nil;
  1562. FCount:=0;
  1563. end;
  1564. function TLinkedList.GetFirst:TLinkedListItem;
  1565. begin
  1566. if FFirst=nil then
  1567. GetFirst:=nil
  1568. else
  1569. begin
  1570. GetFirst:=FFirst;
  1571. if FFirst=FLast then
  1572. FLast:=nil;
  1573. FFirst:=FFirst.Next;
  1574. dec(FCount);
  1575. end;
  1576. end;
  1577. function TLinkedList.GetLast:TLinkedListItem;
  1578. begin
  1579. if FLast=nil then
  1580. Getlast:=nil
  1581. else
  1582. begin
  1583. Getlast:=FLast;
  1584. if FLast=FFirst then
  1585. FFirst:=nil;
  1586. FLast:=FLast.Previous;
  1587. dec(FCount);
  1588. end;
  1589. end;
  1590. procedure TLinkedList.insertList(p : TLinkedList);
  1591. begin
  1592. { empty List ? }
  1593. if (p.FFirst=nil) then
  1594. exit;
  1595. p.Flast.Next:=FFirst;
  1596. { we have a double Linked List }
  1597. if assigned(FFirst) then
  1598. FFirst.Previous:=p.Flast;
  1599. FFirst:=p.FFirst;
  1600. if (FLast=nil) then
  1601. Flast:=p.Flast;
  1602. inc(FCount,p.FCount);
  1603. { p becomes empty }
  1604. p.FFirst:=nil;
  1605. p.Flast:=nil;
  1606. p.FCount:=0;
  1607. end;
  1608. procedure TLinkedList.insertListBefore(Item:TLinkedListItem;p : TLinkedList);
  1609. begin
  1610. { empty List ? }
  1611. if (p.FFirst=nil) then
  1612. exit;
  1613. if (Item=nil) then
  1614. begin
  1615. { Insert at begin }
  1616. InsertList(p);
  1617. exit;
  1618. end
  1619. else
  1620. begin
  1621. p.FLast.Next:=Item;
  1622. p.FFirst.Previous:=Item.Previous;
  1623. if assigned(Item.Previous) then
  1624. Item.Previous.Next:=p.FFirst
  1625. else
  1626. FFirst:=p.FFirst;
  1627. Item.Previous:=p.FLast;
  1628. inc(FCount,p.FCount);
  1629. end;
  1630. { p becomes empty }
  1631. p.FFirst:=nil;
  1632. p.Flast:=nil;
  1633. p.FCount:=0;
  1634. end;
  1635. procedure TLinkedList.insertListAfter(Item:TLinkedListItem;p : TLinkedList);
  1636. begin
  1637. { empty List ? }
  1638. if (p.FFirst=nil) then
  1639. exit;
  1640. if (Item=nil) then
  1641. begin
  1642. { Insert at begin }
  1643. InsertList(p);
  1644. exit;
  1645. end
  1646. else
  1647. begin
  1648. p.FFirst.Previous:=Item;
  1649. p.FLast.Next:=Item.Next;
  1650. if assigned(Item.Next) then
  1651. Item.Next.Previous:=p.FLast
  1652. else
  1653. FLast:=p.FLast;
  1654. Item.Next:=p.FFirst;
  1655. inc(FCount,p.FCount);
  1656. end;
  1657. { p becomes empty }
  1658. p.FFirst:=nil;
  1659. p.Flast:=nil;
  1660. p.FCount:=0;
  1661. end;
  1662. procedure TLinkedList.concatList(p : TLinkedList);
  1663. begin
  1664. if (p.FFirst=nil) then
  1665. exit;
  1666. if FFirst=nil then
  1667. FFirst:=p.FFirst
  1668. else
  1669. begin
  1670. FLast.Next:=p.FFirst;
  1671. p.FFirst.Previous:=Flast;
  1672. end;
  1673. Flast:=p.Flast;
  1674. inc(FCount,p.FCount);
  1675. { make p empty }
  1676. p.Flast:=nil;
  1677. p.FFirst:=nil;
  1678. p.FCount:=0;
  1679. end;
  1680. procedure TLinkedList.insertListcopy(p : TLinkedList);
  1681. var
  1682. NewNode,NewNode2 : TLinkedListItem;
  1683. begin
  1684. NewNode:=p.First;
  1685. while assigned(NewNode) do
  1686. begin
  1687. NewNode2:=NewNode.Getcopy;
  1688. if assigned(NewNode2) then
  1689. Insert(NewNode2);
  1690. NewNode:=NewNode.Next;
  1691. end;
  1692. end;
  1693. procedure TLinkedList.concatListcopy(p : TLinkedList);
  1694. var
  1695. NewNode,NewNode2 : TLinkedListItem;
  1696. begin
  1697. NewNode:=p.First;
  1698. while assigned(NewNode) do
  1699. begin
  1700. NewNode2:=NewNode.Getcopy;
  1701. if assigned(NewNode2) then
  1702. Concat(NewNode2);
  1703. NewNode:=NewNode.Next;
  1704. end;
  1705. end;
  1706. {****************************************************************************
  1707. TStringListItem
  1708. ****************************************************************************}
  1709. constructor TStringListItem.Create(const s:string);
  1710. begin
  1711. inherited Create;
  1712. FPStr:=stringdup(s);
  1713. end;
  1714. destructor TStringListItem.Destroy;
  1715. begin
  1716. stringdispose(FPStr);
  1717. end;
  1718. function TStringListItem.Str:string;
  1719. begin
  1720. Str:=FPStr^;
  1721. end;
  1722. function TStringListItem.GetCopy:TLinkedListItem;
  1723. begin
  1724. Result:=(inherited GetCopy);
  1725. TStringListItem(Result).FPStr:=stringdup(FPstr^);
  1726. end;
  1727. {****************************************************************************
  1728. TSTRINGList
  1729. ****************************************************************************}
  1730. constructor tstringList.Create;
  1731. begin
  1732. inherited Create;
  1733. FDoubles:=true;
  1734. end;
  1735. constructor tstringList.Create_no_double;
  1736. begin
  1737. inherited Create;
  1738. FDoubles:=false;
  1739. end;
  1740. procedure tstringList.insert(const s : string);
  1741. begin
  1742. if (s='') or
  1743. ((not FDoubles) and (find(s)<>nil)) then
  1744. exit;
  1745. inherited insert(tstringListItem.create(s));
  1746. end;
  1747. procedure tstringList.concat(const s : string);
  1748. begin
  1749. if (s='') or
  1750. ((not FDoubles) and (find(s)<>nil)) then
  1751. exit;
  1752. inherited concat(tstringListItem.create(s));
  1753. end;
  1754. procedure tstringList.remove(const s : string);
  1755. var
  1756. p : tstringListItem;
  1757. begin
  1758. if s='' then
  1759. exit;
  1760. p:=find(s);
  1761. if assigned(p) then
  1762. begin
  1763. inherited Remove(p);
  1764. p.Free;
  1765. end;
  1766. end;
  1767. function tstringList.GetFirst : string;
  1768. var
  1769. p : tstringListItem;
  1770. begin
  1771. p:=tstringListItem(inherited GetFirst);
  1772. if p=nil then
  1773. GetFirst:=''
  1774. else
  1775. begin
  1776. GetFirst:=p.FPStr^;
  1777. p.free;
  1778. end;
  1779. end;
  1780. function tstringList.Getlast : string;
  1781. var
  1782. p : tstringListItem;
  1783. begin
  1784. p:=tstringListItem(inherited Getlast);
  1785. if p=nil then
  1786. Getlast:=''
  1787. else
  1788. begin
  1789. Getlast:=p.FPStr^;
  1790. p.free;
  1791. end;
  1792. end;
  1793. function tstringList.FindCase(const s:string):TstringListItem;
  1794. var
  1795. NewNode : tstringListItem;
  1796. begin
  1797. result:=nil;
  1798. if s='' then
  1799. exit;
  1800. NewNode:=tstringListItem(FFirst);
  1801. while assigned(NewNode) do
  1802. begin
  1803. if NewNode.FPStr^=s then
  1804. begin
  1805. result:=NewNode;
  1806. exit;
  1807. end;
  1808. NewNode:=tstringListItem(NewNode.Next);
  1809. end;
  1810. end;
  1811. function tstringList.Find(const s:string):TstringListItem;
  1812. var
  1813. NewNode : tstringListItem;
  1814. ups : string;
  1815. begin
  1816. result:=nil;
  1817. if s='' then
  1818. exit;
  1819. ups:=upper(s);
  1820. NewNode:=tstringListItem(FFirst);
  1821. while assigned(NewNode) do
  1822. begin
  1823. if upper(NewNode.FPStr^)=ups then
  1824. begin
  1825. result:=NewNode;
  1826. exit;
  1827. end;
  1828. NewNode:=tstringListItem(NewNode.Next);
  1829. end;
  1830. end;
  1831. procedure TStringList.InsertItem(item:TStringListItem);
  1832. begin
  1833. inherited Insert(item);
  1834. end;
  1835. procedure TStringList.ConcatItem(item:TStringListItem);
  1836. begin
  1837. inherited Concat(item);
  1838. end;
  1839. procedure TStringList.readstream(f:TCStream);
  1840. const
  1841. BufSize = 16384;
  1842. var
  1843. Hsp,
  1844. p,maxp,
  1845. Buf : PChar;
  1846. Prev : Char;
  1847. HsPos,
  1848. ReadLen,
  1849. BufPos,
  1850. BufEnd : Longint;
  1851. hs : string;
  1852. procedure ReadBuf;
  1853. begin
  1854. if BufPos<BufEnd then
  1855. begin
  1856. Move(Buf[BufPos],Buf[0],BufEnd-BufPos);
  1857. Dec(BufEnd,BufPos);
  1858. BufPos:=0;
  1859. end;
  1860. ReadLen:=f.Read(buf[BufEnd],BufSize-BufEnd);
  1861. inc(BufEnd,ReadLen);
  1862. end;
  1863. begin
  1864. Getmem(Buf,Bufsize);
  1865. BufPos:=0;
  1866. BufEnd:=0;
  1867. HsPos:=1;
  1868. ReadBuf;
  1869. repeat
  1870. hsp:=@hs[hsPos];
  1871. p:=@Buf[BufPos];
  1872. maxp:=@Buf[BufEnd];
  1873. while (p<maxp) and not(P^ in [#10,#13]) do
  1874. begin
  1875. hsp^:=p^;
  1876. inc(p);
  1877. if hsp-@hs[1]<255 then
  1878. inc(hsp);
  1879. end;
  1880. inc(BufPos,maxp-p);
  1881. inc(HsPos,maxp-p);
  1882. prev:=p^;
  1883. inc(BufPos);
  1884. { no system uses #10#13 as line seperator (#10 = *nix, #13 = Mac, }
  1885. { #13#10 = Dos), so if we've got #10, we can safely exit }
  1886. if (prev<>#10) then
  1887. begin
  1888. if (BufPos>=BufEnd) then
  1889. begin
  1890. ReadBuf;
  1891. if BufPos>=BufEnd then
  1892. break;
  1893. end;
  1894. { is there also a #10 after it? }
  1895. if prev=#13 then
  1896. begin
  1897. if (Buf[BufPos]=#10) then
  1898. inc(BufPos);
  1899. prev:=#10;
  1900. end;
  1901. end;
  1902. if prev=#10 then
  1903. begin
  1904. hs[0]:=char(hsp-@hs[1]);
  1905. Concat(hs);
  1906. HsPos:=1;
  1907. end;
  1908. until BufPos>=BufEnd;
  1909. hs[0]:=char(hsp-@hs[1]);
  1910. Concat(hs);
  1911. freemem(buf);
  1912. end;
  1913. procedure TStringList.writestream(f:TCStream);
  1914. var
  1915. Node : TStringListItem;
  1916. LineEnd : string[2];
  1917. begin
  1918. Case DefaultTextLineBreakStyle Of
  1919. tlbsLF: LineEnd := #10;
  1920. tlbsCRLF: LineEnd := #13#10;
  1921. tlbsCR: LineEnd := #13;
  1922. End;
  1923. Node:=tstringListItem(FFirst);
  1924. while assigned(Node) do
  1925. begin
  1926. f.Write(Node.FPStr^[1],Length(Node.FPStr^));
  1927. f.Write(LineEnd[1],length(LineEnd));
  1928. Node:=tstringListItem(Node.Next);
  1929. end;
  1930. end;
  1931. {****************************************************************************
  1932. TNamedIndexItem
  1933. ****************************************************************************}
  1934. constructor TNamedIndexItem.Create;
  1935. begin
  1936. { index }
  1937. Findexnr:=-1;
  1938. FindexNext:=nil;
  1939. { dictionary }
  1940. Fleft:=nil;
  1941. Fright:=nil;
  1942. FName:=nil;
  1943. Fspeedvalue:=cardinal($ffffffff);
  1944. end;
  1945. constructor TNamedIndexItem.Createname(const n:string);
  1946. begin
  1947. { index }
  1948. Findexnr:=-1;
  1949. FindexNext:=nil;
  1950. { dictionary }
  1951. Fleft:=nil;
  1952. Fright:=nil;
  1953. fspeedvalue:=getspeedvalue(n);
  1954. {$ifdef compress}
  1955. FName:=stringdup(minilzw_encode(n));
  1956. {$else}
  1957. FName:=stringdup(n);
  1958. {$endif}
  1959. end;
  1960. destructor TNamedIndexItem.destroy;
  1961. begin
  1962. stringdispose(FName);
  1963. end;
  1964. procedure TNamedIndexItem.setname(const n:string);
  1965. begin
  1966. if assigned(FName) then
  1967. stringdispose(FName);
  1968. fspeedvalue:=getspeedvalue(n);
  1969. {$ifdef compress}
  1970. FName:=stringdup(minilzw_encode(n));
  1971. {$else}
  1972. FName:=stringdup(n);
  1973. {$endif}
  1974. end;
  1975. function TNamedIndexItem.GetName:string;
  1976. begin
  1977. if assigned(FName) then
  1978. {$ifdef compress}
  1979. Getname:=minilzw_decode(FName^)
  1980. {$else}
  1981. Getname:=FName^
  1982. {$endif}
  1983. else
  1984. Getname:='';
  1985. end;
  1986. {****************************************************************************
  1987. TDICTIONARY
  1988. ****************************************************************************}
  1989. constructor Tdictionary.Create;
  1990. begin
  1991. FRoot:=nil;
  1992. FHashArray:=nil;
  1993. noclear:=false;
  1994. delete_doubles:=false;
  1995. end;
  1996. procedure Tdictionary.usehash;
  1997. begin
  1998. if not(assigned(FRoot)) and
  1999. not(assigned(FHashArray)) then
  2000. begin
  2001. New(FHashArray);
  2002. fillchar(FHashArray^,sizeof(FHashArray^),0);
  2003. end;
  2004. end;
  2005. function counttree(p: tnamedindexitem): longint;
  2006. begin
  2007. counttree:=0;
  2008. if not assigned(p) then
  2009. exit;
  2010. result := 1;
  2011. inc(result,counttree(p.fleft));
  2012. inc(result,counttree(p.fright));
  2013. end;
  2014. destructor Tdictionary.destroy;
  2015. begin
  2016. if not noclear then
  2017. clear;
  2018. if assigned(FHashArray) then
  2019. begin
  2020. dispose(FHashArray);
  2021. end;
  2022. end;
  2023. procedure Tdictionary.cleartree(var obj:TNamedIndexItem);
  2024. begin
  2025. if assigned(obj.Fleft) then
  2026. cleartree(obj.FLeft);
  2027. if assigned(obj.FRight) then
  2028. cleartree(obj.FRight);
  2029. obj.free;
  2030. obj:=nil;
  2031. end;
  2032. procedure Tdictionary.clear;
  2033. var
  2034. w : integer;
  2035. begin
  2036. if assigned(FRoot) then
  2037. cleartree(FRoot);
  2038. if assigned(FHashArray) then
  2039. for w:= low(FHashArray^) to high(FHashArray^) do
  2040. if assigned(FHashArray^[w]) then
  2041. cleartree(FHashArray^[w]);
  2042. end;
  2043. function Tdictionary.delete(const s:string):TNamedIndexItem;
  2044. var
  2045. p,SpeedValue : cardinal;
  2046. n : TNamedIndexItem;
  2047. {$ifdef compress}
  2048. senc:string;
  2049. {$else}
  2050. senc:string absolute s;
  2051. {$endif}
  2052. procedure insert_right_bottom(var root,Atree:TNamedIndexItem);
  2053. begin
  2054. while root.FRight<>nil do
  2055. root:=root.FRight;
  2056. root.FRight:=Atree;
  2057. end;
  2058. function delete_from_tree(root:TNamedIndexItem):TNamedIndexItem;
  2059. type
  2060. leftright=(left,right);
  2061. var
  2062. lr : leftright;
  2063. oldroot : TNamedIndexItem;
  2064. begin
  2065. oldroot:=nil;
  2066. while (root<>nil) and (root.SpeedValue<>SpeedValue) do
  2067. begin
  2068. oldroot:=root;
  2069. if SpeedValue<root.SpeedValue then
  2070. begin
  2071. root:=root.FRight;
  2072. lr:=right;
  2073. end
  2074. else
  2075. begin
  2076. root:=root.FLeft;
  2077. lr:=left;
  2078. end;
  2079. end;
  2080. while (root<>nil) and (root.FName^<>senc) do
  2081. begin
  2082. oldroot:=root;
  2083. if senc<root.FName^ then
  2084. begin
  2085. root:=root.FRight;
  2086. lr:=right;
  2087. end
  2088. else
  2089. begin
  2090. root:=root.FLeft;
  2091. lr:=left;
  2092. end;
  2093. end;
  2094. if root<>nil then
  2095. begin
  2096. dec(FCount);
  2097. if root.FLeft<>nil then
  2098. begin
  2099. { Now the Node pointing to root must point to the left
  2100. subtree of root. The right subtree of root must be
  2101. connected to the right bottom of the left subtree.}
  2102. if lr=left then
  2103. oldroot.FLeft:=root.FLeft
  2104. else
  2105. oldroot.FRight:=root.FLeft;
  2106. if root.FRight<>nil then
  2107. insert_right_bottom(root.FLeft,root.FRight);
  2108. end
  2109. else
  2110. begin
  2111. { There is no left subtree. So we can just replace the Node to
  2112. delete with the right subtree.}
  2113. if lr=left then
  2114. oldroot.FLeft:=root.FRight
  2115. else
  2116. oldroot.FRight:=root.FRight;
  2117. end;
  2118. end;
  2119. delete_from_tree:=root;
  2120. end;
  2121. begin
  2122. {$ifdef compress}
  2123. senc:=minilzw_encode(s);
  2124. {$endif}
  2125. SpeedValue:=GetSpeedValue(s);
  2126. n:=FRoot;
  2127. if assigned(FHashArray) then
  2128. begin
  2129. { First, check if the Node to delete directly located under
  2130. the hasharray.}
  2131. p:=SpeedValue mod hasharraysize;
  2132. n:=FHashArray^[p];
  2133. if (n<>nil) and (n.SpeedValue=SpeedValue) and
  2134. (n.FName^=senc) then
  2135. begin
  2136. { The Node to delete is directly located under the
  2137. hasharray. Make the hasharray point to the left
  2138. subtree of the Node and place the right subtree on
  2139. the right-bottom of the left subtree.}
  2140. if n.FLeft<>nil then
  2141. begin
  2142. FHashArray^[p]:=n.FLeft;
  2143. if n.FRight<>nil then
  2144. insert_right_bottom(n.FLeft,n.FRight);
  2145. end
  2146. else
  2147. FHashArray^[p]:=n.FRight;
  2148. delete:=n;
  2149. dec(FCount);
  2150. exit;
  2151. end;
  2152. end
  2153. else
  2154. begin
  2155. { First check if the Node to delete is the root.}
  2156. if (FRoot<>nil) and (n.SpeedValue=SpeedValue) and
  2157. (n.FName^=senc) then
  2158. begin
  2159. if n.FLeft<>nil then
  2160. begin
  2161. FRoot:=n.FLeft;
  2162. if n.FRight<>nil then
  2163. insert_right_bottom(n.FLeft,n.FRight);
  2164. end
  2165. else
  2166. FRoot:=n.FRight;
  2167. delete:=n;
  2168. dec(FCount);
  2169. exit;
  2170. end;
  2171. end;
  2172. delete:=delete_from_tree(n);
  2173. end;
  2174. function Tdictionary.empty:boolean;
  2175. var
  2176. w : integer;
  2177. begin
  2178. if assigned(FHashArray) then
  2179. begin
  2180. empty:=false;
  2181. for w:=low(FHashArray^) to high(FHashArray^) do
  2182. if assigned(FHashArray^[w]) then
  2183. exit;
  2184. empty:=true;
  2185. end
  2186. else
  2187. empty:=(FRoot=nil);
  2188. end;
  2189. procedure Tdictionary.foreach(proc2call:TNamedIndexcallback;arg:pointer);
  2190. procedure a(p:TNamedIndexItem;arg:pointer);
  2191. begin
  2192. proc2call(p,arg);
  2193. if assigned(p.FLeft) then
  2194. a(p.FLeft,arg);
  2195. if assigned(p.FRight) then
  2196. a(p.FRight,arg);
  2197. end;
  2198. var
  2199. i : integer;
  2200. begin
  2201. if assigned(FHashArray) then
  2202. begin
  2203. for i:=low(FHashArray^) to high(FHashArray^) do
  2204. if assigned(FHashArray^[i]) then
  2205. a(FHashArray^[i],arg);
  2206. end
  2207. else
  2208. if assigned(FRoot) then
  2209. a(FRoot,arg);
  2210. end;
  2211. procedure Tdictionary.foreach_static(proc2call:TNamedIndexStaticCallback;arg:pointer);
  2212. procedure a(p:TNamedIndexItem;arg:pointer);
  2213. begin
  2214. proc2call(p,arg);
  2215. if assigned(p.FLeft) then
  2216. a(p.FLeft,arg);
  2217. if assigned(p.FRight) then
  2218. a(p.FRight,arg);
  2219. end;
  2220. var
  2221. i : integer;
  2222. begin
  2223. if assigned(FHashArray) then
  2224. begin
  2225. for i:=low(FHashArray^) to high(FHashArray^) do
  2226. if assigned(FHashArray^[i]) then
  2227. a(FHashArray^[i],arg);
  2228. end
  2229. else
  2230. if assigned(FRoot) then
  2231. a(FRoot,arg);
  2232. end;
  2233. function Tdictionary.replace(oldobj,newobj:TNamedIndexItem):boolean;
  2234. var
  2235. hp : TNamedIndexItem;
  2236. begin
  2237. hp:=nil;
  2238. Replace:=false;
  2239. { must be the same name and hash }
  2240. if (oldobj.FSpeedValue<>newobj.FSpeedValue) or
  2241. (oldobj.FName^<>newobj.FName^) then
  2242. exit;
  2243. { copy tree info }
  2244. newobj.FLeft:=oldobj.FLeft;
  2245. newobj.FRight:=oldobj.FRight;
  2246. { update treeroot }
  2247. if assigned(FHashArray) then
  2248. begin
  2249. hp:=FHashArray^[newobj.FSpeedValue mod hasharraysize];
  2250. if hp=oldobj then
  2251. begin
  2252. FHashArray^[newobj.FSpeedValue mod hasharraysize]:=newobj;
  2253. hp:=nil;
  2254. end;
  2255. end
  2256. else
  2257. begin
  2258. hp:=FRoot;
  2259. if hp=oldobj then
  2260. begin
  2261. FRoot:=newobj;
  2262. hp:=nil;
  2263. end;
  2264. end;
  2265. { update parent entry }
  2266. while assigned(hp) do
  2267. begin
  2268. { is the node to replace the left or right, then
  2269. update this node and stop }
  2270. if hp.FLeft=oldobj then
  2271. begin
  2272. hp.FLeft:=newobj;
  2273. break;
  2274. end;
  2275. if hp.FRight=oldobj then
  2276. begin
  2277. hp.FRight:=newobj;
  2278. break;
  2279. end;
  2280. { First check SpeedValue, to allow a fast insert }
  2281. if hp.SpeedValue>oldobj.SpeedValue then
  2282. hp:=hp.FRight
  2283. else
  2284. if hp.SpeedValue<oldobj.SpeedValue then
  2285. hp:=hp.FLeft
  2286. else
  2287. begin
  2288. if (hp.FName^=oldobj.FName^) then
  2289. begin
  2290. { this can never happend, return error }
  2291. exit;
  2292. end
  2293. else
  2294. if oldobj.FName^>hp.FName^ then
  2295. hp:=hp.FLeft
  2296. else
  2297. hp:=hp.FRight;
  2298. end;
  2299. end;
  2300. Replace:=true;
  2301. end;
  2302. function Tdictionary.insert(obj:TNamedIndexItem):TNamedIndexItem;
  2303. begin
  2304. inc(FCount);
  2305. if assigned(FHashArray) then
  2306. insert:=insertNode(obj,FHashArray^[obj.SpeedValue mod hasharraysize])
  2307. else
  2308. insert:=insertNode(obj,FRoot);
  2309. end;
  2310. function tdictionary.insertNode(NewNode:TNamedIndexItem;var currNode:TNamedIndexItem):TNamedIndexItem;
  2311. begin
  2312. if currNode=nil then
  2313. begin
  2314. currNode:=NewNode;
  2315. insertNode:=NewNode;
  2316. end
  2317. { First check SpeedValue, to allow a fast insert }
  2318. else
  2319. if currNode.SpeedValue>NewNode.SpeedValue then
  2320. insertNode:=insertNode(NewNode,currNode.FRight)
  2321. else
  2322. if currNode.SpeedValue<NewNode.SpeedValue then
  2323. insertNode:=insertNode(NewNode,currNode.FLeft)
  2324. else
  2325. begin
  2326. if currNode.FName^>NewNode.FName^ then
  2327. insertNode:=insertNode(NewNode,currNode.FRight)
  2328. else
  2329. if currNode.FName^<NewNode.FName^ then
  2330. insertNode:=insertNode(NewNode,currNode.FLeft)
  2331. else
  2332. begin
  2333. if (delete_doubles) and
  2334. assigned(currNode) then
  2335. begin
  2336. NewNode.FLeft:=currNode.FLeft;
  2337. NewNode.FRight:=currNode.FRight;
  2338. if delete_doubles then
  2339. begin
  2340. currnode.FLeft:=nil;
  2341. currnode.FRight:=nil;
  2342. currnode.free;
  2343. end;
  2344. currNode:=NewNode;
  2345. insertNode:=NewNode;
  2346. end
  2347. else
  2348. insertNode:=currNode;
  2349. end;
  2350. end;
  2351. end;
  2352. procedure tdictionary.inserttree(currtree,currroot:TNamedIndexItem);
  2353. begin
  2354. if assigned(currtree) then
  2355. begin
  2356. inserttree(currtree.FLeft,currroot);
  2357. inserttree(currtree.FRight,currroot);
  2358. currtree.FRight:=nil;
  2359. currtree.FLeft:=nil;
  2360. insertNode(currtree,currroot);
  2361. end;
  2362. end;
  2363. function tdictionary.rename(const olds,News : string):TNamedIndexItem;
  2364. var
  2365. spdval : cardinal;
  2366. lasthp,
  2367. hp,hp2,hp3 : TNamedIndexItem;
  2368. {$ifdef compress}
  2369. oldsenc,newsenc:string;
  2370. {$else}
  2371. oldsenc:string absolute olds;
  2372. newsenc:string absolute news;
  2373. {$endif}
  2374. begin
  2375. {$ifdef compress}
  2376. oldsenc:=minilzw_encode(olds);
  2377. newsenc:=minilzw_encode(news);
  2378. {$endif}
  2379. spdval:=GetSpeedValue(olds);
  2380. if assigned(FHashArray) then
  2381. hp:=FHashArray^[spdval mod hasharraysize]
  2382. else
  2383. hp:=FRoot;
  2384. lasthp:=nil;
  2385. while assigned(hp) do
  2386. begin
  2387. if spdval>hp.SpeedValue then
  2388. begin
  2389. lasthp:=hp;
  2390. hp:=hp.FLeft
  2391. end
  2392. else
  2393. if spdval<hp.SpeedValue then
  2394. begin
  2395. lasthp:=hp;
  2396. hp:=hp.FRight
  2397. end
  2398. else
  2399. begin
  2400. if (hp.FName^=oldsenc) then
  2401. begin
  2402. { Get in hp2 the replacer for the root or hasharr }
  2403. hp2:=hp.FLeft;
  2404. hp3:=hp.FRight;
  2405. if not assigned(hp2) then
  2406. begin
  2407. hp2:=hp.FRight;
  2408. hp3:=hp.FLeft;
  2409. end;
  2410. { remove entry from the tree }
  2411. if assigned(lasthp) then
  2412. begin
  2413. if lasthp.FLeft=hp then
  2414. lasthp.FLeft:=hp2
  2415. else
  2416. lasthp.FRight:=hp2;
  2417. end
  2418. else
  2419. begin
  2420. if assigned(FHashArray) then
  2421. FHashArray^[spdval mod hasharraysize]:=hp2
  2422. else
  2423. FRoot:=hp2;
  2424. end;
  2425. { reinsert the hp3 in the tree from hp2 }
  2426. inserttree(hp3,hp2);
  2427. { reset Node with New values }
  2428. hp.FLeft:=nil;
  2429. hp.FRight:=nil;
  2430. stringdispose(hp.FName);
  2431. hp.FName:=stringdup(newsenc);
  2432. hp.FSpeedValue:=GetSpeedValue(news);
  2433. { reinsert }
  2434. if assigned(FHashArray) then
  2435. rename:=insertNode(hp,FHashArray^[hp.SpeedValue mod hasharraysize])
  2436. else
  2437. rename:=insertNode(hp,FRoot);
  2438. exit;
  2439. end
  2440. else
  2441. if oldsenc>hp.FName^ then
  2442. begin
  2443. lasthp:=hp;
  2444. hp:=hp.FLeft
  2445. end
  2446. else
  2447. begin
  2448. lasthp:=hp;
  2449. hp:=hp.FRight;
  2450. end;
  2451. end;
  2452. end;
  2453. result := nil;
  2454. end;
  2455. function Tdictionary.search(const s:string):TNamedIndexItem;
  2456. begin
  2457. search:=speedsearch(s,getspeedvalue(s));
  2458. end;
  2459. function Tdictionary.speedsearch(const s:string;SpeedValue:cardinal):TNamedIndexItem;
  2460. var
  2461. NewNode:TNamedIndexItem;
  2462. {$ifdef compress}
  2463. decn:string;
  2464. {$endif}
  2465. begin
  2466. if assigned(FHashArray) then
  2467. NewNode:=FHashArray^[SpeedValue mod hasharraysize]
  2468. else
  2469. NewNode:=FRoot;
  2470. while assigned(NewNode) do
  2471. begin
  2472. if SpeedValue>NewNode.SpeedValue then
  2473. NewNode:=NewNode.FLeft
  2474. else
  2475. if SpeedValue<NewNode.SpeedValue then
  2476. NewNode:=NewNode.FRight
  2477. else
  2478. begin
  2479. {$ifdef compress}
  2480. decn:=minilzw_decode(newnode.fname^);
  2481. if (decn=s) then
  2482. begin
  2483. speedsearch:=NewNode;
  2484. exit;
  2485. end
  2486. else
  2487. if s>decn then
  2488. NewNode:=NewNode.FLeft
  2489. else
  2490. NewNode:=NewNode.FRight;
  2491. {$else}
  2492. if (NewNode.FName^=s) then
  2493. begin
  2494. speedsearch:=NewNode;
  2495. exit;
  2496. end
  2497. else
  2498. if s>NewNode.FName^ then
  2499. NewNode:=NewNode.FLeft
  2500. else
  2501. NewNode:=NewNode.FRight;
  2502. {$endif}
  2503. end;
  2504. end;
  2505. speedsearch:=nil;
  2506. end;
  2507. {****************************************************************************
  2508. tindexarray
  2509. ****************************************************************************}
  2510. constructor tindexarray.create(Agrowsize:integer);
  2511. begin
  2512. growsize:=Agrowsize;
  2513. size:=0;
  2514. count:=0;
  2515. data:=nil;
  2516. First:=nil;
  2517. noclear:=false;
  2518. end;
  2519. destructor tindexarray.destroy;
  2520. begin
  2521. if assigned(data) then
  2522. begin
  2523. if not noclear then
  2524. clear;
  2525. freemem(data);
  2526. data:=nil;
  2527. end;
  2528. end;
  2529. function tindexarray.search(nr:integer):TNamedIndexItem;
  2530. begin
  2531. if nr<=count then
  2532. search:=data^[nr]
  2533. else
  2534. search:=nil;
  2535. end;
  2536. procedure tindexarray.clear;
  2537. var
  2538. i : integer;
  2539. begin
  2540. for i:=1 to count do
  2541. if assigned(data^[i]) then
  2542. begin
  2543. data^[i].free;
  2544. data^[i]:=nil;
  2545. end;
  2546. count:=0;
  2547. First:=nil;
  2548. end;
  2549. procedure tindexarray.foreach(proc2call : Tnamedindexcallback;arg:pointer);
  2550. var
  2551. i : integer;
  2552. begin
  2553. for i:=1 to count do
  2554. if assigned(data^[i]) then
  2555. proc2call(data^[i],arg);
  2556. end;
  2557. procedure tindexarray.foreach_static(proc2call : Tnamedindexstaticcallback;arg:pointer);
  2558. var
  2559. i : integer;
  2560. begin
  2561. for i:=1 to count do
  2562. if assigned(data^[i]) then
  2563. proc2call(data^[i],arg);
  2564. end;
  2565. procedure tindexarray.grow(gsize:integer);
  2566. var
  2567. osize : integer;
  2568. begin
  2569. osize:=size;
  2570. inc(size,gsize);
  2571. reallocmem(data,size*sizeof(pointer));
  2572. fillchar(data^[osize+1],gsize*sizeof(pointer),0);
  2573. end;
  2574. procedure tindexarray.deleteindex(p:TNamedIndexItem);
  2575. var
  2576. i : integer;
  2577. begin
  2578. i:=p.Findexnr;
  2579. { update counter }
  2580. if i=count then
  2581. dec(count);
  2582. { update Linked List }
  2583. while (i>0) do
  2584. begin
  2585. dec(i);
  2586. if (i>0) and assigned(data^[i]) then
  2587. begin
  2588. data^[i].FindexNext:=data^[p.Findexnr].FindexNext;
  2589. break;
  2590. end;
  2591. end;
  2592. if i=0 then
  2593. First:=p.FindexNext;
  2594. data^[p.FIndexnr]:=nil;
  2595. { clear entry }
  2596. p.FIndexnr:=-1;
  2597. p.FIndexNext:=nil;
  2598. end;
  2599. procedure tindexarray.delete(var p:TNamedIndexItem);
  2600. begin
  2601. deleteindex(p);
  2602. p.free;
  2603. p:=nil;
  2604. end;
  2605. procedure tindexarray.insert(p:TNamedIndexItem);
  2606. var
  2607. i : integer;
  2608. begin
  2609. if p.FIndexnr=-1 then
  2610. begin
  2611. inc(count);
  2612. p.FIndexnr:=count;
  2613. end;
  2614. if p.FIndexnr>count then
  2615. count:=p.FIndexnr;
  2616. if count>size then
  2617. grow(((count div growsize)+1)*growsize);
  2618. Assert(not assigned(data^[p.FIndexnr]) or (p=data^[p.FIndexnr]));
  2619. data^[p.FIndexnr]:=p;
  2620. { update Linked List backward }
  2621. i:=p.FIndexnr;
  2622. while (i>0) do
  2623. begin
  2624. dec(i);
  2625. if (i>0) and assigned(data^[i]) then
  2626. begin
  2627. data^[i].FIndexNext:=p;
  2628. break;
  2629. end;
  2630. end;
  2631. if i=0 then
  2632. First:=p;
  2633. { update Linked List forward }
  2634. i:=p.FIndexnr;
  2635. while (i<=count) do
  2636. begin
  2637. inc(i);
  2638. if (i<=count) and assigned(data^[i]) then
  2639. begin
  2640. p.FIndexNext:=data^[i];
  2641. exit;
  2642. end;
  2643. end;
  2644. if i>count then
  2645. p.FIndexNext:=nil;
  2646. end;
  2647. procedure tindexarray.replace(oldp,newp:TNamedIndexItem);
  2648. var
  2649. i : integer;
  2650. begin
  2651. newp.FIndexnr:=oldp.FIndexnr;
  2652. newp.FIndexNext:=oldp.FIndexNext;
  2653. data^[newp.FIndexnr]:=newp;
  2654. if First=oldp then
  2655. First:=newp;
  2656. { update Linked List backward }
  2657. i:=newp.FIndexnr;
  2658. while (i>0) do
  2659. begin
  2660. dec(i);
  2661. if (i>0) and assigned(data^[i]) then
  2662. begin
  2663. data^[i].FIndexNext:=newp;
  2664. break;
  2665. end;
  2666. end;
  2667. end;
  2668. {****************************************************************************
  2669. tdynamicarray
  2670. ****************************************************************************}
  2671. constructor tdynamicarray.create(Ablocksize:integer);
  2672. begin
  2673. FPosn:=0;
  2674. FPosnblock:=nil;
  2675. FFirstblock:=nil;
  2676. FLastblock:=nil;
  2677. Fblocksize:=Ablocksize;
  2678. grow;
  2679. end;
  2680. destructor tdynamicarray.destroy;
  2681. var
  2682. hp : pdynamicblock;
  2683. begin
  2684. while assigned(FFirstblock) do
  2685. begin
  2686. hp:=FFirstblock;
  2687. FFirstblock:=FFirstblock^.Next;
  2688. Freemem(hp);
  2689. end;
  2690. end;
  2691. function tdynamicarray.size:integer;
  2692. begin
  2693. if assigned(FLastblock) then
  2694. size:=FLastblock^.pos+FLastblock^.used
  2695. else
  2696. size:=0;
  2697. end;
  2698. procedure tdynamicarray.reset;
  2699. var
  2700. hp : pdynamicblock;
  2701. begin
  2702. while assigned(FFirstblock) do
  2703. begin
  2704. hp:=FFirstblock;
  2705. FFirstblock:=FFirstblock^.Next;
  2706. Freemem(hp);
  2707. end;
  2708. FPosn:=0;
  2709. FPosnblock:=nil;
  2710. FFirstblock:=nil;
  2711. FLastblock:=nil;
  2712. grow;
  2713. end;
  2714. procedure tdynamicarray.grow;
  2715. var
  2716. nblock : pdynamicblock;
  2717. begin
  2718. Getmem(nblock,blocksize+dynamicblockbasesize);
  2719. if not assigned(FFirstblock) then
  2720. begin
  2721. FFirstblock:=nblock;
  2722. FPosnblock:=nblock;
  2723. nblock^.pos:=0;
  2724. end
  2725. else
  2726. begin
  2727. FLastblock^.Next:=nblock;
  2728. nblock^.pos:=FLastblock^.pos+FLastblock^.used;
  2729. end;
  2730. nblock^.used:=0;
  2731. nblock^.Next:=nil;
  2732. fillchar(nblock^.data,blocksize,0);
  2733. FLastblock:=nblock;
  2734. end;
  2735. procedure tdynamicarray.align(i:integer);
  2736. var
  2737. j : integer;
  2738. begin
  2739. j:=(FPosn mod i);
  2740. if j<>0 then
  2741. begin
  2742. j:=i-j;
  2743. if FPosnblock^.used+j>blocksize then
  2744. begin
  2745. dec(j,blocksize-FPosnblock^.used);
  2746. FPosnblock^.used:=blocksize;
  2747. grow;
  2748. FPosnblock:=FLastblock;
  2749. end;
  2750. inc(FPosnblock^.used,j);
  2751. inc(FPosn,j);
  2752. end;
  2753. end;
  2754. procedure tdynamicarray.seek(i:integer);
  2755. begin
  2756. if (i<FPosnblock^.pos) or (i>=FPosnblock^.pos+blocksize) then
  2757. begin
  2758. { set FPosnblock correct if the size is bigger then
  2759. the current block }
  2760. if FPosnblock^.pos>i then
  2761. FPosnblock:=FFirstblock;
  2762. while assigned(FPosnblock) do
  2763. begin
  2764. if FPosnblock^.pos+blocksize>i then
  2765. break;
  2766. FPosnblock:=FPosnblock^.Next;
  2767. end;
  2768. { not found ? then increase blocks }
  2769. if not assigned(FPosnblock) then
  2770. begin
  2771. repeat
  2772. { the current FLastblock is now also fully used }
  2773. FLastblock^.used:=blocksize;
  2774. grow;
  2775. FPosnblock:=FLastblock;
  2776. until FPosnblock^.pos+blocksize>=i;
  2777. end;
  2778. end;
  2779. FPosn:=i;
  2780. if FPosn mod blocksize>FPosnblock^.used then
  2781. FPosnblock^.used:=FPosn mod blocksize;
  2782. end;
  2783. procedure tdynamicarray.write(const d;len:integer);
  2784. var
  2785. p : pchar;
  2786. i,j : integer;
  2787. begin
  2788. p:=pchar(@d);
  2789. while (len>0) do
  2790. begin
  2791. i:=FPosn mod blocksize;
  2792. if i+len>=blocksize then
  2793. begin
  2794. j:=blocksize-i;
  2795. move(p^,FPosnblock^.data[i],j);
  2796. inc(p,j);
  2797. inc(FPosn,j);
  2798. dec(len,j);
  2799. FPosnblock^.used:=blocksize;
  2800. if assigned(FPosnblock^.Next) then
  2801. FPosnblock:=FPosnblock^.Next
  2802. else
  2803. begin
  2804. grow;
  2805. FPosnblock:=FLastblock;
  2806. end;
  2807. end
  2808. else
  2809. begin
  2810. move(p^,FPosnblock^.data[i],len);
  2811. inc(p,len);
  2812. inc(FPosn,len);
  2813. i:=FPosn mod blocksize;
  2814. if i>FPosnblock^.used then
  2815. FPosnblock^.used:=i;
  2816. len:=0;
  2817. end;
  2818. end;
  2819. end;
  2820. procedure tdynamicarray.writestr(const s:string);
  2821. begin
  2822. write(s[1],length(s));
  2823. end;
  2824. function tdynamicarray.read(var d;len:integer):integer;
  2825. var
  2826. p : pchar;
  2827. i,j,res : integer;
  2828. begin
  2829. res:=0;
  2830. p:=pchar(@d);
  2831. while (len>0) do
  2832. begin
  2833. i:=FPosn mod blocksize;
  2834. if i+len>=FPosnblock^.used then
  2835. begin
  2836. j:=FPosnblock^.used-i;
  2837. move(FPosnblock^.data[i],p^,j);
  2838. inc(p,j);
  2839. inc(FPosn,j);
  2840. inc(res,j);
  2841. dec(len,j);
  2842. if assigned(FPosnblock^.Next) then
  2843. FPosnblock:=FPosnblock^.Next
  2844. else
  2845. break;
  2846. end
  2847. else
  2848. begin
  2849. move(FPosnblock^.data[i],p^,len);
  2850. inc(p,len);
  2851. inc(FPosn,len);
  2852. inc(res,len);
  2853. len:=0;
  2854. end;
  2855. end;
  2856. read:=res;
  2857. end;
  2858. procedure tdynamicarray.readstream(f:TCStream;maxlen:longint);
  2859. var
  2860. i,left : integer;
  2861. begin
  2862. if maxlen=-1 then
  2863. maxlen:=maxlongint;
  2864. repeat
  2865. left:=blocksize-FPosnblock^.used;
  2866. if left>maxlen then
  2867. left:=maxlen;
  2868. i:=f.Read(FPosnblock^.data[FPosnblock^.used],left);
  2869. dec(maxlen,i);
  2870. inc(FPosnblock^.used,i);
  2871. if FPosnblock^.used=blocksize then
  2872. begin
  2873. if assigned(FPosnblock^.Next) then
  2874. FPosnblock:=FPosnblock^.Next
  2875. else
  2876. begin
  2877. grow;
  2878. FPosnblock:=FLastblock;
  2879. end;
  2880. end;
  2881. until (i<left) or (maxlen=0);
  2882. end;
  2883. procedure tdynamicarray.writestream(f:TCStream);
  2884. var
  2885. hp : pdynamicblock;
  2886. begin
  2887. hp:=FFirstblock;
  2888. while assigned(hp) do
  2889. begin
  2890. f.Write(hp^.data,hp^.used);
  2891. hp:=hp^.Next;
  2892. end;
  2893. end;
  2894. end.