cclasses.pas 88 KB

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