cclasses.pas 84 KB

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